瀏覽代碼

enh: shift unpin pinned models

Timothy Jaeryang Baek 2 月之前
父節點
當前提交
98f38f00ff

+ 21 - 0
src/lib/components/icons/PinSlash.svelte

@@ -0,0 +1,21 @@
+<script lang="ts">
+	export let className = 'size-4';
+	export let strokeWidth = '1.5';
+</script>
+
+<svg
+	stroke-width={strokeWidth}
+	stroke="currentColor"
+	class={className}
+	aria-hidden="true"
+	xmlns="http://www.w3.org/2000/svg"
+	fill="none"
+	width="24"
+	height="24"
+	viewBox="0 0 22 22"
+	><path d="M9.5 14.5L3 21" stroke-linecap="round" stroke-linejoin="round"></path><path
+		d="M7.67602 7.8896L6.69713 7.78823L5.00007 9.48528L14.1925 18.6777L15.8895 16.9806L15.7879 16M11.4847 7L15.1568 2.67141L21.0065 8.5211L16.6991 12.175"
+		stroke-linecap="round"
+		stroke-linejoin="round"
+	></path><path d="M3 3L21 21" stroke-linecap="round" stroke-linejoin="round"></path></svg
+>

+ 1 - 1
src/lib/components/layout/Sidebar.svelte

@@ -817,7 +817,7 @@
 
 			<div class="relative flex flex-col flex-1">
 				{#if ($models ?? []).length > 0 && ($settings?.pinnedModels ?? []).length > 0}
-					<PinnedModelList bind:selectedChatId />
+					<PinnedModelList bind:selectedChatId {shiftKey} />
 				{/if}
 
 				{#if $config?.features?.enable_channels && ($user?.role === 'admin' || $channels.length > 0)}

+ 71 - 0
src/lib/components/layout/Sidebar/PinnedModelItem.svelte

@@ -0,0 +1,71 @@
+<script lang="ts">
+	import { getContext } from 'svelte';
+
+	const i18n = getContext('i18n');
+
+	import { WEBUI_BASE_URL } from '$lib/constants';
+
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import PinSlash from '$lib/components/icons/PinSlash.svelte';
+
+	export let model = null;
+	export let shiftKey = false;
+	export let onClick = () => {};
+	export let onUnpin = () => {};
+
+	let mouseOver = false;
+</script>
+
+{#if model}
+	<!-- svelte-ignore a11y-no-static-element-interactions -->
+	<div
+		class="px-[7px] flex justify-center text-gray-800 dark:text-gray-200 cursor-grab relative group"
+		data-id={model?.id}
+		on:mouseenter={(e) => {
+			mouseOver = true;
+		}}
+		on:mouseleave={(e) => {
+			mouseOver = false;
+		}}
+	>
+		<a
+			class="grow flex items-center space-x-2.5 rounded-lg px-2 py-[7px] group-hover:bg-gray-100 dark:group-hover:bg-gray-900 transition"
+			href="/?model={model?.id}"
+			on:click={onClick}
+			draggable="false"
+		>
+			<div class="self-center shrink-0">
+				<img
+					crossorigin="anonymous"
+					src={model?.info?.meta?.profile_image_url ?? `${WEBUI_BASE_URL}/static/favicon.png`}
+					class=" size-5 rounded-full -translate-x-[0.5px]"
+					alt="logo"
+				/>
+			</div>
+
+			<div class="flex self-center translate-y-[0.5px]">
+				<div class=" self-center text-sm font-primary line-clamp-1">
+					{model?.name ?? model.id}
+				</div>
+			</div>
+		</a>
+
+		{#if mouseOver && shiftKey}
+			<div class="absolute right-5 top-2.5">
+				<div class=" flex items-center self-center space-x-1.5">
+					<Tooltip content={$i18n.t('Unpin')} className="flex items-center">
+						<button
+							class=" self-center dark:hover:text-white transition"
+							on:click={() => {
+								onUnpin();
+							}}
+							type="button"
+						>
+							<PinSlash className="size-3.5" strokeWidth="2" />
+						</button>
+					</Tooltip>
+				</div>
+			</div>
+		{/if}
+	</div>
+{/if}

+ 18 - 33
src/lib/components/layout/Sidebar/PinnedModelList.svelte

@@ -6,8 +6,10 @@
 	import { chatId, mobile, models, settings, showSidebar } from '$lib/stores';
 	import { WEBUI_BASE_URL } from '$lib/constants';
 	import { updateUserSettings } from '$lib/apis/users';
+	import PinnedModelItem from './PinnedModelItem.svelte';
 
 	export let selectedChatId = null;
+	export let shiftKey = false;
 
 	const initPinnedModelsSortable = () => {
 		const pinnedModelsList = document.getElementById('pinned-models-list');
@@ -40,39 +42,22 @@
 	{#each $settings.pinnedModels as modelId (modelId)}
 		{@const model = $models.find((model) => model.id === modelId)}
 		{#if model}
-			<div
-				class="px-[7px] flex justify-center text-gray-800 dark:text-gray-200 cursor-grab"
-				data-id={modelId}
-			>
-				<a
-					class="grow flex items-center space-x-2.5 rounded-lg px-2 py-[7px] hover:bg-gray-100 dark:hover:bg-gray-900 transition"
-					href="/?model={modelId}"
-					on:click={() => {
-						selectedChatId = null;
-						chatId.set('');
-
-						if ($mobile) {
-							showSidebar.set(false);
-						}
-					}}
-					draggable="false"
-				>
-					<div class="self-center shrink-0">
-						<img
-							crossorigin="anonymous"
-							src={model?.info?.meta?.profile_image_url ?? `${WEBUI_BASE_URL}/static/favicon.png`}
-							class=" size-5 rounded-full -translate-x-[0.5px]"
-							alt="logo"
-						/>
-					</div>
-
-					<div class="flex self-center translate-y-[0.5px]">
-						<div class=" self-center text-sm font-primary line-clamp-1">
-							{model?.name ?? modelId}
-						</div>
-					</div>
-				</a>
-			</div>
+			<PinnedModelItem
+				{model}
+				{shiftKey}
+				onClick={() => {
+					selectedChatId = null;
+					chatId.set('');
+					if ($mobile) {
+						showSidebar.set(false);
+					}
+				}}
+				onUnpin={() => {
+					const pinnedModels = $settings.pinnedModels.filter((id) => id !== modelId);
+					settings.set({ ...$settings, pinnedModels });
+					updateUserSettings(localStorage.token, { ui: $settings });
+				}}
+			/>
 		{/if}
 	{/each}
 </div>