better select

This commit is contained in:
axel 2025-04-12 00:19:40 +02:00
parent 5e02851a20
commit c27f956d64

View File

@ -1,8 +1,13 @@
<script lang="ts">
import { browser } from "$app/environment";
import { slide } from "svelte/transition";
import IconListDetails from "~icons/tabler/list-details";
import IconMinus from "~icons/tabler/minus";
import IconPlus from "~icons/tabler/plus";
import IconSearch from "~icons/tabler/search";
import IconX from "~icons/tabler/x";
import Button from "../ui/Button.svelte";
import IconPlus from "~icons/tabler/plus";
import IconMinus from "~icons/tabler/minus";
let {
label,
sublabel = "",
@ -20,10 +25,15 @@
} = $props();
let selectData = $state(data);
let expanded = $state(false);
let search = $state("");
let focused = $state(false);
$effect(() => {
console.log(selectData);
})
if (browser) {
document.addEventListener("click", () => {
if (!focused) expanded = false;
});
}
</script>
<div class="flex gap-x-10 gap-y-3 flex-wrap mb-5">
@ -39,13 +49,26 @@
{/each}
</select>
<div class="flex gap-2 flex-wrap border border-neutral-200 rounded p-4 shadow w-fit h-fit max-w-[300px] max-h-[200px] overflow-y-scroll">
<div class="relative flex gap-10 items-center h-fit rounded border border-gray-300 shadow-sm pl-4 pr-2 py-2 text-sm focus:ring-indigo-500 focus:border-indigo-500">
{#if selectData.length == 0}
<p class="text-sm text-neutral-400">No data</p>
<p>None available</p>
{:else}
{#each selectData as el}
<Button Icon={el.selected ? IconMinus : IconPlus} type="button" extra="!px-2 !py-1 !text-xs !rounded-sm" onclick={() => {el.selected = !el.selected}} inverted={!el.selected}>{el.name}</Button>
{/each}
<p>{selectData.filter(d => d.selected).length} selected</p>
<Button Icon={expanded ? IconX : IconListDetails} type="button" extra="!px-2 !py-1 !text-xs !rounded-sm" onclick={() => {expanded = !expanded; focused = true}} onmouseleave={() => focused = false}>{expanded ? "Close" : "Select"}</Button>
{/if}
{#if expanded}
<ul transition:slide onmouseleave={() => focused = false} onmouseenter={() => focused = true} class="absolute flex flex-col gap-2 top-[calc(100%+10px)] z-1 left-0 w-full max-h-40 overflow-y-scroll bg-white rounded border border-gray-300 shadow-sm p-2 text-xs">
<div class="flex gap-2 items-center">
<IconSearch class="text-neutral-400"/>
<input type="text" placeholder="Search..." bind:value={search} class="block w-full text-sm !outline-none transition-all duration-300 ease-in-out border-transparent focus:border-b-2 focus:border-indigo-500">
</div>
<div class="w-full h-px bg-neutral-200"></div>
{#each search ? selectData.filter(d => d.name.toLowerCase().includes(search.toLowerCase())) : selectData as el}
<Button Icon={el.selected ? IconMinus : IconPlus} type="button" extra="!p-1 !text-xs !rounded-sm w-full !border-none" onclick={() => {el.selected = !el.selected}} inverted={!el.selected}>{el.name}</Button>
{/each}
</ul>
{/if}
</div>
</div>