<script lang="ts">
import { onMount } from "svelte";
import { git } from "../../../stores/git.svelte.js";
import AppIcon from "../../layout/AppIcon.svelte";
let {
repoPath,
fleet = false,
onclose,
}: {
repoPath?: string;
fleet?: boolean;
onclose: () => void;
} = $props();
let branches = $state<string[]>([]);
let current = $state<string | null>(null);
let selected = $state("");
let newBranchName = $state("");
let createNew = $state(false);
let loading = $state(true);
let error: string | null = $state(null);
onMount(async () => {
try {
const result = await git.getBranches(repoPath);
branches = result.branches;
current = result.current;
if (result.current) {
selected = result.current;
} else if (branches.length > 0) {
selected = branches[0]!;
}
} catch (e) {
error = e instanceof Error ? e.message : String(e);
} finally {
loading = false;
}
});
function handleSubmit() {
let accepted: boolean;
if (createNew) {
const name = newBranchName.trim();
if (!name) return;
accepted = fleet ? git.checkoutAll(name, true) : git.checkout(name, repoPath, true);
} else {
if (!selected) return;
accepted = fleet ? git.checkoutAll(selected) : git.checkout(selected, repoPath);
}
if (accepted) onclose();
}
function handleKeydown(e: KeyboardEvent) {
if (e.key === "Escape") onclose();
if (e.key === "Enter" && !e.shiftKey) handleSubmit();
}
</script>
<div class="modal-overlay" onclick={onclose} onkeydown={handleKeydown} role="presentation">
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div
class="modal-panel"
onclick={(e) => e.stopPropagation()}
onkeydown={handleKeydown}
role="dialog"
aria-label="Checkout Branch"
tabindex="0"
>
<div class="modal-header">
<h2 class="modal-title">{fleet ? "Fleet Checkout" : "Checkout Branch"}</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}
{#if loading}
<div class="loading">Loading branches...</div>
{:else}
<div class="toggle-row">
<button
class="toggle-btn"
class:active={!createNew}
onclick={() => (createNew = false)}
>Existing Branch</button>
<button
class="toggle-btn"
class:active={createNew}
onclick={() => (createNew = true)}
>Create New</button>
</div>
{#if createNew}
<label class="field">
<span class="field-label">New branch name</span>
<input
class="field-input"
type="text"
placeholder="feature/my-branch"
bind:value={newBranchName}
/>
</label>
{:else}
<label class="field">
<span class="field-label">Branch{current ? ` (current: ${current})` : ""}</span>
<select class="field-select" bind:value={selected}>
{#each branches as branch}
<option value={branch}>{branch}{branch === current ? " ✓" : ""}</option>
{/each}
</select>
</label>
{/if}
<div class="modal-actions">
<button class="btn-cancel" onclick={onclose}>Cancel</button>
<button
class="btn-submit"
disabled={createNew ? !newBranchName.trim() : !selected || selected === current}
onclick={handleSubmit}
>
{createNew ? "Create & Checkout" : "Checkout"}
</button>
</div>
{/if}
</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 {
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 {
outline: none;
border-color: var(--vscode-focusBorder);
}
.loading {
padding: var(--wb-spacing-12) 0;
font-size: var(--wb-font-size-12);
color: var(--vscode-disabledForeground);
}
.toggle-row {
display: flex;
gap: var(--wb-spacing-4);
margin-bottom: var(--wb-spacing-12);
}
.toggle-btn {
flex: 1;
padding: var(--wb-spacing-6) var(--wb-spacing-12);
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;
}
.toggle-btn.active {
background: var(--vscode-focusBorder);
color: white;
border-color: var(--vscode-focusBorder);
}
.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>