ChangeStack.svelte

 1<script lang="ts">
 2	import { changes, mainChange, currentChange, selectChange } from '$lib/stores/changes';
 3	import { vcs } from '$lib/stores/files';
 4
 5	let busy = $state<string | null>(null);
 6
 7	async function select(changeId: string) {
 8		if (busy || changeId === $currentChange) return;
 9		busy = changeId;
10		try {
11			await selectChange(changeId);
12		} catch (err) {
13			console.error(err);
14		} finally {
15			busy = null;
16		}
17	}
18</script>
19
20{#if $vcs === 'jj'}
21	<div class="border-t border-border max-h-72 overflow-y-auto shrink-0">
22		<div class="px-3 py-2 text-xs font-semibold text-tertiary uppercase tracking-wider flex items-center justify-between">
23			<span>Changes ({$changes.length})</span>
24			{#if $mainChange}
25				<span class="text-[10px] text-muted normal-case tracking-normal font-mono" title="Bookmark main is at {$mainChange.changeId}">
26					main: {$mainChange.changeId}
27				</span>
28			{/if}
29		</div>
30
31		{#if $changes.length === 0}
32			<div class="px-3 pb-3 text-xs text-muted">No changes since main</div>
33		{:else}
34			<div class="space-y-px px-1 pb-2">
35				{#each $changes as change (change.changeId)}
36					{@const active = change.changeId === $currentChange}
37					{@const pending = busy === change.changeId}
38					<button
39						class="w-full text-left px-2 py-1.5 rounded flex items-start gap-2 text-xs transition-colors {active ? 'bg-hover/80 text-primary' : 'text-secondary hover:bg-hover/50'} {pending ? 'opacity-60' : ''}"
40						onclick={() => select(change.changeId)}
41						title={change.description || '(no description)'}
42					>
43						<span class="font-mono text-[10px] text-muted shrink-0 mt-0.5">{change.changeId}</span>
44						<span class="flex-1 truncate {active ? 'font-medium' : ''}">
45							{change.description || '(no description)'}
46						</span>
47						{#each change.bookmarks as bm}
48							<span class="shrink-0 text-[10px] px-1 rounded bg-accent-green/20 text-accent-green">{bm}</span>
49						{/each}
50						{#if change.isWorkingCopy}
51							<span class="shrink-0 text-[10px] px-1 rounded bg-accent-blue/20 text-accent-blue" title="Working copy @">@</span>
52						{/if}
53					</button>
54				{/each}
55			</div>
56		{/if}
57	</div>
58{/if}