|
52 | 52 | export let className = 'w-[32rem]'; |
53 | 53 | export let triggerClassName = 'text-lg'; |
54 | 54 |
|
| 55 | + let tagsContainerElement; |
| 56 | +
|
55 | 57 | let show = false; |
| 58 | + let tags = []; |
56 | 59 |
|
57 | 60 | let selectedModel = ''; |
58 | 61 | $: selectedModel = items.find((item) => item.value === value) ?? ''; |
59 | 62 |
|
60 | 63 | let searchValue = ''; |
| 64 | + let selectedTag = ''; |
| 65 | +
|
61 | 66 | let ollamaVersion = null; |
62 | 67 |
|
63 | 68 | let selectedModelIdx = 0; |
|
79 | 84 | ); |
80 | 85 |
|
81 | 86 | $: filteredItems = searchValue |
82 | | - ? fuse.search(searchValue).map((e) => { |
83 | | - return e.item; |
84 | | - }) |
85 | | - : items; |
| 87 | + ? fuse |
| 88 | + .search(searchValue) |
| 89 | + .map((e) => { |
| 90 | + return e.item; |
| 91 | + }) |
| 92 | + .filter((item) => { |
| 93 | + if (selectedTag === '') { |
| 94 | + return true; |
| 95 | + } |
| 96 | + return item.model?.info?.meta?.tags?.map((tag) => tag.name).includes(selectedTag); |
| 97 | + }) |
| 98 | + : items.filter((item) => { |
| 99 | + if (selectedTag === '') { |
| 100 | + return true; |
| 101 | + } |
| 102 | + return item.model?.info?.meta?.tags?.map((tag) => tag.name).includes(selectedTag); |
| 103 | + }); |
86 | 104 |
|
87 | 105 | const pullModelHandler = async () => { |
88 | 106 | const sanitizedModelTag = searchValue.trim().replace(/^ollama\s+(run|pull)\s+/, ''); |
|
214 | 232 |
|
215 | 233 | onMount(async () => { |
216 | 234 | ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false); |
| 235 | +
|
| 236 | + if (items) { |
| 237 | + tags = items.flatMap((item) => item.model?.info?.meta?.tags ?? []); |
| 238 | + tags = [...new Set(tags)].map((tag) => tag.name).sort(); |
| 239 | + } |
217 | 240 | }); |
218 | 241 |
|
219 | 242 | const cancelModelPullHandler = async (model: string) => { |
|
298 | 321 | /> |
299 | 322 | </div> |
300 | 323 |
|
301 | | - <hr class="border-gray-100 dark:border-gray-850" /> |
| 324 | + <hr class="border-gray-100 dark:border-gray-800" /> |
302 | 325 | {/if} |
303 | 326 |
|
304 | | - <div class="px-3 my-2 max-h-64 overflow-y-auto scrollbar-hidden group"> |
| 327 | + <div class="px-3 my-2 max-h-64 overflow-y-auto scrollbar-hidden group relative"> |
| 328 | + {#if tags} |
| 329 | + <div class=" flex w-full sticky"> |
| 330 | + <div |
| 331 | + class="flex gap-1 scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5" |
| 332 | + bind:this={tagsContainerElement} |
| 333 | + > |
| 334 | + <button |
| 335 | + class="min-w-fit outline-none p-1.5 {selectedTag === '' |
| 336 | + ? '' |
| 337 | + : 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition" |
| 338 | + on:click={() => { |
| 339 | + selectedTag = ''; |
| 340 | + }} |
| 341 | + > |
| 342 | + {$i18n.t('All')} |
| 343 | + </button> |
| 344 | + |
| 345 | + {#each tags as tag} |
| 346 | + <button |
| 347 | + class="min-w-fit outline-none p-1.5 {selectedTag === tag |
| 348 | + ? '' |
| 349 | + : 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition" |
| 350 | + on:click={() => { |
| 351 | + selectedTag = tag; |
| 352 | + }} |
| 353 | + > |
| 354 | + {tag} |
| 355 | + </button> |
| 356 | + {/each} |
| 357 | + </div> |
| 358 | + </div> |
| 359 | + {/if} |
| 360 | + |
305 | 361 | {#each filteredItems as item, index} |
306 | 362 | <button |
307 | 363 | aria-label="model-item" |
|
441 | 497 | {/if} |
442 | 498 |
|
443 | 499 | {#if !$mobile && (item?.model?.info?.meta?.tags ?? []).length > 0} |
444 | | - <div class="flex gap-0.5 self-center items-center h-full translate-y-[0.5px]"> |
| 500 | + <div |
| 501 | + class="flex gap-0.5 self-center items-center h-full translate-y-[0.5px] overflow-x-auto scrollbar-none" |
| 502 | + > |
445 | 503 | {#each item.model?.info?.meta.tags as tag} |
446 | | - <Tooltip content={tag.name}> |
| 504 | + <Tooltip content={tag.name} className="flex-shrink-0"> |
447 | 505 | <div |
448 | | - class=" text-xs font-bold px-1 rounded-sm uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200" |
| 506 | + class=" text-xs font-bold px-1 rounded-sm uppercase bg-gray-500/20 text-gray-700 dark:text-gray-200" |
449 | 507 | > |
450 | 508 | {tag.name} |
451 | 509 | </div> |
|
575 | 633 | </div> |
576 | 634 |
|
577 | 635 | {#if showTemporaryChatControl} |
578 | | - <hr class="border-gray-100 dark:border-gray-850" /> |
| 636 | + <hr class="border-gray-100 dark:border-gray-800" /> |
579 | 637 |
|
580 | 638 | <div class="flex items-center mx-2 my-2"> |
581 | 639 | <button |
|
0 commit comments