1<script lang="ts">
 2	import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
 3	import * as Tooltip from '$lib/components/ui/tooltip';
 4	import { KeyboardShortcutInfo } from '$lib/components/app';
 5	import type { Component } from 'svelte';
 6
 7	interface ActionItem {
 8		icon: Component;
 9		label: string;
10		onclick: (event: Event) => void;
11		variant?: 'default' | 'destructive';
12		disabled?: boolean;
13		shortcut?: string[];
14		separator?: boolean;
15	}
16
17	interface Props {
18		triggerIcon: Component;
19		triggerTooltip?: string;
20		triggerClass?: string;
21		actions: ActionItem[];
22		align?: 'start' | 'center' | 'end';
23		open?: boolean;
24	}
25
26	let {
27		triggerIcon,
28		triggerTooltip,
29		triggerClass = '',
30		actions,
31		align = 'end',
32		open = $bindable(false)
33	}: Props = $props();
34</script>
35
36<DropdownMenu.Root bind:open>
37	<DropdownMenu.Trigger
38		class="flex h-6 w-6 cursor-pointer items-center justify-center rounded-md p-0 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground {triggerClass}"
39		onclick={(e) => e.stopPropagation()}
40	>
41		{#if triggerTooltip}
42			<Tooltip.Root>
43				<Tooltip.Trigger>
44					{@render iconComponent(triggerIcon, 'h-3 w-3')}
45					<span class="sr-only">{triggerTooltip}</span>
46				</Tooltip.Trigger>
47				<Tooltip.Content>
48					<p>{triggerTooltip}</p>
49				</Tooltip.Content>
50			</Tooltip.Root>
51		{:else}
52			{@render iconComponent(triggerIcon, 'h-3 w-3')}
53		{/if}
54	</DropdownMenu.Trigger>
55
56	<DropdownMenu.Content {align} class="z-[999999] w-48">
57		{#each actions as action, index (action.label)}
58			{#if action.separator && index > 0}
59				<DropdownMenu.Separator />
60			{/if}
61
62			<DropdownMenu.Item
63				onclick={action.onclick}
64				variant={action.variant}
65				disabled={action.disabled}
66				class="flex items-center justify-between hover:[&>kbd]:opacity-100"
67			>
68				<div class="flex items-center gap-2">
69					{@render iconComponent(
70						action.icon,
71						`h-4 w-4 ${action.variant === 'destructive' ? 'text-destructive' : ''}`
72					)}
73					{action.label}
74				</div>
75
76				{#if action.shortcut}
77					<KeyboardShortcutInfo keys={action.shortcut} variant={action.variant} />
78				{/if}
79			</DropdownMenu.Item>
80		{/each}
81	</DropdownMenu.Content>
82</DropdownMenu.Root>
83
84{#snippet iconComponent(IconComponent: Component, className: string)}
85	<IconComponent class={className} />
86{/snippet}