|
@@ -28,34 +28,18 @@
|
|
import { toast } from 'svelte-sonner';
|
|
import { toast } from 'svelte-sonner';
|
|
import { fade, slide } from 'svelte/transition';
|
|
import { fade, slide } from 'svelte/transition';
|
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
|
- import Tooltip from '../common/Tooltip.svelte';
|
|
|
|
- import ChatMenu from './Sidebar/ChatMenu.svelte';
|
|
|
|
- import ShareChatModal from '../chat/ShareChatModal.svelte';
|
|
|
|
- import ArchiveBox from '../icons/ArchiveBox.svelte';
|
|
|
|
import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
|
|
import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
|
|
import UserMenu from './Sidebar/UserMenu.svelte';
|
|
import UserMenu from './Sidebar/UserMenu.svelte';
|
|
import { updateUserSettings } from '$lib/apis/users';
|
|
import { updateUserSettings } from '$lib/apis/users';
|
|
|
|
+ import ChatItem from './Sidebar/ChatItem.svelte';
|
|
|
|
|
|
const BREAKPOINT = 768;
|
|
const BREAKPOINT = 768;
|
|
|
|
|
|
- let show = false;
|
|
|
|
let navElement;
|
|
let navElement;
|
|
-
|
|
|
|
- let title: string = 'UI';
|
|
|
|
let search = '';
|
|
let search = '';
|
|
|
|
|
|
- let shareChatId = null;
|
|
|
|
-
|
|
|
|
let selectedChatId = null;
|
|
let selectedChatId = null;
|
|
-
|
|
|
|
- let chatDeleteId = null;
|
|
|
|
- let chatTitleEditId = null;
|
|
|
|
- let chatTitle = '';
|
|
|
|
-
|
|
|
|
- let showShareChatModal = false;
|
|
|
|
let showDropdown = false;
|
|
let showDropdown = false;
|
|
- let isEditing = false;
|
|
|
|
-
|
|
|
|
let filteredChatList = [];
|
|
let filteredChatList = [];
|
|
|
|
|
|
$: filteredChatList = $chats.filter((chat) => {
|
|
$: filteredChatList = $chats.filter((chat) => {
|
|
@@ -78,13 +62,6 @@
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
- mobile;
|
|
|
|
- const onResize = () => {
|
|
|
|
- if ($showSidebar && window.innerWidth < BREAKPOINT) {
|
|
|
|
- showSidebar.set(false);
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
onMount(async () => {
|
|
onMount(async () => {
|
|
mobile.subscribe((e) => {
|
|
mobile.subscribe((e) => {
|
|
if ($showSidebar && e) {
|
|
if ($showSidebar && e) {
|
|
@@ -149,69 +126,13 @@
|
|
await chats.set(enrichedChats);
|
|
await chats.set(enrichedChats);
|
|
};
|
|
};
|
|
|
|
|
|
- const loadChat = async (id) => {
|
|
|
|
- goto(`/c/${id}`);
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const editChatTitle = async (id, _title) => {
|
|
|
|
- if (_title === '') {
|
|
|
|
- toast.error($i18n.t('Title cannot be an empty string.'));
|
|
|
|
- } else {
|
|
|
|
- title = _title;
|
|
|
|
-
|
|
|
|
- await updateChatById(localStorage.token, id, {
|
|
|
|
- title: _title
|
|
|
|
- });
|
|
|
|
- await chats.set(await getChatList(localStorage.token));
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const deleteChat = async (id) => {
|
|
|
|
- const res = await deleteChatById(localStorage.token, id).catch((error) => {
|
|
|
|
- toast.error(error);
|
|
|
|
- chatDeleteId = null;
|
|
|
|
-
|
|
|
|
- return null;
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- if (res) {
|
|
|
|
- if ($chatId === id) {
|
|
|
|
- goto('/');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- await chats.set(await getChatList(localStorage.token));
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const cloneChatHandler = async (id) => {
|
|
|
|
- const res = await cloneChatById(localStorage.token, id).catch((error) => {
|
|
|
|
- toast.error(error);
|
|
|
|
- return null;
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- if (res) {
|
|
|
|
- goto(`/c/${res.id}`);
|
|
|
|
- await chats.set(await getChatList(localStorage.token));
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
const saveSettings = async (updated) => {
|
|
const saveSettings = async (updated) => {
|
|
await settings.set({ ...$settings, ...updated });
|
|
await settings.set({ ...$settings, ...updated });
|
|
await updateUserSettings(localStorage.token, { ui: $settings });
|
|
await updateUserSettings(localStorage.token, { ui: $settings });
|
|
location.href = '/';
|
|
location.href = '/';
|
|
};
|
|
};
|
|
-
|
|
|
|
- const archiveChatHandler = async (id) => {
|
|
|
|
- await archiveChatById(localStorage.token, id);
|
|
|
|
- await chats.set(await getChatList(localStorage.token));
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const focusEdit = async (node: HTMLInputElement) => {
|
|
|
|
- node.focus();
|
|
|
|
- };
|
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
-<ShareChatModal bind:show={showShareChatModal} chatId={shareChatId} />
|
|
|
|
<ArchivedChatsModal
|
|
<ArchivedChatsModal
|
|
bind:show={$showArchivedChats}
|
|
bind:show={$showArchivedChats}
|
|
on:change={async () => {
|
|
on:change={async () => {
|
|
@@ -252,12 +173,10 @@
|
|
draggable="false"
|
|
draggable="false"
|
|
on:click={async () => {
|
|
on:click={async () => {
|
|
selectedChatId = null;
|
|
selectedChatId = null;
|
|
-
|
|
|
|
await goto('/');
|
|
await goto('/');
|
|
const newChatButton = document.getElementById('new-chat-button');
|
|
const newChatButton = document.getElementById('new-chat-button');
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
newChatButton?.click();
|
|
newChatButton?.click();
|
|
-
|
|
|
|
if ($mobile) {
|
|
if ($mobile) {
|
|
showSidebar.set(false);
|
|
showSidebar.set(false);
|
|
}
|
|
}
|
|
@@ -486,215 +405,13 @@
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
{/if}
|
|
|
|
|
|
- <div class=" w-full pr-2 relative group">
|
|
|
|
- {#if chatTitleEditId === chat.id}
|
|
|
|
- <div
|
|
|
|
- class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId ||
|
|
|
|
- chat.id === chatTitleEditId ||
|
|
|
|
- chat.id === chatDeleteId
|
|
|
|
- ? 'bg-gray-200 dark:bg-gray-900'
|
|
|
|
- : chat.id === selectedChatId
|
|
|
|
- ? 'bg-gray-100 dark:bg-gray-950'
|
|
|
|
- : 'group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis"
|
|
|
|
- >
|
|
|
|
- <input
|
|
|
|
- use:focusEdit
|
|
|
|
- bind:value={chatTitle}
|
|
|
|
- class=" bg-transparent w-full outline-none mr-10"
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
- {:else}
|
|
|
|
- <a
|
|
|
|
- class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId ||
|
|
|
|
- chat.id === chatTitleEditId ||
|
|
|
|
- chat.id === chatDeleteId
|
|
|
|
- ? 'bg-gray-200 dark:bg-gray-900'
|
|
|
|
- : chat.id === selectedChatId
|
|
|
|
- ? 'bg-gray-100 dark:bg-gray-950'
|
|
|
|
- : ' group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis"
|
|
|
|
- href="/c/{chat.id}"
|
|
|
|
- on:click={() => {
|
|
|
|
- selectedChatId = chat.id;
|
|
|
|
- if ($mobile) {
|
|
|
|
- showSidebar.set(false);
|
|
|
|
- }
|
|
|
|
- }}
|
|
|
|
- on:dblclick={() => {
|
|
|
|
- chatTitle = chat.title;
|
|
|
|
- chatTitleEditId = chat.id;
|
|
|
|
- }}
|
|
|
|
- draggable="false"
|
|
|
|
- >
|
|
|
|
- <div class=" flex self-center flex-1 w-full">
|
|
|
|
- <div class=" text-left self-center overflow-hidden w-full h-[20px]">
|
|
|
|
- {chat.title}
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </a>
|
|
|
|
- {/if}
|
|
|
|
-
|
|
|
|
- <div
|
|
|
|
- class="
|
|
|
|
-
|
|
|
|
- {chat.id === $chatId || chat.id === chatTitleEditId || chat.id === chatDeleteId
|
|
|
|
- ? 'from-gray-200 dark:from-gray-900'
|
|
|
|
- : chat.id === selectedChatId
|
|
|
|
- ? 'from-gray-100 dark:from-gray-950'
|
|
|
|
- : 'invisible group-hover:visible from-gray-100 dark:from-gray-950'}
|
|
|
|
- absolute right-[10px] top-[10px] pr-2 pl-5 bg-gradient-to-l from-80%
|
|
|
|
-
|
|
|
|
- to-transparent"
|
|
|
|
- >
|
|
|
|
- {#if chatTitleEditId === chat.id}
|
|
|
|
- <div class="flex self-center space-x-1.5 z-10">
|
|
|
|
- <button
|
|
|
|
- class=" self-center dark:hover:text-white transition"
|
|
|
|
- on:click={() => {
|
|
|
|
- editChatTitle(chat.id, chatTitle);
|
|
|
|
- chatTitleEditId = null;
|
|
|
|
- chatTitle = '';
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 20 20"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- fill-rule="evenodd"
|
|
|
|
- d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
|
|
|
|
- clip-rule="evenodd"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- <button
|
|
|
|
- class=" self-center dark:hover:text-white transition"
|
|
|
|
- on:click={() => {
|
|
|
|
- chatTitleEditId = null;
|
|
|
|
- chatTitle = '';
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 20 20"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- </div>
|
|
|
|
- {:else if chatDeleteId === chat.id}
|
|
|
|
- <div class="flex self-center space-x-1.5 z-10">
|
|
|
|
- <button
|
|
|
|
- class=" self-center dark:hover:text-white transition"
|
|
|
|
- on:click={() => {
|
|
|
|
- deleteChat(chat.id);
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 20 20"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- fill-rule="evenodd"
|
|
|
|
- d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
|
|
|
|
- clip-rule="evenodd"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- <button
|
|
|
|
- class=" self-center dark:hover:text-white transition"
|
|
|
|
- on:click={() => {
|
|
|
|
- chatDeleteId = null;
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 20 20"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- </div>
|
|
|
|
- {:else}
|
|
|
|
- <div class="flex self-center space-x-1 z-10">
|
|
|
|
- <ChatMenu
|
|
|
|
- chatId={chat.id}
|
|
|
|
- cloneChatHandler={() => {
|
|
|
|
- cloneChatHandler(chat.id);
|
|
|
|
- }}
|
|
|
|
- shareHandler={() => {
|
|
|
|
- shareChatId = selectedChatId;
|
|
|
|
- showShareChatModal = true;
|
|
|
|
- }}
|
|
|
|
- archiveChatHandler={() => {
|
|
|
|
- archiveChatHandler(chat.id);
|
|
|
|
- }}
|
|
|
|
- renameHandler={() => {
|
|
|
|
- chatTitle = chat.title;
|
|
|
|
- chatTitleEditId = chat.id;
|
|
|
|
- }}
|
|
|
|
- deleteHandler={() => {
|
|
|
|
- chatDeleteId = chat.id;
|
|
|
|
- }}
|
|
|
|
- onClose={() => {
|
|
|
|
- selectedChatId = null;
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <button
|
|
|
|
- aria-label="Chat Menu"
|
|
|
|
- class=" self-center dark:hover:text-white transition"
|
|
|
|
- on:click={() => {
|
|
|
|
- selectedChatId = chat.id;
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 16 16"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- d="M2 8a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM6.5 8a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM12.5 6.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Z"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- </ChatMenu>
|
|
|
|
-
|
|
|
|
- {#if chat.id === $chatId}
|
|
|
|
- <button
|
|
|
|
- id="delete-chat-button"
|
|
|
|
- class="hidden"
|
|
|
|
- on:click={() => {
|
|
|
|
- chatDeleteId = chat.id;
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 16 16"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-4 h-4"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- d="M2 8a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM6.5 8a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM12.5 6.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Z"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
- {/if}
|
|
|
|
- </div>
|
|
|
|
- {/if}
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <ChatItem
|
|
|
|
+ {chat}
|
|
|
|
+ selected={selectedChatId === chat.id}
|
|
|
|
+ on:select={() => {
|
|
|
|
+ selectedChatId = chat.id;
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
{/each}
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|