Spaces:
Running
Running
| <script lang="ts" generics="TData"> | |
| import type { Table } from '@tanstack/table-core'; | |
| import { Input } from '$lib/components/ui/input'; | |
| import { Button } from '$lib/components/ui/button'; | |
| import * as DropdownMenu from '$lib/components/ui/dropdown-menu'; | |
| import * as Select from '$lib/components/ui/select'; | |
| import MagnifyingGlassIcon from 'phosphor-svelte/lib/MagnifyingGlassIcon'; | |
| import SlidersHorizontalIcon from 'phosphor-svelte/lib/SlidersHorizontalIcon'; | |
| import XIcon from 'phosphor-svelte/lib/XIcon'; | |
| import { prettyMap } from '$lib/utils/format'; | |
| interface Props { | |
| table: Table<TData>; | |
| searchPlaceholder?: string; | |
| mapOptions?: string[]; | |
| } | |
| let { table, searchPlaceholder = 'Search…', mapOptions = [] }: Props = $props(); | |
| const globalFilter = $derived((table.getState().globalFilter as string) ?? ''); | |
| const mapFilter = $derived((table.getColumn('map_name')?.getFilterValue() as string) ?? '__all'); | |
| const isFiltered = $derived( | |
| (table.getState().globalFilter as string)?.length > 0 || | |
| table.getState().columnFilters.length > 0 | |
| ); | |
| </script> | |
| <div class="flex flex-wrap items-center gap-2 py-3"> | |
| <div class="relative"> | |
| <MagnifyingGlassIcon | |
| size={14} | |
| weight="bold" | |
| class="absolute top-1/2 left-2.5 -translate-y-1/2 text-muted-foreground" | |
| /> | |
| <Input | |
| placeholder={searchPlaceholder} | |
| value={globalFilter} | |
| oninput={(e) => table.setGlobalFilter(e.currentTarget.value)} | |
| class="h-8 w-[200px] pl-8 lg:w-[260px]" | |
| /> | |
| </div> | |
| {#if mapOptions.length > 0 && table.getColumn('map_name')} | |
| <Select.Root | |
| type="single" | |
| value={mapFilter} | |
| onValueChange={(v) => { | |
| table.getColumn('map_name')?.setFilterValue(v === '__all' ? undefined : v); | |
| }} | |
| > | |
| <Select.Trigger size="sm" class="h-8 min-w-[130px] capitalize"> | |
| {mapFilter === '__all' ? 'All maps' : prettyMap(mapFilter)} | |
| </Select.Trigger> | |
| <Select.Content> | |
| <Select.Item value="__all">All maps</Select.Item> | |
| {#each mapOptions as map (map)} | |
| <Select.Item value={map} class="capitalize">{prettyMap(map)}</Select.Item> | |
| {/each} | |
| </Select.Content> | |
| </Select.Root> | |
| {/if} | |
| {#if isFiltered} | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| class="h-8 px-2" | |
| onclick={() => { | |
| table.setGlobalFilter(''); | |
| table.resetColumnFilters(); | |
| }} | |
| > | |
| Reset | |
| <XIcon size={12} weight="bold" class="ml-1" /> | |
| </Button> | |
| {/if} | |
| <div class="ml-auto flex items-center gap-2"> | |
| <DropdownMenu.Root> | |
| <DropdownMenu.Trigger> | |
| {#snippet child({ props })} | |
| <Button {...props} variant="outline" size="sm" class="h-8"> | |
| <SlidersHorizontalIcon size={12} weight="bold" /> | |
| View | |
| </Button> | |
| {/snippet} | |
| </DropdownMenu.Trigger> | |
| <DropdownMenu.Content align="end" class="w-[180px]"> | |
| <DropdownMenu.Label>Toggle columns</DropdownMenu.Label> | |
| <DropdownMenu.Separator /> | |
| {#each table.getAllColumns().filter((c) => c.getCanHide()) as column (column.id)} | |
| <DropdownMenu.CheckboxItem | |
| class="capitalize" | |
| checked={column.getIsVisible()} | |
| onCheckedChange={(v) => column.toggleVisibility(!!v)} | |
| > | |
| {(column.columnDef.meta as { label?: string } | undefined)?.label ?? | |
| column.id.replace(/_/g, ' ')} | |
| </DropdownMenu.CheckboxItem> | |
| {/each} | |
| </DropdownMenu.Content> | |
| </DropdownMenu.Root> | |
| </div> | |
| </div> | |