<!--
A new worktree of one project, made by prj: `prj wt add`, which places every
repository of the project as a worktree of main-worktree's own.
The branch and the starting point are optional; prj's defaults are its own
(`card/<name>`, from the remote's default branch), and the form does not
guess at them.
-->
<script lang="ts">
import { actionKey, levels } from "../../stores/levels.svelte.js";
interface Props {
project: string;
}
let { project }: Props = $props();
let open = $state(false);
let name = $state("");
let branch = $state("");
let from = $state("");
const outcome = $derived(levels.outcome(actionKey.add(project)));
const valid = $derived(/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name.trim()));
async function submit(e: SubmitEvent) {
e.preventDefault();
if (!valid || outcome?.running) return;
const added = await levels.addWorktree({
project,
name: name.trim(),
...(branch.trim() ? { branch: branch.trim() } : {}),
...(from.trim() ? { from: from.trim() } : {}),
});
if (added) {
name = "";
branch = "";
from = "";
open = false;
}
}
</script>
{#if open}
<form class="new-worktree" onsubmit={submit} aria-label="New worktree of {project}">
<label class="field">
<span class="field-label">Name</span>
<input class="field-input" bind:value={name} placeholder="feature" required />
</label>
<label class="field">
<span class="field-label">Branch (optional)</span>
<input class="field-input" bind:value={branch} placeholder="card/{name.trim() || 'name'}" />
</label>
<label class="field">
<span class="field-label">From (optional)</span>
<input class="field-input" bind:value={from} placeholder="origin/HEAD" />
</label>
<div class="button-row">
<button class="primary" type="submit" disabled={!valid || outcome?.running}>
{outcome?.running ? "Creating…" : "Create worktree"}
</button>
<button class="secondary" type="button" onclick={() => (open = false)}>Cancel</button>
</div>
</form>
{:else}
<button class="secondary tiny" onclick={() => (open = true)}>New worktree</button>
{/if}
{#if outcome && !outcome.running}
<div class="new-worktree-outcome" class:failed={outcome.error !== null}>
{#if outcome.error !== null}
<span role="alert">{outcome.error}</span>
{:else if outcome.output}
<pre>{outcome.output}</pre>
{/if}
<button class="quiet" onclick={() => levels.dismiss(actionKey.add(project))}>Dismiss</button>
</div>
{/if}
<style>
.new-worktree {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: var(--wb-spacing-8);
align-items: end;
padding: var(--wb-spacing-8) var(--wb-spacing-10);
border-top: 1px solid var(--vscode-panel-border);
}
.new-worktree-outcome {
display: flex;
align-items: flex-start;
gap: var(--wb-spacing-8);
padding: var(--wb-spacing-4) var(--wb-spacing-10);
font-size: var(--wb-font-size-11);
color: var(--vscode-descriptionForeground);
}
.new-worktree-outcome.failed {
color: var(--wb-error);
}
.new-worktree-outcome pre {
margin: 0;
flex: 1;
white-space: pre-wrap;
font-family: var(--vscode-editor-font-family, monospace);
}
.new-worktree-outcome span {
flex: 1;
}
</style>