File size: 2,597 Bytes
41a5ab2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<script lang="ts">

	import * as DropdownMenu from '$lib/components/ui/dropdown-menu';

	import * as Tooltip from '$lib/components/ui/tooltip';

	import { KeyboardShortcutInfo } from '$lib/components/app';

	import type { Component } from 'svelte';



	interface ActionItem {

		icon: Component;

		label: string;

		onclick: (event: Event) => void;

		variant?: 'default' | 'destructive';

		disabled?: boolean;

		shortcut?: string[];

		separator?: boolean;

	}



	interface Props {

		triggerIcon: Component;

		triggerTooltip?: string;

		triggerClass?: string;

		actions: ActionItem[];

		align?: 'start' | 'center' | 'end';

		open?: boolean;

	}



	let {

		triggerIcon,

		triggerTooltip,

		triggerClass = '',

		actions,

		align = 'end',

		open = $bindable(false)

	}: Props = $props();

</script>

<DropdownMenu.Root bind:open>
	<DropdownMenu.Trigger

		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}"

		onclick={(e) => e.stopPropagation()}
	>
		{#if triggerTooltip}
			<Tooltip.Root>
				<Tooltip.Trigger>
					{@render iconComponent(triggerIcon, 'h-3 w-3')}
					<span class="sr-only">{triggerTooltip}</span>
				</Tooltip.Trigger>
				<Tooltip.Content>
					<p>{triggerTooltip}</p>
				</Tooltip.Content>
			</Tooltip.Root>
		{:else}
			{@render iconComponent(triggerIcon, 'h-3 w-3')}
		{/if}
	</DropdownMenu.Trigger>

	<DropdownMenu.Content {align} class="z-[999999] w-48">
		{#each actions as action, index (action.label)}
			{#if action.separator && index > 0}
				<DropdownMenu.Separator />
			{/if}

			<DropdownMenu.Item

				onclick={action.onclick}

				variant={action.variant}

				disabled={action.disabled}

				class="flex items-center justify-between hover:[&>kbd]:opacity-100"

			>
				<div class="flex items-center gap-2">
					{@render iconComponent(
						action.icon,
						`h-4 w-4 ${action.variant === 'destructive' ? 'text-destructive' : ''}`
					)}
					{action.label}
				</div>

				{#if action.shortcut}
					<KeyboardShortcutInfo keys={action.shortcut} variant={action.variant} />
				{/if}
			</DropdownMenu.Item>
		{/each}
	</DropdownMenu.Content>
</DropdownMenu.Root>

{#snippet iconComponent(IconComponent: Component, className: string)}
	<IconComponent class={className} />
{/snippet}