~james/core

core/web/src/lib/components/repo/FileCardHeader.svelte -rw-r--r-- 1.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 hours ago
                                                                                
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
<script lang="ts">
	import type { Snippet } from "svelte";
	import ChevronDown from "$icon/chevron-down";
	import ChevronRight from "$icon/chevron-right";

	interface Props {
		open?: boolean;
		collapsible?: boolean;
		spacer?: boolean;
		onToggle?: () => void;
		class?: string;
		title: Snippet;
		actions?: Snippet;
	}

	let {
		open = true,
		collapsible = true,
		spacer = false,
		onToggle,
		class: className = "",
		title,
		actions
	}: Props = $props();

	const isInteractive = $derived(collapsible && onToggle != null);
	const titleClass =
		"flex min-w-0 flex-1 items-center gap-xs overflow-hidden px-2.5 py-xs text-left text-foreground-default select-none";
</script>

<div
	class={[
		"flex justify-between rounded-t-md border border-border-default bg-background-default",
		isInteractive && "hover:bg-background-subtle",
		(!open || !collapsible) && "rounded-b-md",
		className
	]}
>
	{#if isInteractive}
		<button
			type="button"
			class={[titleClass, "cursor-pointer"]}
			onclick={onToggle}
			aria-expanded={open}
		>
			{#if open}
				<ChevronDown class="size-3.5 shrink-0 text-foreground-subtle" aria-hidden="true" />
			{:else}
				<ChevronRight class="size-3.5 shrink-0 text-foreground-subtle" aria-hidden="true" />
			{/if}
			{@render title()}
		</button>
	{:else}
		<div class={titleClass}>
			{#if spacer}
				<span class="size-3.5 shrink-0" aria-hidden="true"></span>
			{/if}
			{@render title()}
		</div>
	{/if}

	{#if actions}
		<div class="flex shrink-0 items-center gap-xs pr-1.5">
			{@render actions()}
		</div>
	{/if}
</div>