File size: 3,868 Bytes
654f56a
9b4caaa
3df1e9f
af10150
7450ebd
64cfbce
 
aac02fe
b2170a7
 
b1426d3
f77d645
7450ebd
 
6a8491a
af10150
 
 
 
 
6a8491a
9b4caaa
654f56a
af10150
9b4caaa
af10150
9b4caaa
af10150
 
654f56a
aac02fe
53e0cfa
9b4caaa
aac02fe
654f56a
 
aac02fe
654f56a
af10150
654f56a
aac02fe
 
654f56a
 
 
9b4caaa
654f56a
64cfbce
 
 
 
 
654f56a
f77d645
cf47645
7450ebd
cf47645
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aac02fe
654f56a
af10150
9b4caaa
af10150
7450ebd
af10150
6a8491a
aac02fe
6a8491a
7450ebd
 
 
 
 
 
 
 
 
 
 
aac02fe
 
 
 
af10150
aac02fe
11e0dcc
aac02fe
 
 
 
 
 
af10150
aac02fe
 
 
 
 
 
 
 
6a8491a
af10150
aac02fe
654f56a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<script lang="ts">
	import { session } from "$lib/state/session.svelte.js";
	import { cn } from "$lib/utils/cn.js";
	import { Select } from "melt/builders";
	import IconHistory from "~icons/carbon/recently-viewed";
	import IconCaret from "~icons/carbon/chevron-down";
	import IconCross from "~icons/carbon/close";
	import IconEdit from "~icons/carbon/edit";
	import IconSave from "~icons/carbon/save";
	import IconDelete from "~icons/carbon/trash-can";
	import { prompt } from "../prompts.svelte";
	import Tooltip from "../tooltip.svelte";
	import CheckpointsMenu from "./checkpoints-menu.svelte";
	import { checkpoints } from "$lib/state/checkpoints.svelte";

	interface Props {
		class?: string;
	}

	let { class: classNames = "" }: Props = $props();

	const isDefault = $derived(session.$.activeProjectId === "default");

	const select = new Select({
		value: () => session.$.activeProjectId,
		onValueChange(v) {
			if (v) session.$.activeProjectId = v;
		},
		sameWidth: true,
	});

	async function saveProject() {
		session.saveProject((await prompt("Set project name")) || "Project #" + (session.$.projects.length + 1));
	}
</script>

<div class={cn("flex w-full items-stretch gap-2 ", classNames)}>
	<button
		{...select.trigger}
		class={cn(
			"relative flex grow items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm",
			"hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110"
		)}
	>
		<div class="flex items-center gap-1 text-sm">
			{session.project.name}
		</div>
		<div
			class="absolute right-2 grid size-4 flex-none place-items-center rounded-sm bg-gray-100 text-xs dark:bg-gray-600"
		>
			<IconCaret />
		</div>
	</button>

	<div class="flex items-center gap-2">
		<CheckpointsMenu />
		{#if isDefault}
			<Tooltip>
				{#snippet trigger(tooltip)}
					<button class="btn size-[32px] p-0" {...tooltip.trigger} onclick={saveProject}>
						<IconSave />
					</button>
				{/snippet}
				Save to Project
			</Tooltip>
		{:else}
			<Tooltip>
				{#snippet trigger(tooltip)}
					<button
						class="btn size-[32px] p-0"
						{...tooltip.trigger}
						onclick={() => (session.$.activeProjectId = "default")}
					>
						<IconCross />
					</button>
				{/snippet}
				Close project
			</Tooltip>
		{/if}
	</div>
</div>

<div {...select.content} class="rounded-lg border bg-gray-100 dark:border-gray-700 dark:bg-gray-800">
	{#each session.$.projects as { name, id } (id)}
		{@const option = select.getOption(id)}
		{@const hasCheckpoints = checkpoints.for(id).length > 0}
		<div {...option} class="group block w-full p-1 text-sm dark:text-white">
			<div
				class="flex items-center gap-2 rounded-md py-1.5 pr-1 pl-2 group-data-[highlighted]:bg-gray-200 dark:group-data-[highlighted]:bg-gray-700"
			>
				<div class="flex items-center gap-2">
					{name}
					{#if hasCheckpoints}
						<div
							class="text-3xs grid aspect-square place-items-center rounded bg-yellow-400/25 p-0.5 text-yellow-400"
							aria-label="Project has checkpoints"
						>
							<IconHistory />
						</div>
					{/if}
				</div>
				{#if id !== "default"}
					<div class="ml-auto flex items-center gap-1">
						<button
							class="grid place-items-center rounded-md p-1 text-xs hover:bg-gray-300 dark:hover:bg-gray-600"
							onclick={async e => {
								e.stopPropagation();
								session.updateProject(id, { name: (await prompt("Edit project name", name)) || name });
							}}
						>
							<IconEdit />
						</button>
						<button
							class="grid place-items-center rounded-md p-1 text-xs hover:bg-gray-300 dark:hover:bg-gray-600"
							onclick={e => {
								e.stopPropagation();
								session.deleteProject(id);
							}}
						>
							<IconDelete />
						</button>
					</div>
				{/if}
			</div>
		</div>
	{/each}
</div>