This commit is contained in:
Timothy Jaeryang Baek
2026-07-14 03:10:12 -04:00
parent d364101761
commit d475cb9174
8 changed files with 97 additions and 120 deletions
+69 -102
View File
@@ -9,7 +9,6 @@
config,
mobile,
settings,
showArchivedChats,
showControls,
showSidebar,
temporaryChatEnabled,
@@ -23,7 +22,6 @@
import ShareChatModal from '../chat/ShareChatModal.svelte';
import Tooltip from '../common/Tooltip.svelte';
import Menu from '$lib/components/layout/Navbar/Menu.svelte';
import UserMenu from '$lib/components/layout/Sidebar/UserMenu.svelte';
import AdjustmentsHorizontal from '../icons/AdjustmentsHorizontal.svelte';
import PencilSquare from '../icons/PencilSquare.svelte';
@@ -37,7 +35,6 @@
import ChatPlus from '../icons/ChatPlus.svelte';
import ChatCheck from '../icons/ChatCheck.svelte';
import Knobs from '../icons/Knobs.svelte';
import { WEBUI_API_BASE_URL } from '$lib/constants';
const i18n = getContext('i18n');
@@ -80,11 +77,7 @@
aria-label="New Chat"
/>
<nav
class="sticky top-0 z-30 w-full {chat?.id
? 'pt-0.5 pb-1'
: 'pt-1 pb-1'} -mb-12 flex flex-col items-center drag-region"
>
<nav class="sticky top-0 z-30 w-full pt-0.5 pb-1 -mb-12 flex flex-col items-center drag-region">
<div class="flex items-center w-full pl-1.5 pr-1">
<div
id="navbar-bg-gradient-to-b"
@@ -93,47 +86,83 @@
: 'invisible'} bg-linear-to-b via-40% to-97% from-white/90 via-white/50 to-transparent dark:from-gray-900/90 dark:via-gray-900/50 dark:to-transparent pointer-events-none absolute inset-0 -bottom-10 z-[-1]"
></div>
<div class=" flex max-w-full w-full mx-auto px-1.5 md:px-2 bg-transparent">
<div class=" flex max-w-full w-full mx-auto bg-transparent">
<div class="flex items-center w-full max-w-full">
{#if $mobile && !$showSidebar}
<div
class="-translate-x-0.5 mr-1 mt-1 self-start flex flex-none items-center text-gray-600 dark:text-gray-400"
>
<div class="-translate-x-0.5 mr-1 mt-1 self-start flex flex-none items-center">
<Tooltip content={$showSidebar ? $i18n.t('Close Sidebar') : $i18n.t('Open Sidebar')}>
<button
class=" cursor-pointer flex rounded-lg hover:bg-gray-100 dark:hover:bg-gray-850 transition"
class="flex size-6 cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
on:click={() => {
showSidebar.set(!$showSidebar);
}}
aria-label={$showSidebar ? $i18n.t('Close Sidebar') : $i18n.t('Open Sidebar')}
>
<div class=" self-center p-1.5">
<Sidebar />
</div>
<Sidebar />
</button>
</Tooltip>
</div>
{/if}
<div class="flex-1 overflow-hidden max-w-full mt-0.5 py-0.5 {$showSidebar ? 'ml-1' : ''}">
<div
class="flex-1 overflow-hidden max-w-full mt-0.5 py-0.5 pl-0.5 {$showSidebar
? 'ml-1'
: ''}"
>
{#if chat?.id}
<button
type="button"
class="max-w-full truncate rounded-lg px-2 py-1 text-left text-[13px] font-medium text-gray-700 transition-colors duration-100 hover:bg-gray-50/40 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800/40 dark:hover:text-gray-100"
on:click={() => scrollToTop?.()}
>
{title || chat?.chat?.title || $i18n.t('New Chat')}
</button>
<div class="flex max-w-full min-w-0 items-center gap-2">
<div
class="min-w-0 truncate py-1 text-left text-[15px] font-normal text-gray-700 dark:text-gray-300"
>
{title || chat?.chat?.title || $i18n.t('New Chat')}
</div>
{#if shareEnabled && chat && (chat.id || $temporaryChatEnabled)}
<Menu
{chat}
{shareEnabled}
{readOnly}
{scrollToTop}
shareHandler={() => {
showShareChatModal = !showShareChatModal;
}}
archiveChatHandler={() => {
archiveChatHandler(chat.id);
}}
deleteChatHandler={() => {
deleteChatHandler(chat.id);
}}
{moveChatHandler}
>
<button
class="flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
id="chat-context-menu-button"
aria-label={$i18n.t('Chat actions')}
>
<EllipsisHorizontal className="size-4.5" strokeWidth="1.5" />
</button>
</Menu>
{/if}
</div>
{:else}
<div class="pointer-events-none invisible flex max-w-full min-w-0 items-center gap-2">
<div
class="min-w-0 truncate py-1 text-left text-[15px] font-normal text-gray-700 dark:text-gray-300"
>
{$i18n.t('New Chat')}
</div>
</div>
{/if}
</div>
<div class="self-start flex flex-none items-center text-gray-600 dark:text-gray-400">
<div class="mr-1 flex flex-none items-center gap-2 self-center">
<!-- <div class="md:hidden flex self-center w-[1px] h-5 mx-2 bg-gray-300 dark:bg-stone-700" /> -->
{#if $user?.role === 'user' ? ($user?.permissions?.chat?.temporary ?? true) && !($user?.permissions?.chat?.temporary_enforced ?? false) : true}
{#if !chat?.id}
<Tooltip content={$i18n.t(`Temporary Chat`)}>
<button
class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
class="flex size-6 cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
id="temporary-chat-button"
on:click={async () => {
if (($settings?.temporaryChatByDefault ?? false) && $temporaryChatEnabled) {
@@ -154,28 +183,26 @@
window.history.replaceState(null, '', location.pathname);
}
}}
aria-label={$i18n.t(`Temporary Chat`)}
>
<div class=" m-auto self-center">
{#if $temporaryChatEnabled}
<ChatBubbleDottedChecked className=" size-4.5" strokeWidth="1.5" />
{:else}
<ChatBubbleDotted className=" size-4.5" strokeWidth="1.5" />
{/if}
</div>
{#if $temporaryChatEnabled}
<ChatBubbleDottedChecked className="size-4.5" strokeWidth="1.5" />
{:else}
<ChatBubbleDotted className="size-4.5" strokeWidth="1.5" />
{/if}
</button>
</Tooltip>
{:else if $temporaryChatEnabled}
<Tooltip content={$i18n.t(`Save Chat`)}>
<button
class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
class="flex size-6 cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
id="save-temporary-chat-button"
on:click={async () => {
onSaveTempChat();
}}
aria-label={$i18n.t(`Save Chat`)}
>
<div class=" m-auto self-center">
<ChatCheck className=" size-4.5" strokeWidth="1.5" />
</div>
<ChatCheck className="size-4.5" strokeWidth="1.5" />
</button>
</Tooltip>
{/if}
@@ -184,92 +211,32 @@
{#if $mobile && !$temporaryChatEnabled && chat && chat.id}
<Tooltip content={$i18n.t('New Chat')}>
<button
class=" flex {$showSidebar
class="flex size-6 {$showSidebar
? 'md:hidden'
: ''} cursor-pointer px-2 py-2 rounded-xl text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-850 transition"
: ''} cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
on:click={() => {
initNewChat();
}}
aria-label="New Chat"
>
<div class=" m-auto self-center">
<ChatPlus className=" size-4.5" strokeWidth="1.5" />
</div>
<ChatPlus className="size-4.5" strokeWidth="1.5" />
</button>
</Tooltip>
{/if}
{#if shareEnabled && chat && (chat.id || $temporaryChatEnabled)}
<Menu
{chat}
{shareEnabled}
{readOnly}
{scrollToTop}
shareHandler={() => {
showShareChatModal = !showShareChatModal;
}}
archiveChatHandler={() => {
archiveChatHandler(chat.id);
}}
deleteChatHandler={() => {
deleteChatHandler(chat.id);
}}
{moveChatHandler}
>
<button
class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
id="chat-context-menu-button"
>
<div class=" m-auto self-center">
<EllipsisHorizontal className=" size-5" strokeWidth="1.5" />
</div>
</button>
</Menu>
{/if}
{#if $user?.role === 'admin' || ($user?.permissions.chat?.controls ?? true)}
<Tooltip content={$i18n.t('Controls')}>
<button
class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
class="flex size-6 cursor-pointer items-center justify-center rounded-lg text-gray-500 transition hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
on:click={async () => {
await showControls.set(!$showControls);
}}
aria-label="Controls"
>
<div class=" m-auto self-center">
<Knobs className=" size-5" strokeWidth="1" />
</div>
<Knobs className="size-5" strokeWidth="1" />
</button>
</Tooltip>
{/if}
{#if $user !== undefined && $user !== null}
<UserMenu
className="w-[240px]"
role={$user?.role}
help={true}
on:show={(e) => {
if (e.detail === 'archived-chat') {
showArchivedChats.set(true);
}
}}
>
<button
type="button"
class="select-none flex rounded-xl p-1.5 w-full hover:bg-gray-50 dark:hover:bg-gray-850 transition"
aria-label={$i18n.t('User menu')}
>
<div class=" self-center">
<img
src={`${WEBUI_API_BASE_URL}/users/${$user?.id}/profile/image`}
class="size-6 object-cover rounded-full"
alt=""
draggable="false"
/>
</div>
</button>
</UserMenu>
{/if}
</div>
</div>
</div>