Spaces:
Running
Running
| <script lang="ts"> | |
| import { Plus, Info, ChevronLeft } from '@lucide/svelte'; | |
| import * as Command from '$lib/components/ui/command/'; | |
| import { Button } from '$lib/components/ui/button/'; | |
| import { modelsState } from '$lib/state/models.svelte'; | |
| import { MAX_TRENDING_MODELS } from '$lib'; | |
| interface Props { | |
| onSelect?: (model: string) => void; | |
| excludeIds?: string[]; | |
| } | |
| let { onSelect, excludeIds = [] }: Props = $props(); | |
| let open = $state(false); | |
| let search = $state(''); | |
| const filteredModels = $derived( | |
| modelsState.models.filter((m) => { | |
| const matchesSearch = !search || m.id.toLowerCase().includes(search.toLowerCase()); | |
| const notExcluded = !excludeIds.includes(m.id); | |
| return matchesSearch && notExcluded; | |
| }) | |
| ); | |
| let trendingModels = $derived(filteredModels.slice(0, MAX_TRENDING_MODELS)); | |
| let otherModels = $derived(filteredModels.slice(MAX_TRENDING_MODELS)); | |
| </script> | |
| <Button | |
| variant="outline" | |
| size="icon-sm" | |
| class="!shadow-none!" | |
| onclick={() => { | |
| open = true; | |
| search = ''; | |
| }} | |
| > | |
| <Plus /> | |
| </Button> | |
| {#if excludeIds.length === 0} | |
| <p | |
| class="relative ml-1 flex items-center gap-1 rounded-md bg-gray-500/10 px-2.5 py-2 text-xs text-gray-600" | |
| > | |
| <ChevronLeft | |
| class="absolute top-1/2 -left-2 size-3 -translate-y-1/2 fill-gray-500/10 text-gray-500/10" | |
| /> | |
| <Info class="size-3" /> | |
| Please select at least one model. | |
| </p> | |
| {/if} | |
| <Command.Dialog bind:open shouldFilter={false}> | |
| <Command.Input bind:value={search} placeholder="Search models..." /> | |
| <Command.List> | |
| {#if modelsState.loading} | |
| <Command.Loading>Loading models...</Command.Loading> | |
| {:else if modelsState.error} | |
| <Command.Empty>{modelsState.error}</Command.Empty> | |
| {:else if filteredModels.length === 0} | |
| <Command.Empty>No results found.</Command.Empty> | |
| {:else} | |
| <Command.Group heading="🔥 Trending"> | |
| {#each trendingModels as model (model.id)} | |
| <Command.Item | |
| onSelect={() => { | |
| onSelect?.(model.id); | |
| open = false; | |
| }} | |
| > | |
| <img | |
| src={`https://huggingface.co/api/avatars/${model.owned_by}`} | |
| alt="" | |
| class="size-4 rounded-full" | |
| /> | |
| <span>{model.id.split('/').pop() ?? model.id}</span> | |
| </Command.Item> | |
| {/each} | |
| <Command.Separator /> | |
| </Command.Group> | |
| <Command.Group heading="Other models"> | |
| {#each otherModels as model (model.id)} | |
| <Command.Item | |
| onSelect={() => { | |
| onSelect?.(model.id); | |
| open = false; | |
| }} | |
| > | |
| <img | |
| src={`https://huggingface.co/api/avatars/${model.owned_by}`} | |
| alt="" | |
| class="size-4 rounded-full" | |
| /> | |
| <span>{model.id.split('/').pop() ?? model.id}</span> | |
| </Command.Item> | |
| {/each} | |
| </Command.Group> | |
| {/if} | |
| </Command.List> | |
| </Command.Dialog> | |