diff options
Diffstat (limited to 'llama.cpp/tools/server/webui/src/lib/components/ui/select')
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> |
