mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-09 03:18:18 +00:00
refac
This commit is contained in:
parent
d8131d1091
commit
d364101761
12 changed files with 161 additions and 128 deletions
|
|
@ -695,12 +695,12 @@
|
|||
} else if (type === 'chat:message:favorite') {
|
||||
// Update message favorite status
|
||||
message.favorite = data.favorite;
|
||||
} else if (type === 'chat:title') {
|
||||
chatTitle.set(data);
|
||||
await refreshChatList(localStorage.token);
|
||||
} else if (type === 'chat:tags') {
|
||||
chat = await getChatById(localStorage.token, $chatId);
|
||||
allTags.set(await getAllTags(localStorage.token));
|
||||
} else if (type === 'chat:title') {
|
||||
chatTitle.set(data);
|
||||
await refreshChatList(localStorage.token);
|
||||
} else if (type === 'chat:tags') {
|
||||
chat = await getChatById(localStorage.token, $chatId);
|
||||
allTags.set(await getAllTags(localStorage.token));
|
||||
} else if (type === 'source' || type === 'citation') {
|
||||
if (data?.type === 'code_execution') {
|
||||
// Code execution; update existing code execution by ID, or add new one.
|
||||
|
|
@ -1759,11 +1759,11 @@
|
|||
|
||||
const chatCompletedHandler = async (_chatId, modelId, responseMessageId, messages) => {
|
||||
// Backend handles outlet filters and persistence inline.
|
||||
// Just refresh the sidebar chat list.
|
||||
if ($chatId == _chatId && !$temporaryChatEnabled) {
|
||||
await refreshChatList(localStorage.token);
|
||||
}
|
||||
};
|
||||
// Just refresh the sidebar chat list.
|
||||
if ($chatId == _chatId && !$temporaryChatEnabled) {
|
||||
await refreshChatList(localStorage.token);
|
||||
}
|
||||
};
|
||||
|
||||
const chatActionHandler = async (_chatId, actionId, modelId, responseMessageId, event = null) => {
|
||||
const messages = createMessagesList(history, responseMessageId);
|
||||
|
|
@ -1810,12 +1810,12 @@
|
|||
history: history,
|
||||
params: params,
|
||||
files: chatFiles
|
||||
});
|
||||
});
|
||||
|
||||
await refreshChatList(localStorage.token);
|
||||
}
|
||||
await refreshChatList(localStorage.token);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getChatEventEmitter = async (modelId: string, chatId: string = '') => {
|
||||
return setInterval(() => {
|
||||
|
|
@ -2653,11 +2653,11 @@
|
|||
// and causing spurious toast notifications / state duplication).
|
||||
if (res.chat_id && $chatId !== res.chat_id && $chatId === _chatId) {
|
||||
await chatId.set(res.chat_id);
|
||||
if (!$temporaryChatEnabled) {
|
||||
window.history.replaceState(history.state, '', `/c/${res.chat_id}`);
|
||||
await refreshChatList(localStorage.token);
|
||||
if (!$temporaryChatEnabled) {
|
||||
window.history.replaceState(history.state, '', `/c/${res.chat_id}`);
|
||||
await refreshChatList(localStorage.token);
|
||||
|
||||
// Persist chat-level params (system prompt, advanced
|
||||
// Persist chat-level params (system prompt, advanced
|
||||
// params) that the backend doesn't receive in the
|
||||
// chat completion request. Files are now persisted
|
||||
// by the backend at chat creation time.
|
||||
|
|
@ -2930,14 +2930,14 @@
|
|||
_chatId = chat.id;
|
||||
await chatId.set(_chatId);
|
||||
|
||||
window.history.replaceState(history.state, '', `/c/${_chatId}`);
|
||||
window.history.replaceState(history.state, '', `/c/${_chatId}`);
|
||||
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
await refreshChatList(localStorage.token);
|
||||
await refreshChatList(localStorage.token);
|
||||
|
||||
selectedFolder.set(null);
|
||||
} else {
|
||||
selectedFolder.set(null);
|
||||
} else {
|
||||
_chatId = `local:${$socket?.id}`; // Use socket id for temporary chat
|
||||
await chatId.set(_chatId);
|
||||
}
|
||||
|
|
@ -3012,24 +3012,24 @@
|
|||
}
|
||||
);
|
||||
|
||||
if (res) {
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
if (res) {
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
|
||||
toast.success($i18n.t('Chat moved successfully'));
|
||||
}
|
||||
toast.success($i18n.t('Chat moved successfully'));
|
||||
}
|
||||
} else {
|
||||
toast.error($i18n.t('Failed to move chat'));
|
||||
}
|
||||
};
|
||||
|
||||
const archiveChatHandler = async (id: string) => {
|
||||
try {
|
||||
await archiveChatById(localStorage.token, id);
|
||||
initNewChat();
|
||||
await goto('/');
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
toast.success($i18n.t('Chat archived.'));
|
||||
} catch (error) {
|
||||
const archiveChatHandler = async (id: string) => {
|
||||
try {
|
||||
await archiveChatById(localStorage.token, id);
|
||||
initNewChat();
|
||||
await goto('/');
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
toast.success($i18n.t('Chat archived.'));
|
||||
} catch (error) {
|
||||
console.error('Error archiving chat:', error);
|
||||
toast.error($i18n.t('Failed to archive chat.'));
|
||||
}
|
||||
|
|
@ -3058,13 +3058,13 @@
|
|||
if (!id) return;
|
||||
|
||||
try {
|
||||
const res = await deleteChatById(localStorage.token, id);
|
||||
if (res) {
|
||||
initNewChat();
|
||||
await goto('/');
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
allTags.set(await getAllTags(localStorage.token));
|
||||
toast.success($i18n.t('Chat deleted.'));
|
||||
const res = await deleteChatById(localStorage.token, id);
|
||||
if (res) {
|
||||
initNewChat();
|
||||
await goto('/');
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
allTags.set(await getAllTags(localStorage.token));
|
||||
toast.success($i18n.t('Chat deleted.'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting chat:', error);
|
||||
|
|
@ -3183,7 +3183,6 @@
|
|||
}}
|
||||
{history}
|
||||
title={$chatTitle}
|
||||
bind:selectedModels
|
||||
shareEnabled={!!history.currentId}
|
||||
{initNewChat}
|
||||
scrollToTop={!isNearTop ? scrollToTop : null}
|
||||
|
|
@ -3214,12 +3213,12 @@
|
|||
null
|
||||
);
|
||||
|
||||
if (savedChat) {
|
||||
temporaryChatEnabled.set(false);
|
||||
chatId.set(savedChat.id);
|
||||
await refreshChatList(localStorage.token);
|
||||
if (savedChat) {
|
||||
temporaryChatEnabled.set(false);
|
||||
chatId.set(savedChat.id);
|
||||
await refreshChatList(localStorage.token);
|
||||
|
||||
await goto(`/c/${savedChat.id}`);
|
||||
await goto(`/c/${savedChat.id}`);
|
||||
toast.success($i18n.t('Conversation saved successfully'));
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -3253,7 +3252,7 @@
|
|||
setInputText={(text) => {
|
||||
messageInput?.setText(text);
|
||||
}}
|
||||
{selectedModels}
|
||||
bind:selectedModels
|
||||
{atSelectedModel}
|
||||
{sendMessage}
|
||||
{showMessage}
|
||||
|
|
@ -3282,7 +3281,7 @@
|
|||
bind:this={messageInput}
|
||||
{history}
|
||||
{taskIds}
|
||||
{selectedModels}
|
||||
bind:selectedModels
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
|
|
@ -3365,7 +3364,7 @@
|
|||
<div class="flex items-center h-full">
|
||||
<Placeholder
|
||||
{history}
|
||||
{selectedModels}
|
||||
bind:selectedModels
|
||||
bind:messageInput
|
||||
bind:files
|
||||
bind:prompt
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
>
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model?.id}&lang=${$i18n.language}`}
|
||||
class=" size-[2.7rem] rounded-full border-[1px] border-gray-100 dark:border-none"
|
||||
class=" size-[2.7rem] rounded-full"
|
||||
alt="logo"
|
||||
draggable="false"
|
||||
on:error={(e) => {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
let showValves = getOpen('valves', false);
|
||||
let showSystemPrompt = getOpen('systemPrompt');
|
||||
let showAdvancedParams = getOpen('advancedParams');
|
||||
|
||||
const compactSectionButtonClass =
|
||||
'w-full h-8 px-2.5 rounded-xl text-[13px] font-normal text-gray-600 hover:bg-gray-50/40 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800/40 dark:hover:text-gray-100 transition cursor-pointer select-none';
|
||||
</script>
|
||||
|
||||
<div class=" dark:text-white">
|
||||
|
|
@ -80,8 +83,6 @@
|
|||
{/each}
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
|
||||
{/if}
|
||||
|
||||
{#if $user?.role === 'admin' || ($user?.permissions.chat?.valves ?? true)}
|
||||
|
|
@ -89,14 +90,12 @@
|
|||
bind:open={showValves}
|
||||
onChange={setOpen('valves')}
|
||||
title={$i18n.t('Valves')}
|
||||
buttonClassName="w-full"
|
||||
buttonClassName={compactSectionButtonClass}
|
||||
>
|
||||
<div class="text-sm" slot="content">
|
||||
<div class="px-2 pt-1 text-sm" slot="content">
|
||||
<Valves show={showValves} />
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
|
||||
{/if}
|
||||
|
||||
{#if $user?.role === 'admin' || ($user?.permissions.chat?.system_prompt ?? true)}
|
||||
|
|
@ -104,21 +103,19 @@
|
|||
title={$i18n.t('System Prompt')}
|
||||
bind:open={showSystemPrompt}
|
||||
onChange={setOpen('systemPrompt')}
|
||||
buttonClassName="w-full"
|
||||
buttonClassName={compactSectionButtonClass}
|
||||
>
|
||||
<div class="" slot="content">
|
||||
<div class="px-2 pt-1" slot="content">
|
||||
<textarea
|
||||
bind:value={params.system}
|
||||
class="w-full text-xs outline-hidden resize-vertical {$settings.highContrastMode
|
||||
? 'border-2 border-gray-300 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 p-2.5'
|
||||
: 'py-1.5 bg-transparent'}"
|
||||
rows="4"
|
||||
class="w-full text-sm outline-hidden resize-vertical {$settings.highContrastMode
|
||||
? 'border-2 border-gray-300 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 px-2 py-1.5'
|
||||
: 'py-1 bg-transparent'}"
|
||||
rows="3"
|
||||
placeholder={$i18n.t('Enter system prompt')}
|
||||
/>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
|
||||
{/if}
|
||||
|
||||
{#if $user?.role === 'admin' || ($user?.permissions.chat?.params ?? true)}
|
||||
|
|
@ -126,9 +123,9 @@
|
|||
title={$i18n.t('Advanced Params')}
|
||||
bind:open={showAdvancedParams}
|
||||
onChange={setOpen('advancedParams')}
|
||||
buttonClassName="w-full"
|
||||
buttonClassName={compactSectionButtonClass}
|
||||
>
|
||||
<div class="text-sm mt-1.5" slot="content">
|
||||
<div class="px-2 pt-1 text-sm" slot="content">
|
||||
<div>
|
||||
<AdvancedParams admin={$user?.role === 'admin'} custom={true} bind:params />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@
|
|||
|
||||
{#if show && !loading}
|
||||
<form
|
||||
class="flex flex-col h-full justify-between space-y-3 text-sm"
|
||||
class="flex flex-col h-full justify-between space-y-2 text-xs"
|
||||
on:submit|preventDefault={() => {
|
||||
submitHandler();
|
||||
dispatch('save');
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<div class="flex gap-2">
|
||||
<div class="flex-1">
|
||||
<select
|
||||
class=" w-full rounded-sm text-xs py-2 px-1 bg-transparent outline-hidden"
|
||||
class="w-full h-[1.6875rem] rounded-xl text-xs px-2 bg-transparent outline-hidden"
|
||||
bind:value={tab}
|
||||
placeholder={$i18n.t('Select')}
|
||||
>
|
||||
|
|
@ -161,7 +161,7 @@
|
|||
|
||||
<div class="flex-1">
|
||||
<select
|
||||
class="w-full rounded-sm py-2 px-1 text-xs bg-transparent outline-hidden"
|
||||
class="w-full h-[1.6875rem] rounded-xl px-2 text-xs bg-transparent outline-hidden"
|
||||
bind:value={selectedId}
|
||||
on:change={async () => {
|
||||
await tick();
|
||||
|
|
@ -192,17 +192,17 @@
|
|||
</div>
|
||||
|
||||
{#if selectedId}
|
||||
<hr class="border-gray-50/30 dark:border-gray-800/30 my-1 w-full" />
|
||||
|
||||
<div class="my-2 text-xs">
|
||||
<div class="my-1 text-xs">
|
||||
{#if !loading}
|
||||
<Valves
|
||||
{valvesSpec}
|
||||
bind:valves
|
||||
on:change={() => {
|
||||
debounceSubmitHandler();
|
||||
}}
|
||||
/>
|
||||
<div class="chat-control-valves">
|
||||
<Valves
|
||||
{valvesSpec}
|
||||
bind:valves
|
||||
on:change={() => {
|
||||
debounceSubmitHandler();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<Spinner className="size-5" />
|
||||
{/if}
|
||||
|
|
@ -213,3 +213,12 @@
|
|||
{:else}
|
||||
<Spinner className="size-4" />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.chat-control-valves :global(input),
|
||||
.chat-control-valves :global(select),
|
||||
.chat-control-valves :global(textarea) {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
|
||||
import InputMenu from './MessageInput/InputMenu.svelte';
|
||||
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
||||
import ModelSelector from './ModelSelector.svelte';
|
||||
|
||||
import ToolServersModal from './ToolServersModal.svelte';
|
||||
import SkillsModal from './SkillsModal.svelte';
|
||||
|
|
@ -1997,11 +1998,31 @@
|
|||
</button>
|
||||
</Tooltip>
|
||||
{/each}
|
||||
|
||||
{#if !history?.currentId || history.messages[history.currentId]?.done == true}
|
||||
<!-- Terminal Server Selector -->
|
||||
{@const hasDirectToolServerAccess =
|
||||
$_user?.role === 'admin' ||
|
||||
($_user?.permissions?.features?.direct_tool_servers ?? true)}
|
||||
{#if terminalCapableModels.length > 0 && (($terminalServers ?? []).some((t) => t.id) || (hasDirectToolServerAccess && (($terminalServers ?? []).some((t) => !t.id) || ($settings?.terminalServers ?? []).some((s) => s.url))))}
|
||||
<TerminalMenu bind:show={showTerminalMenu} />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="self-end flex space-x-1 mr-1 shrink-0 gap-[0.5px]">
|
||||
<div class="-mr-1 flex min-w-0 max-w-[10rem] items-center sm:max-w-[13rem]">
|
||||
<ModelSelector
|
||||
bind:selectedModels
|
||||
showSetDefault={!history?.currentId}
|
||||
placement="auto"
|
||||
align="end"
|
||||
triggerClassName="items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] font-normal text-gray-600 transition-colors duration-100 hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-300 dark:hover:bg-gray-800/40 dark:hover:text-gray-200"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if isActive && prompt === '' && files.length === 0}
|
||||
<div class=" flex items-center">
|
||||
<Tooltip content={$i18n.t('Stop')}>
|
||||
|
|
@ -2045,14 +2066,6 @@
|
|||
{/if}
|
||||
|
||||
{#if !history?.currentId || history.messages[history.currentId]?.done == true}
|
||||
<!-- Terminal Server Selector -->
|
||||
{@const hasDirectToolServerAccess =
|
||||
$_user?.role === 'admin' ||
|
||||
($_user?.permissions?.features?.direct_tool_servers ?? true)}
|
||||
{#if terminalCapableModels.length > 0 && (($terminalServers ?? []).some((t) => t.id) || (hasDirectToolServerAccess && (($terminalServers ?? []).some((t) => !t.id) || ($settings?.terminalServers ?? []).some((s) => s.url))))}
|
||||
<TerminalMenu bind:show={showTerminalMenu} />
|
||||
{/if}
|
||||
|
||||
{#if $_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true)}
|
||||
<!-- {$i18n.t('Record voice')} -->
|
||||
<Tooltip content={$i18n.t('Dictate')}>
|
||||
|
|
|
|||
|
|
@ -91,14 +91,14 @@
|
|||
</script>
|
||||
|
||||
<div class="flex items-center translate-x-0.5">
|
||||
<Dropdown bind:show align="end">
|
||||
<Dropdown bind:show align="start">
|
||||
<Tooltip content={$i18n.t('Terminal')} placement="top">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1.5 translate-y-[1px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 text-[13px] transition rounded-lg cursor-pointer {$selectedTerminalId &&
|
||||
class="flex items-center gap-1.5 translate-y-[1px] text-[13px] text-gray-600 hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-300 dark:hover:bg-gray-800/40 dark:hover:text-gray-200 transition rounded-lg cursor-pointer {$selectedTerminalId &&
|
||||
selectedLabel
|
||||
? ' px-2.5 py-1 '
|
||||
: ' p-2 opacity-50'}"
|
||||
? ' p-1 '
|
||||
: ' p-1 opacity-50'}"
|
||||
>
|
||||
<Cloud className="size-3.5" strokeWidth="2" />
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
export let showSetDefault = true;
|
||||
export let triggerClassName = 'text-lg';
|
||||
export let className = undefined;
|
||||
export let placement: 'top' | 'bottom' | 'auto' = 'bottom';
|
||||
export let align: 'start' | 'end' = 'start';
|
||||
|
||||
let compareModels = selectedModels.length > 1;
|
||||
|
||||
|
|
@ -57,10 +59,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full items-start">
|
||||
<div class="flex w-full max-w-fit">
|
||||
<div class="overflow-hidden w-full">
|
||||
<div class="max-w-full {($settings?.highContrastMode ?? false) ? 'm-1' : 'mr-1'}">
|
||||
<div class="flex min-w-0 max-w-full flex-col items-start">
|
||||
<div class="flex min-w-0 max-w-full">
|
||||
<div class="min-w-0 max-w-full overflow-hidden">
|
||||
<div class="min-w-0 max-w-full">
|
||||
<Selector
|
||||
id="model"
|
||||
placeholder={$i18n.t('Select a model')}
|
||||
|
|
@ -72,6 +74,8 @@
|
|||
{pinModelHandler}
|
||||
{className}
|
||||
{triggerClassName}
|
||||
{placement}
|
||||
{align}
|
||||
{showSetDefault}
|
||||
onSetDefault={saveDefaultModel}
|
||||
multipleEnabled={$user?.role === 'admin' ||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@
|
|||
|
||||
export let className = 'w-[22rem]';
|
||||
export let triggerClassName = 'text-lg';
|
||||
export let placement: 'top' | 'bottom' | 'auto' = 'bottom';
|
||||
export let align: 'start' | 'end' = 'start';
|
||||
export let showSetDefault = false;
|
||||
export let onSetDefault: () => Promise<void> | void = () => {};
|
||||
|
||||
|
|
@ -87,20 +89,36 @@
|
|||
const updatePosition = () => {
|
||||
if (!show || !triggerElement) return;
|
||||
const rect = triggerElement.getBoundingClientRect();
|
||||
const contentRect = contentElement?.getBoundingClientRect();
|
||||
const contentWidth = contentRect?.width ?? 0;
|
||||
const contentHeight = contentRect?.height ?? 0;
|
||||
const spaceBelow = window.innerHeight - rect.bottom - 8;
|
||||
const spaceAbove = rect.top - 8;
|
||||
const resolvedPlacement =
|
||||
placement === 'auto'
|
||||
? contentHeight && spaceBelow < contentHeight && spaceAbove > spaceBelow
|
||||
? 'top'
|
||||
: 'bottom'
|
||||
: placement;
|
||||
dropdownPosition = {
|
||||
top: rect.bottom + 2,
|
||||
left: $mobile ? 8 : rect.left,
|
||||
top:
|
||||
resolvedPlacement === 'top' && contentHeight
|
||||
? rect.top - contentHeight - 2
|
||||
: rect.bottom + 2,
|
||||
left: $mobile ? 8 : align === 'end' && contentWidth ? rect.right - contentWidth : rect.left,
|
||||
width: $mobile ? window.innerWidth - 16 : 0
|
||||
};
|
||||
};
|
||||
|
||||
const toggleOpen = () => {
|
||||
const toggleOpen = async () => {
|
||||
show = !show;
|
||||
if (show) {
|
||||
searchValue = '';
|
||||
listScrollTop = 0;
|
||||
resetView();
|
||||
updatePosition();
|
||||
await tick();
|
||||
updatePosition();
|
||||
window.setTimeout(() => document.getElementById('model-search-input')?.focus(), 0);
|
||||
} else {
|
||||
document.getElementById(`model-selector-${id}-button`)?.blur();
|
||||
|
|
@ -609,7 +627,7 @@
|
|||
on:click={toggleOpen}
|
||||
>
|
||||
<div
|
||||
class="flex w-full text-left px-0.5 bg-transparent truncate {triggerClassName} justify-between {($settings?.highContrastMode ??
|
||||
class="flex w-full min-w-0 text-left px-0.5 bg-transparent {triggerClassName} justify-between {($settings?.highContrastMode ??
|
||||
false)
|
||||
? 'dark:placeholder-gray-100 placeholder-gray-800'
|
||||
: 'placeholder-gray-400'}"
|
||||
|
|
@ -622,8 +640,8 @@
|
|||
);
|
||||
}}
|
||||
>
|
||||
{triggerLabel}
|
||||
<ChevronDown className=" self-center ml-2 size-3" strokeWidth="2.5" />
|
||||
<span class="min-w-0 flex-1 truncate">{triggerLabel}</span>
|
||||
<ChevronDown className="ml-1.5 size-2.5 shrink-0 self-center" strokeWidth="2.5" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
import { goto } from '$app/navigation';
|
||||
|
||||
import ShareChatModal from '../chat/ShareChatModal.svelte';
|
||||
import ModelSelector from '../chat/ModelSelector.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';
|
||||
|
|
@ -50,9 +49,7 @@
|
|||
|
||||
export let chat;
|
||||
export let history;
|
||||
export let selectedModels;
|
||||
export let showModelSelector = true;
|
||||
|
||||
export let title = '';
|
||||
export let onSaveTempChat: () => {};
|
||||
export let archiveChatHandler: (id: string) => void;
|
||||
export let deleteChatHandler: (id: string) => void;
|
||||
|
|
@ -117,18 +114,15 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="flex-1 overflow-hidden max-w-full mt-0.5 py-0.5
|
||||
{$showSidebar ? 'ml-1' : ''}
|
||||
"
|
||||
>
|
||||
{#if showModelSelector}
|
||||
<ModelSelector
|
||||
bind:selectedModels
|
||||
showSetDefault={!shareEnabled && !readOnly}
|
||||
disabled={readOnly}
|
||||
triggerClassName="text-[17px]"
|
||||
/>
|
||||
<div class="flex-1 overflow-hidden max-w-full mt-0.5 py-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>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@
|
|||
$selectedFolder != null &&
|
||||
$selectedFolder.user_id !== $user?.id &&
|
||||
$selectedFolder.permission !== 'write';
|
||||
|
||||
</script>
|
||||
|
||||
<div class="m-auto w-full max-w-6xl px-2 @2xl:px-20 translate-y-6 py-24 text-center">
|
||||
|
|
@ -133,7 +132,7 @@
|
|||
>
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model?.id}&lang=${$i18n.language}`}
|
||||
class=" size-9 @sm:size-10 rounded-full border-[1px] border-gray-100 dark:border-none"
|
||||
class=" size-9 @sm:size-10 rounded-full"
|
||||
aria-hidden="true"
|
||||
draggable="false"
|
||||
on:error={(e) => {
|
||||
|
|
@ -219,7 +218,7 @@
|
|||
<MessageInput
|
||||
bind:this={messageInput}
|
||||
{history}
|
||||
{selectedModels}
|
||||
bind:selectedModels
|
||||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@
|
|||
{#if !disabled}
|
||||
<div class="flex self-center translate-y-[1px]">
|
||||
{#if open}
|
||||
<ChevronUp strokeWidth="3.5" className="size-3.5" />
|
||||
<ChevronUp strokeWidth="2.75" className="size-3" />
|
||||
{:else}
|
||||
<ChevronDown strokeWidth="3.5" className="size-3.5" />
|
||||
<ChevronDown strokeWidth="2.75" className="size-3" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -144,9 +144,9 @@
|
|||
{#if chevron}
|
||||
<div class="flex self-start translate-y-1">
|
||||
{#if open}
|
||||
<ChevronUp strokeWidth="3.5" className="size-3.5" />
|
||||
<ChevronUp strokeWidth="2.75" className="size-3" />
|
||||
{:else}
|
||||
<ChevronDown strokeWidth="3.5" className="size-3.5" />
|
||||
<ChevronDown strokeWidth="2.75" className="size-3" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<XMark className="size-3.5" />
|
||||
</button>
|
||||
{:else}
|
||||
<ChevronDown className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronDown className="size-2.5" strokeWidth="2.5" />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue