mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-13 12:55:19 +00:00
refac: folders
This commit is contained in:
parent
3f27d9ada1
commit
3ec1efb6e0
6 changed files with 138 additions and 131 deletions
|
|
@ -432,15 +432,17 @@
|
|||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
class="sticky {stickyButtonsClassName} left-0 right-0 py-2 pr-3 flex items-center justify-between w-full z-10 text-xs text-black dark:text-white"
|
||||
class="absolute left-0 right-0 py-2.5 pr-3 text-text-300 pl-4.5 text-xs font-medium dark:text-white"
|
||||
>
|
||||
<div class="text-text-300 pl-4.5 text-xs font-medium dark:text-white">
|
||||
{lang}
|
||||
</div>
|
||||
{lang}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="sticky {stickyButtonsClassName} left-0 right-0 py-2 pr-3 flex items-center justify-end w-full z-10 text-xs text-black dark:text-white"
|
||||
>
|
||||
<div class="flex items-center gap-0.5">
|
||||
<button
|
||||
class="flex gap-1 items-center bg-none border-none transition rounded-md px-1.5 py-0.5"
|
||||
class="flex gap-1 items-center bg-none border-none transition rounded-md px-1.5 py-0.5 bg-white dark:bg-black"
|
||||
on:click={collapseCodeBlock}
|
||||
>
|
||||
<div class=" -translate-y-[0.5px]">
|
||||
|
|
@ -454,12 +456,14 @@
|
|||
|
||||
{#if ($config?.features?.enable_code_execution ?? true) && (lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code)))}
|
||||
{#if executing}
|
||||
<div class="run-code-button bg-none border-none p-0.5 cursor-not-allowed">
|
||||
<div
|
||||
class="run-code-button bg-none border-none p-0.5 cursor-not-allowed bg-white dark:bg-black"
|
||||
>
|
||||
{$i18n.t('Running')}
|
||||
</div>
|
||||
{:else if run}
|
||||
<button
|
||||
class="flex gap-1 items-center run-code-button bg-none border-none transition rounded-md px-1.5 py-0.5"
|
||||
class="flex gap-1 items-center run-code-button bg-none border-none transition rounded-md px-1.5 py-0.5 bg-white dark:bg-black"
|
||||
on:click={async () => {
|
||||
code = _code;
|
||||
await tick();
|
||||
|
|
@ -475,7 +479,7 @@
|
|||
|
||||
{#if save}
|
||||
<button
|
||||
class="save-code-button bg-none border-none transition rounded-md px-1.5 py-0.5"
|
||||
class="save-code-button bg-none border-none transition rounded-md px-1.5 py-0.5 bg-white dark:bg-black"
|
||||
on:click={saveCode}
|
||||
>
|
||||
{saved ? $i18n.t('Saved') : $i18n.t('Save')}
|
||||
|
|
@ -483,13 +487,13 @@
|
|||
{/if}
|
||||
|
||||
<button
|
||||
class="copy-code-button bg-none border-none transition rounded-md px-1.5 py-0.5"
|
||||
class="copy-code-button bg-none border-none transition rounded-md px-1.5 py-0.5 bg-white dark:bg-black"
|
||||
on:click={copyCode}>{copied ? $i18n.t('Copied') : $i18n.t('Copy')}</button
|
||||
>
|
||||
|
||||
{#if preview && ['html', 'svg'].includes(lang)}
|
||||
<button
|
||||
class="flex gap-1 items-center run-code-button bg-none border-none transition rounded-md px-1.5 py-0.5"
|
||||
class="flex gap-1 items-center run-code-button bg-none border-none transition rounded-md px-1.5 py-0.5 bg-white dark:bg-black"
|
||||
on:click={previewCode}
|
||||
>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@
|
|||
{save}
|
||||
{preview}
|
||||
edit={editCodeBlock}
|
||||
stickyButtonsClassName={topPadding ? 'top-6' : 'top-0'}
|
||||
stickyButtonsClassName={topPadding ? 'top-7' : 'top-0'}
|
||||
onSave={(value) => {
|
||||
onSave({
|
||||
raw: token.raw,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
<nav class="sticky top-0 z-30 w-full py-1 -mb-8 flex flex-col items-center drag-region">
|
||||
<div class="flex items-center w-full pl-1.5 pr-1">
|
||||
<div
|
||||
class=" bg-linear-to-b via-40% from-white via-white to-transparent dark:from-gray-900 dark:via-gray-900 dark:to-transparent pointer-events-none absolute inset-0 -bottom-7 z-[-1]"
|
||||
class=" bg-linear-to-b via-40% to-97% from-white via-white to-transparent dark:from-gray-900 dark:via-gray-900 dark:to-transparent pointer-events-none absolute inset-0 -bottom-7 z-[-1]"
|
||||
></div>
|
||||
|
||||
<div class=" flex max-w-full w-full mx-auto px-1.5 md:px-2 pt-0.5 bg-transparent">
|
||||
|
|
|
|||
|
|
@ -16,14 +16,15 @@
|
|||
export let name = '';
|
||||
export let collapsible = true;
|
||||
|
||||
export let className = '';
|
||||
export let buttonClassName = 'text-gray-600 dark:text-gray-400';
|
||||
|
||||
export let chevron = true;
|
||||
export let onAddLabel: string = '';
|
||||
export let onAdd: null | Function = null;
|
||||
|
||||
export let dragAndDrop = true;
|
||||
|
||||
export let className = '';
|
||||
|
||||
let folderElement;
|
||||
|
||||
let draggedOver = false;
|
||||
|
|
@ -138,20 +139,20 @@
|
|||
>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="w-full group rounded-lg relative flex items-center justify-between hover:bg-gray-100 dark:hover:bg-gray-900 text-gray-500 dark:text-gray-500 transition"
|
||||
class="w-full group rounded-lg relative flex items-center justify-between hover:bg-gray-100 dark:hover:bg-gray-900 transition {buttonClassName}"
|
||||
>
|
||||
<button class="w-full py-1.5 pl-2 flex items-center gap-1.5 text-xs font-medium">
|
||||
{#if chevron}
|
||||
<div class="text-gray-300 dark:text-gray-600 p-[1px]">
|
||||
<div class=" p-[1px]">
|
||||
{#if open}
|
||||
<ChevronDown className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronDown className=" size-3" strokeWidth="2" />
|
||||
{:else}
|
||||
<ChevronRight className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronRight className=" size-3" strokeWidth="2" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="translate-y-[0.5px]">
|
||||
<div class="translate-y-[0.5px] {chevron ? '' : 'pl-1'}">
|
||||
{name}
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -871,14 +871,42 @@
|
|||
</Folder>
|
||||
{/if}
|
||||
|
||||
{#if folders}
|
||||
<Folder
|
||||
className="px-2 mt-0.5"
|
||||
name={$i18n.t('Folders')}
|
||||
chevron={false}
|
||||
dragAndDrop={false}
|
||||
onAdd={() => {
|
||||
showCreateFolderModal = true;
|
||||
}}
|
||||
onAddLabel={$i18n.t('New Folder')}
|
||||
>
|
||||
<Folders
|
||||
{folders}
|
||||
{shiftKey}
|
||||
onDelete={(folderId) => {
|
||||
selectedFolder.set(null);
|
||||
initChatList();
|
||||
}}
|
||||
on:update={() => {
|
||||
initChatList();
|
||||
}}
|
||||
on:import={(e) => {
|
||||
const { folderId, items } = e.detail;
|
||||
importChatHandler(items, false, folderId);
|
||||
}}
|
||||
on:change={async () => {
|
||||
initChatList();
|
||||
}}
|
||||
/>
|
||||
</Folder>
|
||||
{/if}
|
||||
|
||||
<Folder
|
||||
className="px-2 mt-0.5"
|
||||
name={$i18n.t('Chats')}
|
||||
chevron={false}
|
||||
onAdd={() => {
|
||||
showCreateFolderModal = true;
|
||||
}}
|
||||
onAddLabel={$i18n.t('New Folder')}
|
||||
on:change={async (e) => {
|
||||
selectedFolder.set(null);
|
||||
await goto('/');
|
||||
|
|
@ -940,115 +968,89 @@
|
|||
}
|
||||
}}
|
||||
>
|
||||
{#if folders || $pinnedChats.length > 0}
|
||||
{#if $pinnedChats.length > 0}
|
||||
<div class="mb-1">
|
||||
{#if folders}
|
||||
<Folders
|
||||
{folders}
|
||||
{shiftKey}
|
||||
onDelete={(folderId) => {
|
||||
selectedFolder.set(null);
|
||||
initChatList();
|
||||
}}
|
||||
on:update={() => {
|
||||
initChatList();
|
||||
<div class="flex flex-col space-y-1 rounded-xl">
|
||||
<Folder
|
||||
buttonClassName=" text-gray-500"
|
||||
bind:open={showPinnedChat}
|
||||
on:change={(e) => {
|
||||
localStorage.setItem('showPinnedChat', e.detail);
|
||||
console.log(e.detail);
|
||||
}}
|
||||
on:import={(e) => {
|
||||
const { folderId, items } = e.detail;
|
||||
importChatHandler(items, false, folderId);
|
||||
importChatHandler(e.detail, true);
|
||||
}}
|
||||
on:change={async () => {
|
||||
initChatList();
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
on:drop={async (e) => {
|
||||
const { type, id, item } = e.detail;
|
||||
|
||||
{#if $pinnedChats.length > 0}
|
||||
<div class="flex flex-col space-y-1 rounded-xl">
|
||||
<Folder
|
||||
className=""
|
||||
bind:open={showPinnedChat}
|
||||
on:change={(e) => {
|
||||
localStorage.setItem('showPinnedChat', e.detail);
|
||||
console.log(e.detail);
|
||||
}}
|
||||
on:import={(e) => {
|
||||
importChatHandler(e.detail, true);
|
||||
}}
|
||||
on:drop={async (e) => {
|
||||
const { type, id, item } = e.detail;
|
||||
|
||||
if (type === 'chat') {
|
||||
let chat = await getChatById(localStorage.token, id).catch((error) => {
|
||||
return null;
|
||||
});
|
||||
if (!chat && item) {
|
||||
chat = await importChat(
|
||||
localStorage.token,
|
||||
item.chat,
|
||||
item?.meta ?? {},
|
||||
false,
|
||||
null,
|
||||
item?.created_at ?? null,
|
||||
item?.updated_at ?? null
|
||||
);
|
||||
}
|
||||
|
||||
if (chat) {
|
||||
console.log(chat);
|
||||
if (chat.folder_id) {
|
||||
const res = await updateChatFolderIdById(
|
||||
localStorage.token,
|
||||
chat.id,
|
||||
null
|
||||
).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
if (!chat.pinned) {
|
||||
const res = await toggleChatPinnedStatusById(
|
||||
localStorage.token,
|
||||
chat.id
|
||||
);
|
||||
}
|
||||
|
||||
initChatList();
|
||||
}
|
||||
if (type === 'chat') {
|
||||
let chat = await getChatById(localStorage.token, id).catch((error) => {
|
||||
return null;
|
||||
});
|
||||
if (!chat && item) {
|
||||
chat = await importChat(
|
||||
localStorage.token,
|
||||
item.chat,
|
||||
item?.meta ?? {},
|
||||
false,
|
||||
null,
|
||||
item?.created_at ?? null,
|
||||
item?.updated_at ?? null
|
||||
);
|
||||
}
|
||||
}}
|
||||
name={$i18n.t('Pinned')}
|
||||
|
||||
if (chat) {
|
||||
console.log(chat);
|
||||
if (chat.folder_id) {
|
||||
const res = await updateChatFolderIdById(
|
||||
localStorage.token,
|
||||
chat.id,
|
||||
null
|
||||
).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
if (!chat.pinned) {
|
||||
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
|
||||
}
|
||||
|
||||
initChatList();
|
||||
}
|
||||
}
|
||||
}}
|
||||
name={$i18n.t('Pinned')}
|
||||
>
|
||||
<div
|
||||
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900 text-gray-900 dark:text-gray-200"
|
||||
>
|
||||
<div
|
||||
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900"
|
||||
>
|
||||
{#each $pinnedChats as chat, idx (`pinned-chat-${chat?.id ?? idx}`)}
|
||||
<ChatItem
|
||||
className=""
|
||||
id={chat.id}
|
||||
title={chat.title}
|
||||
{shiftKey}
|
||||
selected={selectedChatId === chat.id}
|
||||
on:select={() => {
|
||||
selectedChatId = chat.id;
|
||||
}}
|
||||
on:unselect={() => {
|
||||
selectedChatId = null;
|
||||
}}
|
||||
on:change={async () => {
|
||||
initChatList();
|
||||
}}
|
||||
on:tag={(e) => {
|
||||
const { type, name } = e.detail;
|
||||
tagEventHandler(type, name, chat.id);
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</Folder>
|
||||
</div>
|
||||
{/if}
|
||||
{#each $pinnedChats as chat, idx (`pinned-chat-${chat?.id ?? idx}`)}
|
||||
<ChatItem
|
||||
className=""
|
||||
id={chat.id}
|
||||
title={chat.title}
|
||||
{shiftKey}
|
||||
selected={selectedChatId === chat.id}
|
||||
on:select={() => {
|
||||
selectedChatId = chat.id;
|
||||
}}
|
||||
on:unselect={() => {
|
||||
selectedChatId = null;
|
||||
}}
|
||||
on:change={async () => {
|
||||
initChatList();
|
||||
}}
|
||||
on:tag={(e) => {
|
||||
const { type, name } = e.detail;
|
||||
tagEventHandler(type, name, chat.id);
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</Folder>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@
|
|||
}}
|
||||
>
|
||||
<button
|
||||
class="text-gray-500 dark:text-gray-500 transition-all p-[3px] hover:bg-gray-200 dark:hover:bg-gray-850 rounded-lg"
|
||||
class="text-gray-500 dark:text-gray-500 transition-all p-1 hover:bg-gray-200 dark:hover:bg-gray-850 rounded-lg"
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
open = !open;
|
||||
|
|
@ -472,22 +472,22 @@
|
|||
>
|
||||
{#if folders[folderId]?.meta?.icon}
|
||||
<div class="flex group-hover:hidden transition-all">
|
||||
<Emoji className="size-4" shortCode={folders[folderId].meta.icon} />
|
||||
<Emoji className="size-3.5" shortCode={folders[folderId].meta.icon} />
|
||||
</div>
|
||||
|
||||
<div class="hidden group-hover:flex transition-all p-[1px]">
|
||||
{#if open}
|
||||
<ChevronDown className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronDown className=" size-3" strokeWidth="2.5" />
|
||||
{:else}
|
||||
<ChevronRight className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronRight className=" size-3" strokeWidth="2.5" />
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="p-[1px]">
|
||||
{#if open}
|
||||
<ChevronDown className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronDown className=" size-3" strokeWidth="2.5" />
|
||||
{:else}
|
||||
<ChevronRight className=" size-3.5" strokeWidth="2.5" />
|
||||
<ChevronRight className=" size-3" strokeWidth="2.5" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
Loading…
Reference in a new issue