From 6ec02a4c819afb9458b10a3ff0b07934dada3de7 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Sat, 5 Sep 2026 01:13:43 +0200 Subject: [PATCH] ui : models discover dialog Add the Models Discover explorer behind a new sidebar action and full-screen dialog: a searchable HuggingFace GGUF list (org avatars, capability icons, catalog size ranges) and a detail pane with header, metadata chips, the sanitized model-card readme and the download area - per-quant action chips grouped by bit depth, sidecar queuing and a scrollable serve-command preview with dynamic quant selects. Searchable dropdowns gain sticky headers/footers. Assisted-by: pi:GLM-5.3-Flash --- .../app/dialogs/DialogModelsDiscover.svelte | 25 ++ .../src/lib/components/app/dialogs/index.ts | 10 + .../app/models/discover/ModelsDiscover.svelte | 138 +++++++++ .../ModelsDiscoverChatTemplateDialog.svelte | 67 +++++ .../ModelsDiscoverDetails.svelte | 96 ++++++ ...odelsDiscoverDetailsDownloadOptions.svelte | 173 +++++++++++ ...tailsDownloadOptionsDownloadCommand.svelte | 278 ++++++++++++++++++ ...sDownloadOptionsQuantDownloadButton.svelte | 244 +++++++++++++++ ...lsDiscoverDetailsDownloadOptionsRow.svelte | 60 ++++ .../download-options.utils.ts | 28 ++ .../index.ts | 40 +++ .../ModelsDiscoverDetailsHeader.svelte | 93 ++++++ .../ModelsDiscoverDetailsHfHubStats.svelte | 31 ++ .../ModelsDiscoverDetailsMetadata.svelte | 80 +++++ .../ModelsDiscoverDetailsMetadataItem.svelte | 15 + .../ModelsDiscoverDetailsReadme.svelte | 17 ++ .../ModelsDiscoverDetailsSkeleton.svelte | 93 ++++++ .../discover/ModelsDiscoverDetails/index.ts | 72 +++++ ... ModelsDiscoverDownloadProgressBar.svelte} | 0 .../ModelsDiscoverList.svelte | 41 +++ .../ModelsDiscoverListItem.svelte | 129 ++++++++ .../ModelsDiscoverListItemSkeleton.svelte | 39 +++ .../ModelsDiscoverListSearch.svelte | 22 ++ .../discover/ModelsDiscoverList/index.ts | 38 +++ .../components/app/models/discover/index.ts | 39 +++ .../SidebarNavigation.svelte | 5 + .../SidebarNavigationActions.svelte | 62 ++-- .../ui/select/select-trigger.svelte | 12 +- tools/ui/src/lib/constants/index.ts | 1 + .../models-discover-download.constants.ts | 54 ++++ .../lib/constants/settings-keys.constants.ts | 1 + .../src/lib/constants/settings.constants.ts | 7 + tools/ui/src/lib/constants/ui.constants.ts | 7 +- tools/ui/src/lib/enums/ui.enums.ts | 1 + tools/ui/src/lib/utils/index.ts | 2 +- 35 files changed, 1991 insertions(+), 29 deletions(-) create mode 100644 tools/ui/src/lib/components/app/dialogs/DialogModelsDiscover.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscover.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverChatTemplateDialog.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetails.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptions.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsDownloadCommand.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsRow.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/download-options.utils.ts create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/index.ts create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHeader.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHfHubStats.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadata.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadataItem.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsReadme.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsSkeleton.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/index.ts rename tools/ui/src/lib/components/app/models/discover/{DownloadProgressBar.svelte => ModelsDiscoverDownloadProgressBar.svelte} (100%) create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverList.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItem.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItemSkeleton.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListSearch.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/index.ts create mode 100644 tools/ui/src/lib/components/app/models/discover/index.ts create mode 100644 tools/ui/src/lib/constants/models-discover-download.constants.ts diff --git a/tools/ui/src/lib/components/app/dialogs/DialogModelsDiscover.svelte b/tools/ui/src/lib/components/app/dialogs/DialogModelsDiscover.svelte new file mode 100644 index 0000000000..43f1c09fdf --- /dev/null +++ b/tools/ui/src/lib/components/app/dialogs/DialogModelsDiscover.svelte @@ -0,0 +1,25 @@ + + + + + + + diff --git a/tools/ui/src/lib/components/app/dialogs/index.ts b/tools/ui/src/lib/components/app/dialogs/index.ts index 9b0b62bd08..5f05f91750 100644 --- a/tools/ui/src/lib/components/app/dialogs/index.ts +++ b/tools/ui/src/lib/components/app/dialogs/index.ts @@ -537,3 +537,13 @@ export { default as DialogMcpResourcePreview } from './DialogMcpResourcePreview. * ``` */ export { default as DialogMermaidPreview } from './DialogMermaidPreview.svelte'; + +/** + * **DialogModelsDiscover** - full-screen model discovery dialog. + * + * Two-pane layout: searchable model list (Hugging Face + llama.app catalog) + * on the left, model details with download options on the right. + * + * @see ModelsDiscover in $lib/components/app/models/discover + */ +export { default as DialogModelsDiscover } from './DialogModelsDiscover.svelte'; diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscover.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscover.svelte new file mode 100644 index 0000000000..d9fd1f3854 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscover.svelte @@ -0,0 +1,138 @@ + + + + +
+ {#if selectedId} + + {/if} +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverChatTemplateDialog.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverChatTemplateDialog.svelte new file mode 100644 index 0000000000..d64642676e --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverChatTemplateDialog.svelte @@ -0,0 +1,67 @@ + + + + + + + Chat template + + + + + + + + +
{chatTemplate}
+
+
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetails.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetails.svelte new file mode 100644 index 0000000000..3d15e6f1a6 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetails.svelte @@ -0,0 +1,96 @@ + + +{#if loading} + +{:else if error} +
+

{error}

+
+{:else if details} +
+ + + + + +
+{/if} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptions.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptions.svelte new file mode 100644 index 0000000000..ed6ddfe66b --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptions.svelte @@ -0,0 +1,173 @@ + + +{#if bitDepthRows.length} +
+ +
+ {#each rows as row (row.bitDepth)} + + {/each} +
+ + +
+ +
+
+{/if} + + (confirmOpen = false)} + open={confirmOpen} + repoWithTag={pending.repoWithTag} +/> diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsDownloadCommand.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsDownloadCommand.svelte new file mode 100644 index 0000000000..e380505f38 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsDownloadCommand.svelte @@ -0,0 +1,278 @@ + + + + +
+ +
+ {SERVE_COMMAND.BIN} + + {SERVE_COMMAND.SUBCOMMAND} + + {SERVE_COMMAND.MODEL_FLAG} + + + {modelId}{mainQuant ? MODEL_ID.QUANTIZATION_SEPARATOR : ''} + + + + {#if baseOption} + v && (basePick = v)} type="single" value={baseOption.path}> + + {baseOption.label} + + + + {#each mainOptions as option (option.path)} + + {option.label} + + {/each} + + + {/if} + + + {#if draftOptions.length && !withDraft} + + {/if} + + + {#if draftOption} + + {SERVE_COMMAND.DRAFT_FLAG} + + + {modelId}{draftQuant ? MODEL_ID.QUANTIZATION_SEPARATOR : ''} + + + v && (draftPick = v)} + type="single" + value={draftOption.path} + > + + {draftOption.label} + + + + {#each typeDraftOptions as option (option.path)} + + {option.label} + + {/each} + + + + {#if draftType} + {SERVE_COMMAND.SPEC_TYPE_FLAG} + + + {#if specTypes.length > 1} + v && (draftTypePick = v as ModelSidecar)} + type="single" + value={draftType} + > + + {SPEC_TYPE[draftType]} + + + + {#each specTypes as type (type)} + + {SPEC_TYPE[type]} + + {/each} + + + {:else} + {SPEC_TYPE[draftType]} + {/if} + {/if} + + + + {/if} +
+ + +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton.svelte new file mode 100644 index 0000000000..c64ebe556b --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton.svelte @@ -0,0 +1,244 @@ + + +{#snippet chipBody(dividerClass: string)} + + {#if meta?.sidecar} + + {meta.sidecar} + + {/if} + + {label} + + +{/snippet} + + +{#snippet tooltipTrigger(tip: string, button: Snippet<[Record]>)} + + + {#snippet child({ props })} + {@render button(props)} + {/snippet} + + + +

{tip}

+
+
+{/snippet} + +{#snippet deleteChip(props: Record)} + + +{/snippet} + +{#snippet pauseResumeChip(props: Record)} + +{/snippet} + +{#snippet cancelChip(props: Record)} + + +{/snippet} + +{#snippet downloadChip(props: Record)} + + +{/snippet} + +{#if entry.isDownloaded} + {@render tooltipTrigger(tooltipText, deleteChip)} +{:else if entry.isDownloading || entry.isPaused} + +
+ {@render tooltipTrigger(tooltipText, pauseResumeChip)} + + {@render tooltipTrigger('Cancel downloading', cancelChip)} + + {#if percent !== null} + + {/if} +
+{:else} + {@render tooltipTrigger(tooltipText, downloadChip)} +{/if} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsRow.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsRow.svelte new file mode 100644 index 0000000000..11bfe45d42 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/ModelsDiscoverDetailsDownloadOptionsRow.svelte @@ -0,0 +1,60 @@ + + +
+
+ {#if bitDepth === OTHER_BIT_DEPTH} + {OTHER_BIT_DEPTH_LABEL} + {:else} + {bitDepth}{BIT_DEPTH_LABEL_SUFFIX} + {/if} + + {#if mainMemGb} + + needs at least {mainMemGb}{GIGABYTE_LABEL}{draftMemGb + ? ` + ${draftMemGb}${GIGABYTE_LABEL}` + : ''} memory + + {/if} +
+ +
+ {#each files as file (file.path)} + + {/each} +
+
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/download-options.utils.ts b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/download-options.utils.ts new file mode 100644 index 0000000000..4dd8accb42 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/download-options.utils.ts @@ -0,0 +1,28 @@ +import { DRAFT_FILE_LABEL, MODEL_ID, PATH_SEPARATOR } from '$lib/constants'; +import { ModelSelectableFileKind } from '$lib/enums'; +import { HuggingFaceService } from '$lib/services'; +import { isAuxSidecar, isDraftSidecar } from '$lib/utils'; + +/** Kind of a file path: the main weights, a draft sidecar, or an aux sidecar (mmproj). */ +export function classify(path: string): ModelSelectableFileKind { + const sidecar = HuggingFaceService.extractQuantMeta(path)?.sidecar; + + if (!sidecar) return ModelSelectableFileKind.MAIN; + + return isAuxSidecar(sidecar) ? ModelSelectableFileKind.AUX : ModelSelectableFileKind.DRAFT; +} + +/** Display label of a file: its quant, else the file name without the extension. */ +export function labelFor(path: string): string { + const meta = HuggingFaceService.extractQuantMeta(path); + + if (meta?.quant) return meta.quant; + + // Quantless sidecar files: the chip badge already carries the sidecar type, + // so the label only marks draft files; aux sidecars badge alone. + if (meta?.sidecar) return isDraftSidecar(meta.sidecar) ? DRAFT_FILE_LABEL : ''; + + const basename = path.split(PATH_SEPARATOR).pop() ?? path; + + return basename.replace(MODEL_ID.WEIGHT_EXTENSION_REGEX, ''); +} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/index.ts b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/index.ts new file mode 100644 index 0000000000..b5c0ebef67 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsDownloadOptions/index.ts @@ -0,0 +1,40 @@ +/** + * + * MODELS DISCOVER - DETAILS - DOWNLOAD OPTIONS + * + * The download area of the detail pane: GGUF files grouped by bit depth, each an + * independent download action chip, plus the standalone terminal command preview. + * + */ + +/** + * **ModelsDiscoverDetailsDownloadOptions** - GGUF download options + * + * Groups GGUF files by bit depth and renders one independent download + * action chip per file, plus the standalone terminal command preview. + */ +export { default as ModelsDiscoverDetailsDownloadOptions } from './ModelsDiscoverDetailsDownloadOptions.svelte'; + +/** + * **ModelsDiscoverDetailsDownloadOptionsRow** - One bit-depth group of quants + * + * A single bit-depth row inside ModelsDiscoverDetailsDownloadOptions: the + * depth label with its memory hint and the quant chips of that depth. + */ +export { default as ModelsDiscoverDetailsDownloadOptionsRow } from './ModelsDiscoverDetailsDownloadOptionsRow.svelte'; + +/** + * **ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton** - One quant chip + * + * A single GGUF file as an independent action chip: download / retry when + * idle, pause / resume / cancel while in flight, delete when downloaded. + */ +export { default as ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton } from './ModelsDiscoverDetailsDownloadOptionsQuantDownloadButton.svelte'; + +/** + * **ModelsDiscoverDetailsDownloadOptionsDownloadCommand** - Terminal command + * + * The `llama serve -hf ...` command box with inline quant selects and a copy + * button; owns its picks, nothing two-way binds them to the quant chips. + */ +export { default as ModelsDiscoverDetailsDownloadOptionsDownloadCommand } from './ModelsDiscoverDetailsDownloadOptionsDownloadCommand.svelte'; diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHeader.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHeader.svelte new file mode 100644 index 0000000000..0536ac975a --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHeader.svelte @@ -0,0 +1,93 @@ + + +
+
+
+ + +
+
+

{details.id ?? modelId}

+ + +
+ + {#if baseModels.length} +
+ {baseModels.join(', ')} + + + + +
+ {/if} +
+
+ + + + + View on Hugging Face + + + +
+ + + + +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHfHubStats.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHfHubStats.svelte new file mode 100644 index 0000000000..b848a9bfeb --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsHfHubStats.svelte @@ -0,0 +1,31 @@ + + +
+ {#if typeof details.downloads === 'number'} + + + {HuggingFaceService.formatDownloads(details.downloads)} + + {/if} + + {#if typeof details.likes === 'number'} + + + {HuggingFaceService.formatLikes(details.likes)} + + {/if} + + {#if details.lastModified} + Updated {HuggingFaceService.formatRelativeTime(details.lastModified)} + {/if} +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadata.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadata.svelte new file mode 100644 index 0000000000..4d737e4565 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadata.svelte @@ -0,0 +1,80 @@ + + +{#if description} +

{description}

+{/if} + + +
+ {#if gguf?.total} + + {/if} + + {#if gguf?.context_length} + + {/if} + + {#if gguf?.architecture} + + {/if} + + {#if gguf?.chat_template} + + {/if} + + {#if licenseTag} + + {/if} + + {#if details.gated === true} + + gated + + {/if} +
+ +{#if gguf?.chat_template} + +{/if} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadataItem.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadataItem.svelte new file mode 100644 index 0000000000..3fc87cb362 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsMetadataItem.svelte @@ -0,0 +1,15 @@ + + + + + {label} + + {value} + diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsReadme.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsReadme.svelte new file mode 100644 index 0000000000..3d000ec5a4 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsReadme.svelte @@ -0,0 +1,17 @@ + + +{#if readme} +
+ +
+{/if} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsSkeleton.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsSkeleton.svelte new file mode 100644 index 0000000000..0722154f00 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/ModelsDiscoverDetailsSkeleton.svelte @@ -0,0 +1,93 @@ + + + +
+ +
+
+
+ + +
+ + + +
+
+ + +
+ + +
+ + + + + +
+ + +
+
+ + + + + + + +
+
+
+ + +
+
+ {#each [0, 1, 2] as _, index (index)} +
+
+ + + +
+ +
+ + + +
+
+ {/each} +
+ +
+ + +
+ + + + + +
+ + +
+
+ + +
+ + + + + + + +
+
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/index.ts b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/index.ts new file mode 100644 index 0000000000..2420bd5ef2 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDetails/index.ts @@ -0,0 +1,72 @@ +/** + * + * MODELS DISCOVER - DETAILS + * + * The right-hand detail pane of the discover view: header (avatar, name, stats, metadata + * chips, capability badges), the download options area and the model-card README. + * + */ + +/** + * **ModelsDiscoverDetails** - Model detail view + * + * Detail pane for the selected model. Loads its own data (details + GGUF file + * list) from HuggingFaceService based on the `modelId` route param. + */ +export { default as ModelsDiscoverDetails } from './ModelsDiscoverDetails.svelte'; + +/** + * **ModelsDiscoverDetailsHeader** - Detail view header + * + * Shows the model avatar (base org + quant org corner badge), name, base model + * info, stats, metadata chips and capability badges. + */ +export { default as ModelsDiscoverDetailsHeader } from './ModelsDiscoverDetailsHeader.svelte'; + +/** + * **ModelsDiscoverDetailsHfHubStats** - HuggingFace Hub stats row + * + * Downloads, likes and last-updated for the viewed model, formatted the way + * the Hub shows them. + */ +export { default as ModelsDiscoverDetailsHfHubStats } from './ModelsDiscoverDetailsHfHubStats.svelte'; + +/** + * **ModelsDiscoverDetailsSkeleton** - Detail view loading skeleton + * + * Static placeholder matching the detail layout: header with avatar and name, + * metadata chips, the download options box and readme text lines. + */ +export { default as ModelsDiscoverDetailsSkeleton } from './ModelsDiscoverDetailsSkeleton.svelte'; + +/** + * **ModelsDiscoverDetailsReadme** - Detail view README + * + * Renders the model card README as markdown. + */ +export { default as ModelsDiscoverDetailsReadme } from './ModelsDiscoverDetailsReadme.svelte'; + +/** + * **ModelsDiscoverDetailsMetadata** - Detail view metadata row + * + * The detail view's metadata chips (model size, context, architecture, license, + * chat template). + */ +export { default as ModelsDiscoverDetailsMetadata } from './ModelsDiscoverDetailsMetadata.svelte'; + +/** + * **ModelsDiscoverDetailsMetadataItem** - Single metadata chip + * + * One label | value chip of the detail view's metadata row (model size, + * context, architecture, license). + */ +export { default as ModelsDiscoverDetailsMetadataItem } from './ModelsDiscoverDetailsMetadataItem.svelte'; + +/** + * **ModelsDiscoverChatTemplateDialog** - Chat template viewer + * + * Shows the model's chat template in a scrollable dialog with a copy button. + */ +export { default as ModelsDiscoverChatTemplateDialog } from './ModelsDiscoverChatTemplateDialog.svelte'; + +export * from './ModelsDiscoverDetailsDownloadOptions'; diff --git a/tools/ui/src/lib/components/app/models/discover/DownloadProgressBar.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDownloadProgressBar.svelte similarity index 100% rename from tools/ui/src/lib/components/app/models/discover/DownloadProgressBar.svelte rename to tools/ui/src/lib/components/app/models/discover/ModelsDiscoverDownloadProgressBar.svelte diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverList.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverList.svelte new file mode 100644 index 0000000000..1ebb3192ac --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverList.svelte @@ -0,0 +1,41 @@ + + +
    + {#if loading} + {#each Array(loadingSkeletonRowsCount) as _, index (index)} + + {/each} + {:else} + {#each models as model (model.id)} + + {/each} + {/if} +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItem.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItem.svelte new file mode 100644 index 0000000000..b1b1cdb85b --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItem.svelte @@ -0,0 +1,129 @@ + + +
  • + +
  • diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItemSkeleton.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItemSkeleton.svelte new file mode 100644 index 0000000000..851abc5238 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListItemSkeleton.svelte @@ -0,0 +1,39 @@ + + + +
  • +
    + + +
    + + +
    + {#each badgeWidths as width, i (i)} + + {/each} +
    +
    +
    +
  • diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListSearch.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListSearch.svelte new file mode 100644 index 0000000000..b26c09bd0f --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/ModelsDiscoverListSearch.svelte @@ -0,0 +1,22 @@ + + +
    + handleInput(v)} {placeholder} /> +
    diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/index.ts b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/index.ts new file mode 100644 index 0000000000..d888343a15 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverList/index.ts @@ -0,0 +1,38 @@ +/** + * + * MODELS DISCOVER - LIST + * + * The discover sidebar column: a debounced search field above a navigable list of + * HuggingFace GGUF models, with skeleton rows while loading. + * + */ + +/** + * **ModelsDiscoverList** - Sidebar model list + * + * Renders the discover model list as a navigable column. Each row links to the + * model's detail and highlights the active one. + */ +export { default as ModelsDiscoverList } from './ModelsDiscoverList.svelte'; + +/** + * **ModelsDiscoverListSearch** - Sidebar search input + * + * Debounced search field for the model list. + */ +export { default as ModelsDiscoverListSearch } from './ModelsDiscoverListSearch.svelte'; + +/** + * **ModelsDiscoverListItem** - Single sidebar row + * + * One model entry in the discover sidebar list, selectable via `onSelect`. + */ +export { default as ModelsDiscoverListItem } from './ModelsDiscoverListItem.svelte'; + +/** + * **ModelsDiscoverListItemSkeleton** - Skeleton sidebar row + * + * Pulsing placeholder matching a ModelsDiscoverListItem row, shown while the + * list is loading. + */ +export { default as ModelsDiscoverListItemSkeleton } from './ModelsDiscoverListItemSkeleton.svelte'; diff --git a/tools/ui/src/lib/components/app/models/discover/index.ts b/tools/ui/src/lib/components/app/models/discover/index.ts new file mode 100644 index 0000000000..5926b75153 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/index.ts @@ -0,0 +1,39 @@ +/** + * + * MODELS DISCOVER + * + * Components for the Models Discover view: a sidebar search + list of + * HuggingFace GGUF models and a detail view for the selected model, used as the + * body of the discovery dialog. The list and detail trees live in their own + * subfolders; this barrel re-exports them alongside the shared leaves. + * + */ + +/** + * **ModelsDiscover** - Models discover explorer + * + * The complete discovery layout: a sidebar search + model list on the left and a + * detail view for the selected model on the right. Used as the body of the + * discovery dialog. + */ +export { default as ModelsDiscover } from './ModelsDiscover.svelte'; + +/** + * **ModelsDiscoverAvatar** - Org avatar for a model row + * + * Shows the org's avatar image, falling back to a monogram on a stable hue + * derived from the org name when the image fails to load. Shared by the list, + * the detail header and the model selector rows. + */ +export { default as ModelsDiscoverAvatar } from './ModelsDiscoverAvatar.svelte'; + +/** + * **ModelsDiscoverDownloadProgressBar** - Thin download progress bar + * + * Normalizes bytes to a 0..100% bar; can pin to the bottom edge as an overlay. + * Shared by the quant chips and the model selector's download rows. + */ +export { default as ModelsDiscoverDownloadProgressBar } from './ModelsDiscoverDownloadProgressBar.svelte'; + +export * from './ModelsDiscoverList'; +export * from './ModelsDiscoverDetails'; diff --git a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte index 8bf12279e3..375461cc57 100644 --- a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte +++ b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte @@ -5,6 +5,7 @@ import { ActionIcon, DialogConversationRename, + DialogModelsDiscover, DialogSettingsChat, Logo, SidebarNavigationActions, @@ -93,6 +94,7 @@ let renameDialogOpen = $state(false); let settingsDialogOpen = $state(false); + let modelsDiscoverOpen = $state(false); let renameTargetConversationId = $state(null); let renameDraft = $state(''); let renameOriginalTitle = $state(''); @@ -389,6 +391,7 @@ bind:searchQuery class="px-2" isExpandedMode={innerWidth > 768 ? uiStore.isSidebarExpanded : true} + onDiscoverModelsClick={() => (modelsDiscoverOpen = true)} onNewChat={() => { if (deviceStore.isMobile) { scheduleMobileCollapse(); @@ -452,6 +455,8 @@ + +