asChild is a bits-ui v1 prop the icon picker no longer needs -- it already passes a child snippet. The drop zone set both webkitdirectory and a bare directory attribute, which no browser implements. The library view seeds its collection state once by design, so it says so with untrack.
75 lines
2.1 KiB
Svelte
75 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import * as Popover from '$lib/components/ui/popover/index.js';
|
|
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
|
|
import { Button } from '$lib/components/ui/button/index.js';
|
|
import { Input } from '$lib/components/ui/input/index.js';
|
|
import { ScrollArea } from '$lib/components/ui/scroll-area/index.js';
|
|
import { LIBRARY_ICONS } from './library-icons.js';
|
|
|
|
let {
|
|
value = $bindable('library')
|
|
}: {
|
|
value?: string;
|
|
} = $props();
|
|
|
|
let open = $state(false);
|
|
let search = $state('');
|
|
|
|
const filteredIcons = $derived.by(() => {
|
|
if (!search) return Object.entries(LIBRARY_ICONS);
|
|
const query = search.toLowerCase();
|
|
return Object.entries(LIBRARY_ICONS).filter(
|
|
([key, icon]) =>
|
|
key.includes(query) ||
|
|
icon.label.toLowerCase().includes(query) ||
|
|
icon.category.toLowerCase().includes(query)
|
|
);
|
|
});
|
|
|
|
function selectIcon(iconKey: string) {
|
|
value = iconKey;
|
|
open = false;
|
|
search = '';
|
|
}
|
|
|
|
const selectedIcon = $derived(LIBRARY_ICONS[value] ?? LIBRARY_ICONS['library']);
|
|
const SelectedIconComponent = $derived(selectedIcon.component);
|
|
</script>
|
|
|
|
<Popover.Root bind:open>
|
|
<Popover.Trigger>
|
|
{#snippet child({ props })}
|
|
<Button variant="outline" size="icon" class="h-9 w-9" {...props}>
|
|
<SelectedIconComponent class="size-4" />
|
|
</Button>
|
|
{/snippet}
|
|
</Popover.Trigger>
|
|
<Popover.Content class="w-64 p-3" align="start">
|
|
<Input bind:value={search} placeholder="Search icons..." class="mb-3 h-8" />
|
|
<ScrollArea class="h-48">
|
|
<div class="grid grid-cols-6 gap-1">
|
|
{#each filteredIcons as [key, icon] (key)}
|
|
{@const IconComponent = icon.component}
|
|
<Tooltip.Root>
|
|
<Tooltip.Trigger>
|
|
<button
|
|
type="button"
|
|
class="flex size-8 items-center justify-center rounded-md hover:bg-accent {value ===
|
|
key
|
|
? 'bg-accent'
|
|
: ''}"
|
|
onclick={() => selectIcon(key)}
|
|
>
|
|
<IconComponent class="size-4" />
|
|
</button>
|
|
</Tooltip.Trigger>
|
|
<Tooltip.Content>
|
|
<p>{icon.label}</p>
|
|
</Tooltip.Content>
|
|
</Tooltip.Root>
|
|
{/each}
|
|
</div>
|
|
</ScrollArea>
|
|
</Popover.Content>
|
|
</Popover.Root>
|