refac: sidebar styling

This commit is contained in:
Timothy Jaeryang Baek 2024-12-21 18:12:44 -07:00
parent 24c3f7a664
commit 27d2fbbe33
3 changed files with 183 additions and 173 deletions

View File

@ -1,4 +1,4 @@
<script> <script lang="ts">
import { getContext, createEventDispatcher, onMount, onDestroy } from 'svelte'; import { getContext, createEventDispatcher, onMount, onDestroy } from 'svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -7,12 +7,15 @@
import ChevronDown from '../icons/ChevronDown.svelte'; import ChevronDown from '../icons/ChevronDown.svelte';
import ChevronRight from '../icons/ChevronRight.svelte'; import ChevronRight from '../icons/ChevronRight.svelte';
import Collapsible from './Collapsible.svelte'; import Collapsible from './Collapsible.svelte';
import Tooltip from './Tooltip.svelte';
import Plus from '../icons/Plus.svelte';
export let open = true; export let open = true;
export let id = ''; export let id = '';
export let name = ''; export let name = '';
export let collapsible = true; export let collapsible = true;
export let onCreateFolder: null | Function = null;
export let className = ''; export let className = '';
@ -113,10 +116,10 @@
}} }}
> >
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="w-full"> <div
<button class="w-full group rounded-md 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 py-1.5 px-2 rounded-md flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-500 font-medium hover:bg-gray-100 dark:hover:bg-gray-900 transition" >
> <button class="w-full py-1.5 pl-2 flex items-center gap-1.5 text-xs font-medium">
<div class="text-gray-300 dark:text-gray-600"> <div class="text-gray-300 dark:text-gray-600">
{#if open} {#if open}
<ChevronDown className=" size-3" strokeWidth="2.5" /> <ChevronDown className=" size-3" strokeWidth="2.5" />
@ -129,6 +132,25 @@
{name} {name}
</div> </div>
</button> </button>
{#if onCreateFolder}
<button
class="absolute z-10 right-2 self-center flex items-center"
on:pointerup={(e) => {
e.stopPropagation();
onCreateFolder();
}}
>
<Tooltip content={$i18n.t('New folder')}>
<button
class="p-0.5 dark:hover:bg-gray-850 rounded-lg touch-auto"
on:click={(e) => {}}
>
<Plus className=" size-3" strokeWidth="2.5" />
</button>
</Tooltip>
</button>
{/if}
</div> </div>
<div slot="content" class="w-full"> <div slot="content" class="w-full">

View File

@ -519,19 +519,6 @@
on:input={searchDebounceHandler} on:input={searchDebounceHandler}
placeholder={$i18n.t('Search')} placeholder={$i18n.t('Search')}
/> />
<div class="absolute z-40 right-3.5 top-1">
<Tooltip content={$i18n.t('New folder')}>
<button
class="p-1 rounded-lg bg-gray-50 hover:bg-gray-100 dark:bg-gray-950 dark:hover:bg-gray-900 transition"
on:click={() => {
createFolder();
}}
>
<Plus />
</button>
</Tooltip>
</div>
</div> </div>
<div <div
@ -539,156 +526,157 @@
? 'opacity-20' ? 'opacity-20'
: ''}" : ''}"
> >
{#if $temporaryChatEnabled} <Folder
<div class="absolute z-40 w-full h-full flex justify-center"></div> collapsible={!search}
{/if} className="px-2 mt-0.5"
name={$i18n.t('Chats')}
onCreateFolder={createFolder}
on:import={(e) => {
importChatHandler(e.detail);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
{#if !search && $pinnedChats.length > 0} if (type === 'chat') {
<div class="flex flex-col space-y-1 rounded-xl"> let chat = await getChatById(localStorage.token, id).catch((error) => {
<Folder return null;
className="px-2" });
bind:open={showPinnedChat} if (!chat && item) {
on:change={(e) => { chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
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') { if (chat) {
let chat = await getChatById(localStorage.token, id).catch((error) => { console.log(chat);
return null; if (chat.folder_id) {
}); const res = await updateChatFolderIdById(localStorage.token, chat.id, null).catch(
if (!chat && item) { (error) => {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {}); toast.error(error);
} return 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);
} 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"
>
{#each $pinnedChats as chat, 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}
<div class=" flex-1 flex flex-col overflow-y-auto scrollbar-hidden">
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList(); initChatList();
}} }
on:change={async () => { } else if (type === 'folder') {
initChatList(); if (folders[id].parent_id === null) {
}} return;
/> }
const res = await updateFolderParentIdById(localStorage.token, id, null).catch(
(error) => {
toast.error(error);
return null;
}
);
if (res) {
await initFolders();
}
}
}}
>
{#if $temporaryChatEnabled}
<div class="absolute z-40 w-full h-full flex justify-center"></div>
{/if} {/if}
<Folder {#if !search && $pinnedChats.length > 0}
collapsible={!search} <div class="flex flex-col space-y-1 rounded-xl">
className="px-2 mt-0.5" <Folder
name={$i18n.t('All chats')} className="pl-1"
on:import={(e) => { bind:open={showPinnedChat}
importChatHandler(e.detail); on:change={(e) => {
}} localStorage.setItem('showPinnedChat', e.detail);
on:drop={async (e) => { console.log(e.detail);
const { type, id, item } = e.detail; }}
on:import={(e) => {
importChatHandler(e.detail, true);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
if (type === 'chat') { if (type === 'chat') {
let chat = await getChatById(localStorage.token, id).catch((error) => { let chat = await getChatById(localStorage.token, id).catch((error) => {
return null; return null;
}); });
if (!chat && item) { if (!chat && item) {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {}); chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
} }
if (chat) { if (chat) {
console.log(chat); console.log(chat);
if (chat.folder_id) { if (chat.folder_id) {
const res = await updateChatFolderIdById(localStorage.token, chat.id, null).catch( const res = await updateChatFolderIdById(
(error) => { localStorage.token,
toast.error(error); chat.id,
return null; null
).catch((error) => {
toast.error(error);
return null;
});
} }
);
}
if (chat.pinned) { if (!chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat, id); 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"
>
{#each $pinnedChats as chat, 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}
<div class=" flex-1 flex flex-col overflow-y-auto scrollbar-hidden">
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList(); initChatList();
} }}
} else if (type === 'folder') { on:change={async () => {
if (folders[id].parent_id === null) { initChatList();
return; }}
} />
{/if}
const res = await updateFolderParentIdById(localStorage.token, id, null).catch(
(error) => {
toast.error(error);
return null;
}
);
if (res) {
await initFolders();
}
}
}}
>
<div class="pt-1.5"> <div class="pt-1.5">
{#if $chats} {#if $chats}
{#each $chats as chat, idx} {#each $chats as chat, idx}
@ -701,23 +689,23 @@
> >
{$i18n.t(chat.time_range)} {$i18n.t(chat.time_range)}
<!-- localisation keys for time_range to be recognized from the i18next parser (so they don't get automatically removed): <!-- localisation keys for time_range to be recognized from the i18next parser (so they don't get automatically removed):
{$i18n.t('Today')} {$i18n.t('Today')}
{$i18n.t('Yesterday')} {$i18n.t('Yesterday')}
{$i18n.t('Previous 7 days')} {$i18n.t('Previous 7 days')}
{$i18n.t('Previous 30 days')} {$i18n.t('Previous 30 days')}
{$i18n.t('January')} {$i18n.t('January')}
{$i18n.t('February')} {$i18n.t('February')}
{$i18n.t('March')} {$i18n.t('March')}
{$i18n.t('April')} {$i18n.t('April')}
{$i18n.t('May')} {$i18n.t('May')}
{$i18n.t('June')} {$i18n.t('June')}
{$i18n.t('July')} {$i18n.t('July')}
{$i18n.t('August')} {$i18n.t('August')}
{$i18n.t('September')} {$i18n.t('September')}
{$i18n.t('October')} {$i18n.t('October')}
{$i18n.t('November')} {$i18n.t('November')}
{$i18n.t('December')} {$i18n.t('December')}
--> -->
</div> </div>
{/if} {/if}
@ -766,8 +754,8 @@
</div> </div>
{/if} {/if}
</div> </div>
</Folder> </div>
</div> </Folder>
</div> </div>
<div class="px-2"> <div class="px-2">

View File

@ -19,7 +19,7 @@
{#each folderList as folderId (folderId)} {#each folderList as folderId (folderId)}
<RecursiveFolder <RecursiveFolder
className="px-2" className="pl-1"
{folders} {folders}
{folderId} {folderId}
on:import={(e) => { on:import={(e) => {