summaryrefslogtreecommitdiff
path: root/llama.cpp/tools/server/webui/src/lib/components/ui/select
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-02-12 20:57:17 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-02-12 20:57:17 +0100
commitb333b06772c89d96aacb5490d6a219fba7c09cc6 (patch)
tree211df60083a5946baa2ed61d33d8121b7e251b06 /llama.cpp/tools/server/webui/src/lib/components/ui/select
downloadllmnpc-b333b06772c89d96aacb5490d6a219fba7c09cc6.tar.gz
Engage!
Diffstat (limited to 'llama.cpp/tools/server/webui/src/lib/components/ui/select')
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/index.ts37
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-content.svelte111
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group-heading.svelte21
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group.svelte7
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-item.svelte38
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-label.svelte20
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-down-button.svelte20
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-up-button.svelte20
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-separator.svelte18
-rw-r--r--llama.cpp/tools/server/webui/src/lib/components/ui/select/select-trigger.svelte40
10 files changed, 332 insertions, 0 deletions
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/index.ts b/llama.cpp/tools/server/webui/src/lib/components/ui/select/index.ts
new file mode 100644
index 0000000..bfa73d9
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/index.ts
@@ -0,0 +1,37 @@
+import { Select as SelectPrimitive } from 'bits-ui';
+
+import Group from './select-group.svelte';
+import Label from './select-label.svelte';
+import Item from './select-item.svelte';
+import Content from './select-content.svelte';
+import Trigger from './select-trigger.svelte';
+import Separator from './select-separator.svelte';
+import ScrollDownButton from './select-scroll-down-button.svelte';
+import ScrollUpButton from './select-scroll-up-button.svelte';
+import GroupHeading from './select-group-heading.svelte';
+
+const Root = SelectPrimitive.Root;
+
+export {
+ Root,
+ Group,
+ Label,
+ Item,
+ Content,
+ Trigger,
+ Separator,
+ ScrollDownButton,
+ ScrollUpButton,
+ GroupHeading,
+ //
+ Root as Select,
+ Group as SelectGroup,
+ Label as SelectLabel,
+ Item as SelectItem,
+ Content as SelectContent,
+ Trigger as SelectTrigger,
+ Separator as SelectSeparator,
+ ScrollDownButton as SelectScrollDownButton,
+ ScrollUpButton as SelectScrollUpButton,
+ GroupHeading as SelectGroupHeading
+};
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-content.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-content.svelte
new file mode 100644
index 0000000..4050628
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-content.svelte
@@ -0,0 +1,111 @@
+<script lang="ts">
+ import { onDestroy, onMount } from 'svelte';
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import SelectScrollUpButton from './select-scroll-up-button.svelte';
+ import SelectScrollDownButton from './select-scroll-down-button.svelte';
+ import { cn, type WithoutChild } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ sideOffset = 4,
+ portalProps,
+ children,
+ ...restProps
+ }: WithoutChild<SelectPrimitive.ContentProps> & {
+ portalProps?: SelectPrimitive.PortalProps;
+ } = $props();
+
+ let cleanupInternalListeners: (() => void) | undefined;
+
+ onMount(() => {
+ const listenerOptions: AddEventListenerOptions = { passive: false };
+
+ const blockOutsideWheel = (event: WheelEvent) => {
+ if (!ref) {
+ return;
+ }
+
+ const target = event.target as Node | null;
+
+ if (!target || !ref.contains(target)) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ };
+
+ const blockOutsideTouchMove = (event: TouchEvent) => {
+ if (!ref) {
+ return;
+ }
+
+ const target = event.target as Node | null;
+
+ if (!target || !ref.contains(target)) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ };
+
+ document.addEventListener('wheel', blockOutsideWheel, listenerOptions);
+ document.addEventListener('touchmove', blockOutsideTouchMove, listenerOptions);
+
+ return () => {
+ document.removeEventListener('wheel', blockOutsideWheel, listenerOptions);
+ document.removeEventListener('touchmove', blockOutsideTouchMove, listenerOptions);
+ };
+ });
+
+ $effect(() => {
+ const element = ref;
+
+ cleanupInternalListeners?.();
+
+ if (!element) {
+ return;
+ }
+
+ const stopWheelPropagation = (event: WheelEvent) => {
+ event.stopPropagation();
+ };
+
+ const stopTouchPropagation = (event: TouchEvent) => {
+ event.stopPropagation();
+ };
+
+ element.addEventListener('wheel', stopWheelPropagation);
+ element.addEventListener('touchmove', stopTouchPropagation);
+
+ cleanupInternalListeners = () => {
+ element.removeEventListener('wheel', stopWheelPropagation);
+ element.removeEventListener('touchmove', stopTouchPropagation);
+ };
+ });
+
+ onDestroy(() => {
+ cleanupInternalListeners?.();
+ });
+</script>
+
+<SelectPrimitive.Portal {...portalProps}>
+ <SelectPrimitive.Content
+ bind:ref
+ {sideOffset}
+ data-slot="select-content"
+ class={cn(
+ 'relative z-[var(--layer-popover,1000000)] max-h-(--bits-select-content-available-height) min-w-[8rem] origin-(--bits-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:translate-y-1 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:-translate-x-1 data-[side=left]:slide-in-from-right-2 data-[side=right]:translate-x-1 data-[side=right]:slide-in-from-left-2 data-[side=top]:-translate-y-1 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
+ className
+ )}
+ {...restProps}
+ >
+ <SelectScrollUpButton />
+ <SelectPrimitive.Viewport
+ class={cn(
+ 'h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1 p-1'
+ )}
+ >
+ {@render children?.()}
+ </SelectPrimitive.Viewport>
+ <SelectScrollDownButton />
+ </SelectPrimitive.Content>
+</SelectPrimitive.Portal>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group-heading.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group-heading.svelte
new file mode 100644
index 0000000..77c2042
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group-heading.svelte
@@ -0,0 +1,21 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import { cn } from '$lib/components/ui/utils.js';
+ import type { ComponentProps } from 'svelte';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ children,
+ ...restProps
+ }: ComponentProps<typeof SelectPrimitive.GroupHeading> = $props();
+</script>
+
+<SelectPrimitive.GroupHeading
+ bind:ref
+ data-slot="select-group-heading"
+ class={cn('px-2 py-1.5 text-xs text-muted-foreground', className)}
+ {...restProps}
+>
+ {@render children?.()}
+</SelectPrimitive.GroupHeading>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group.svelte
new file mode 100644
index 0000000..2520795
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-group.svelte
@@ -0,0 +1,7 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from 'bits-ui';
+
+ let { ref = $bindable(null), ...restProps }: SelectPrimitive.GroupProps = $props();
+</script>
+
+<SelectPrimitive.Group data-slot="select-group" {...restProps} />
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-item.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-item.svelte
new file mode 100644
index 0000000..02543c1
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-item.svelte
@@ -0,0 +1,38 @@
+<script lang="ts">
+ import CheckIcon from '@lucide/svelte/icons/check';
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import { cn, type WithoutChild } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ value,
+ label,
+ children: childrenProp,
+ ...restProps
+ }: WithoutChild<SelectPrimitive.ItemProps> = $props();
+</script>
+
+<SelectPrimitive.Item
+ bind:ref
+ {value}
+ data-slot="select-item"
+ class={cn(
+ "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
+ className
+ )}
+ {...restProps}
+>
+ {#snippet children({ selected, highlighted })}
+ <span class="absolute right-2 flex size-3.5 items-center justify-center">
+ {#if selected}
+ <CheckIcon class="size-4" />
+ {/if}
+ </span>
+ {#if childrenProp}
+ {@render childrenProp({ selected, highlighted })}
+ {:else}
+ {label || value}
+ {/if}
+ {/snippet}
+</SelectPrimitive.Item>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-label.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-label.svelte
new file mode 100644
index 0000000..e2b830c
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-label.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import { cn, type WithElementRef } from '$lib/components/ui/utils.js';
+ import type { HTMLAttributes } from 'svelte/elements';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ children,
+ ...restProps
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {} = $props();
+</script>
+
+<div
+ bind:this={ref}
+ data-slot="select-label"
+ class={cn('px-2 py-1.5 text-xs text-muted-foreground', className)}
+ {...restProps}
+>
+ {@render children?.()}
+</div>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-down-button.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-down-button.svelte
new file mode 100644
index 0000000..9256dd8
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-down-button.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import { cn, type WithoutChildrenOrChild } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: WithoutChildrenOrChild<SelectPrimitive.ScrollDownButtonProps> = $props();
+</script>
+
+<SelectPrimitive.ScrollDownButton
+ bind:ref
+ data-slot="select-scroll-down-button"
+ class={cn('flex cursor-default items-center justify-center py-1', className)}
+ {...restProps}
+>
+ <ChevronDownIcon class="size-4" />
+</SelectPrimitive.ScrollDownButton>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-up-button.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-up-button.svelte
new file mode 100644
index 0000000..552e527
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-scroll-up-button.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import { cn, type WithoutChildrenOrChild } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: WithoutChildrenOrChild<SelectPrimitive.ScrollUpButtonProps> = $props();
+</script>
+
+<SelectPrimitive.ScrollUpButton
+ bind:ref
+ data-slot="select-scroll-up-button"
+ class={cn('flex cursor-default items-center justify-center py-1', className)}
+ {...restProps}
+>
+ <ChevronUpIcon class="size-4" />
+</SelectPrimitive.ScrollUpButton>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-separator.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-separator.svelte
new file mode 100644
index 0000000..7daaa8d
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-separator.svelte
@@ -0,0 +1,18 @@
+<script lang="ts">
+ import type { Separator as SeparatorPrimitive } from 'bits-ui';
+ import { Separator } from '$lib/components/ui/separator/index.js';
+ import { cn } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: SeparatorPrimitive.RootProps = $props();
+</script>
+
+<Separator
+ bind:ref
+ data-slot="select-separator"
+ class={cn('pointer-events-none -mx-1 my-1 h-px bg-border', className)}
+ {...restProps}
+/>
diff --git a/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-trigger.svelte b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-trigger.svelte
new file mode 100644
index 0000000..5bc28ee
--- /dev/null
+++ b/llama.cpp/tools/server/webui/src/lib/components/ui/select/select-trigger.svelte
@@ -0,0 +1,40 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from 'bits-ui';
+ import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
+ import { cn, type WithoutChild } from '$lib/components/ui/utils.js';
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ children,
+ size = 'default',
+ variant = 'default',
+ ...restProps
+ }: WithoutChild<SelectPrimitive.TriggerProps> & {
+ size?: 'sm' | 'default';
+ variant?: 'default' | 'plain';
+ } = $props();
+
+ const baseClasses = $derived(
+ variant === 'plain'
+ ? "group inline-flex w-full items-center justify-end gap-2 whitespace-nowrap px-0 py-0 text-sm font-medium text-muted-foreground transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3 [&_svg:not([class*='text-'])]:text-muted-foreground"
+ : "flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground"
+ );
+
+ const chevronClasses = $derived(
+ variant === 'plain'
+ ? 'size-3 opacity-60 transition-transform group-data-[state=open]:-rotate-180'
+ : 'size-4 opacity-50'
+ );
+</script>
+
+<SelectPrimitive.Trigger
+ bind:ref
+ data-slot="select-trigger"
+ data-size={size}
+ class={cn(baseClasses, className)}
+ {...restProps}
+>
+ {@render children?.()}
+ <ChevronDownIcon class={chevronClasses} />
+</SelectPrimitive.Trigger>