diff --git a/src/lib/components/AiCommitSplitDialog.svelte b/src/lib/components/AiCommitSplitDialog.svelte index 0872a04..aba8953 100644 --- a/src/lib/components/AiCommitSplitDialog.svelte +++ b/src/lib/components/AiCommitSplitDialog.svelte @@ -15,6 +15,13 @@ if (draft.groups.length === 0) draft = structuredClone(plan); }); let valid = $derived(draft.groups.length > 1 && draft.groups.every((group) => group.message.trim() && group.files.length)); + let validationIssue = $derived( + draft.groups.findIndex((group) => group.files.length === 0) >= 0 + ? "Every commit needs at least one file." + : draft.groups.findIndex((group) => !group.message.trim()) >= 0 + ? "Every commit needs a message." + : "", + ); function setMessage(index: number, message: string) { draft.groups[index].message = message; @@ -25,6 +32,13 @@ draft.groups[from].files = draft.groups[from].files.filter((path) => path !== file); draft.groups[to].files = [...draft.groups[to].files, file]; } + + function applyDraft() { + // `draft` is a deeply reactive Svelte proxy. `structuredClone(draft)` + // throws a DataCloneError before the callback runs, which made the button + // appear to do nothing. A state snapshot is a plain, cloneable object. + onApply($state.snapshot(draft)); + } { if (event.key === "Escape" && !isApplying) onClose(); }} /> @@ -40,7 +54,10 @@ {#each draft.groups as group, groupIndex}
Commit {groupIndex + 1}{group.files.length} files
- + {#if group.reason}

{group.reason}

{/if}
{#each group.files as file} @@ -55,10 +72,10 @@ {/each}
@@ -74,10 +91,13 @@ article>header{display:flex;align-items:center;gap:8px;color:var(--color-ink)} article>header span{margin-left:auto;color:var(--color-ink-faint);font-size:11px} label{display:grid;gap:5px;color:var(--color-ink-faint);font-size:10px;font-weight:800;text-transform:uppercase} + label span{display:flex;align-items:center;justify-content:space-between;gap:8px} + label em{color:var(--color-accent);font-size:9px;font-style:normal;font-weight:700;text-transform:none} input{height:34px;padding:0 10px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface);color:var(--color-ink);font-family:var(--font-mono)} article>p{margin:0;color:var(--color-ink-muted);font-size:12px;line-height:1.45} .split-files{display:grid;gap:5px} .split-files>div{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:6px;background:var(--color-surface)} code{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;color:var(--color-ink-muted);font-size:11px;white-space:nowrap} select{height:28px;border:1px solid var(--color-border-subtle);border-radius:5px;background:var(--color-surface-raised);color:var(--color-ink);font-size:11px} + .dialog-footer p.invalid{color:#e0a040}