From a64667ca8d3bd6e0b4c8fec37881d50f2eeabfa8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 9 Jun 2025 01:24:11 +0400 Subject: [PATCH] feat: pinned models --- src/lib/components/chat/ModelSelector.svelte | 19 +++++++++++++++++++ .../chat/ModelSelector/ModelItem.svelte | 12 ++++-------- .../chat/ModelSelector/ModelItemMenu.svelte | 10 +++++----- .../chat/ModelSelector/Selector.svelte | 3 +++ src/lib/components/layout/Sidebar.svelte | 5 ++--- src/lib/stores/index.ts | 1 - 6 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/lib/components/chat/ModelSelector.svelte b/src/lib/components/chat/ModelSelector.svelte index f136d4cca..d30d55fe4 100644 --- a/src/lib/components/chat/ModelSelector.svelte +++ b/src/lib/components/chat/ModelSelector.svelte @@ -25,6 +25,24 @@ toast.success($i18n.t('Default model updated')); }; + const pinModelHandler = async (modelId) => { + let pinnedModels = $settings?.pinnedModels ?? []; + + if (pinnedModels.includes(modelId)) { + pinnedModels = pinnedModels.filter((id) => id !== modelId); + } else { + pinnedModels = [...new Set([...pinnedModels, modelId])]; + } + + if (pinnedModels.length > 5) { + toast.error($i18n.t('You can only pin up to 5 models.')); + return; + } + + settings.set({ ...$settings, pinnedModels: pinnedModels }); + await updateUserSettings(localStorage.token, { ui: $settings }); + }; + $: if (selectedModels.length > 0 && $models.length > 0) { selectedModels = selectedModels.map((model) => $models.map((m) => m.id).includes(model) ? model : '' @@ -49,6 +67,7 @@ ? ($user?.permissions?.chat?.temporary ?? true) && !($user?.permissions?.chat?.temporary_enforced ?? false) : true} + {pinModelHandler} bind:value={selectedModel} /> diff --git a/src/lib/components/chat/ModelSelector/ModelItem.svelte b/src/lib/components/chat/ModelSelector/ModelItem.svelte index 2d3e5f938..2e78a376b 100644 --- a/src/lib/components/chat/ModelSelector/ModelItem.svelte +++ b/src/lib/components/chat/ModelSelector/ModelItem.svelte @@ -4,7 +4,7 @@ import { getContext, tick } from 'svelte'; import dayjs from '$lib/dayjs'; - import { mobile, pinnedModels, user } from '$lib/stores'; + import { mobile, settings, user } from '$lib/stores'; import Tooltip from '$lib/components/common/Tooltip.svelte'; import { copyToClipboard, sanitizeResponseContent } from '$lib/utils'; @@ -22,6 +22,8 @@ export let value: string = ''; export let unloadModelHandler: (modelValue: string) => void = () => {}; + export let pinModelHandler: (modelValue: string) => void = () => {}; + export let onClick: () => void = () => {}; const copyLinkHandler = async (model) => { @@ -236,13 +238,7 @@ { - if ($pinnedModels.includes(item.model.id)) { - pinnedModels.set($pinnedModels.filter((id) => id !== item.model.id)); - } else { - pinnedModels.set([...new Set([...$pinnedModels, item.model.id])]); - } - }} + {pinModelHandler} copyLinkHandler={() => { copyLinkHandler(item.model); }} diff --git a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte index c588e648d..df5e0fb3c 100644 --- a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte +++ b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte @@ -8,14 +8,14 @@ import Link from '$lib/components/icons/Link.svelte'; import Eye from '$lib/components/icons/Eye.svelte'; import EyeSlash from '$lib/components/icons/EyeSlash.svelte'; - import { pinnedModels } from '$lib/stores'; + import { settings } from '$lib/stores'; const i18n = getContext('i18n'); export let show = false; export let model; - export let toggleSidebarHandler: Function = () => {}; + export let pinModelHandler: (modelId: string) => void = () => {}; export let copyLinkHandler: Function = () => {}; export let onClose: Function = () => {}; @@ -52,18 +52,18 @@ e.stopPropagation(); e.preventDefault(); - toggleSidebarHandler(); + pinModelHandler(model?.id); show = false; }} > - {#if ($pinnedModels ?? []).includes(model?.id)} + {#if ($settings?.pinnedModels ?? []).includes(model?.id)} {:else} {/if}
- {#if ($pinnedModels ?? []).includes(model?.id)} + {#if ($settings?.pinnedModels ?? []).includes(model?.id)} {$i18n.t('Hide from Sidebar')} {:else} {$i18n.t('Keep in Sidebar')} diff --git a/src/lib/components/chat/ModelSelector/Selector.svelte b/src/lib/components/chat/ModelSelector/Selector.svelte index d27e43b81..1e0f35639 100644 --- a/src/lib/components/chat/ModelSelector/Selector.svelte +++ b/src/lib/components/chat/ModelSelector/Selector.svelte @@ -57,6 +57,8 @@ export let className = 'w-[32rem]'; export let triggerClassName = 'text-lg'; + export let pinModelHandler: (modelId: string) => void = () => {}; + let tagsContainerElement; let show = false; @@ -500,6 +502,7 @@ {item} {index} {value} + {pinModelHandler} {unloadModelHandler} onClick={() => { value = item.value; diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index ee2150f21..f629b104a 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -22,7 +22,6 @@ socket, config, isApp, - pinnedModels, models } from '$lib/stores'; import { onMount, getContext, tick, onDestroy } from 'svelte'; @@ -646,9 +645,9 @@
{/if} - {#if ($pinnedModels ?? []).length > 0} + {#if ($settings?.pinnedModels ?? []).length > 0}
- {#each $pinnedModels as modelId (modelId)} + {#each $settings.pinnedModels as modelId (modelId)} {@const model = $models.find((model) => model.id === modelId)}