File size: 2,747 Bytes
db66673
 
 
 
 
 
f7c8859
db66673
 
5dfba10
db66673
 
 
 
 
 
 
 
 
955bb3b
db66673
 
2961a5b
db66673
 
2961a5b
 
db66673
 
2961a5b
 
 
 
 
 
 
 
 
db66673
 
 
2961a5b
 
 
 
 
 
 
 
 
db66673
 
 
 
 
 
 
 
 
 
 
2961a5b
 
 
 
5dfba10
2961a5b
 
 
955bb3b
 
 
 
 
 
2961a5b
 
 
 
 
 
 
 
5dfba10
2961a5b
 
 
955bb3b
 
 
 
 
 
2961a5b
 
 
db66673
 
2961a5b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<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>