<script lang="ts">
import { issues } from "../../stores/issues.svelte.js";
import AppIcon from "../layout/AppIcon.svelte";
import { remembered } from "../../utils/remember.svelte.js";
let {
repos,
onclose,
}: {
repos: string[];
onclose: () => void;
} = $props();
/// Which repository, kept — issues get filed against the same one for
/// weeks. The title and body are never kept: a remembered issue title is one
/// that gets filed again by accident, describing work it does not describe.
const selectedRepo = remembered("issues.repo", "");
let title = $state("");
let body = $state("");
let submitting = $state(false);
let error: string | null = $state(null);
$effect(() => {
if (selectedRepo.value === "" && repos.length > 0) {
selectedRepo.value = repos[0]!;
return;
}
if (selectedRepo.value !== "" && !repos.includes(selectedRepo.value)) {
selectedRepo.value = repos[0] ?? "";
}
});
async function handleSubmit() {
if (!selectedRepo.value || !title.trim()) return;
submitting = true;
error = null;
try {
const [owner, repo] = selectedRepo.value.split("/");
await issues.createIssue(owner!, repo!, {
title: title.trim(),
body: body.trim() || undefined,
});
onclose();
} catch (e) {
error = e instanceof Error ? e.message : String(e);
} finally {
submitting = false;
}
}
</script>
<div class="modal-overlay" onclick={onclose} onkeydown={(e) => { if (e.key === "Escape") onclose(); }} role="presentation">
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div
class="modal-panel"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => { if (e.key === "Escape") onclose(); }}
role="dialog"
aria-label="Create Issue"
tabindex="0"
>
<div class="modal-header">
<h2 class="modal-title">New Issue</h2>
<button class="modal-close" onclick={onclose} aria-label="Close">
<AppIcon name="x" size={14} />
</button>
</div>
<div class="modal-body">
{#if error}
<div class="modal-error">{error}</div>
{/if}
<label class="field">
<span class="field-label">Repository</span>
<select class="field-select" bind:value={selectedRepo.value}>
{#each repos as repo}
<option value={repo}>{repo}</option>
{/each}
</select>
</label>
<label class="field">
<span class="field-label">Title</span>
<input
class="field-input"
type="text"
placeholder="Issue title"
bind:value={title}
onkeydown={(e) => { if (e.key === "Enter" && !e.shiftKey) handleSubmit(); }}
/>
</label>
<label class="field">
<span class="field-label">Description (optional)</span>
<textarea
class="field-textarea"
placeholder="Describe the issue (Markdown supported)"
bind:value={body}
rows="6"
></textarea>
</label>
<div class="modal-actions">
<button class="btn-cancel" onclick={onclose}>Cancel</button>
<button
class="btn-submit"
disabled={!title.trim() || !selectedRepo.value || submitting}
onclick={handleSubmit}
>
{submitting ? "Creating..." : "Create Issue"}
</button>
</div>
</div>
</div>
</div>
<style>
.field {
display: flex;
flex-direction: column;
gap: var(--wb-spacing-4);
margin-bottom: var(--wb-spacing-12);
}
.field-label {
font-size: var(--wb-font-size-11);
font-weight: 600;
color: var(--vscode-foreground);
}
.field-input,
.field-select,
.field-textarea {
padding: var(--wb-spacing-8) var(--wb-spacing-10);
font-size: var(--wb-font-size-13);
font-family: var(--wsb-font-sans);
color: var(--vscode-editor-foreground);
background: var(--vscode-input-background);
border: 1px solid var(--vscode-widget-border);
border-radius: var(--wsb-radius-sm);
}
.field-input:focus,
.field-select:focus,
.field-textarea:focus {
outline: none;
border-color: var(--vscode-focusBorder);
}
.field-textarea {
resize: vertical;
min-height: var(--wb-control-size-80);
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: var(--wb-spacing-8);
margin-top: var(--wb-spacing-16);
}
.btn-cancel {
height: var(--wb-control-size-32);
padding: 0 var(--wb-spacing-14);
font-size: var(--wb-font-size-12);
font-weight: 500;
color: var(--vscode-foreground);
background: var(--vscode-input-background);
border: 1px solid var(--vscode-widget-border);
border-radius: var(--wsb-radius-sm);
cursor: pointer;
}
.btn-cancel:hover {
background: var(--vscode-list-hoverBackground);
}
.btn-submit {
height: var(--wb-control-size-32);
padding: 0 var(--wb-spacing-14);
font-size: var(--wb-font-size-12);
font-weight: 600;
color: white;
background: var(--vscode-testing-iconPassed);
border-radius: var(--wsb-radius-sm);
cursor: pointer;
}
.btn-submit:disabled {
opacity: 0.5;
cursor: default;
}
.btn-submit:hover:not(:disabled) {
opacity: 0.9;
}
</style>