refac: collection styling

This commit is contained in:
Timothy J. Baek
2024-10-20 00:36:43 -07:00
parent e8c629a2e2
commit 03282da45c
7 changed files with 333 additions and 239 deletions
@@ -2,6 +2,7 @@
import Fuse from 'fuse.js';
import { toast } from 'svelte-sonner';
import { v4 as uuidv4 } from 'uuid';
import { PaneGroup, Pane, PaneResizer } from 'paneforge';
import { onMount, getContext, onDestroy, tick } from 'svelte';
const i18n = getContext('i18n');
@@ -34,8 +35,17 @@
import SyncConfirmDialog from '../../common/ConfirmDialog.svelte';
import RichTextInput from '$lib/components/common/RichTextInput.svelte';
import EllipsisVertical from '$lib/components/icons/EllipsisVertical.svelte';
import Drawer from '$lib/components/common/Drawer.svelte';
import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte';
import MenuLines from '$lib/components/icons/MenuLines.svelte';
let largeScreen = true;
let pane;
let showSidepanel = true;
let minSize = 0;
type Knowledge = {
id: string;
name: string;
@@ -458,6 +468,30 @@
mediaQuery.addEventListener('change', handleMediaQuery);
handleMediaQuery(mediaQuery);
// Select the container element you want to observe
const container = document.getElementById('collection-container');
// initialize the minSize based on the container width
minSize = !largeScreen ? 100 : Math.floor((300 / container.clientWidth) * 100);
// Create a new ResizeObserver instance
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const width = entry.contentRect.width;
// calculate the percentage of 300
const percentage = (300 / width) * 100;
// set the minSize to the percentage, must be an integer
minSize = !largeScreen ? 100 : Math.floor(percentage);
}
});
// Start observing the container's size changes
resizeObserver.observe(container);
if (pane) {
pane.expand();
}
id = $page.params.id;
const res = await getKnowledgeById(localStorage.token, id).catch((e) => {
@@ -551,157 +585,248 @@
}}
/>
<div class="flex flex-col w-full h-full max-h-[100dvh]">
<div class="flex flex-col w-full h-full max-h-[100dvh]" id="collection-container">
{#if id && knowledge}
<div class="flex flex-row flex-1 h-full max-h-full pb-2.5">
<div
class=" {largeScreen
? 'flex-shrink-0'
: 'flex-1'} flex py-2.5 w-80 rounded-2xl border border-gray-50 dark:border-gray-850"
>
<div class=" flex flex-col w-full space-x-2 rounded-lg h-full">
<div class="w-full h-full flex flex-col">
<div class=" px-3">
<div class="flex">
<div class=" self-center ml-1 mr-3">
<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="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
clip-rule="evenodd"
/>
</svg>
</div>
<input
class=" w-full text-sm pr-4 py-1 rounded-r-xl outline-none bg-transparent"
bind:value={query}
placeholder={$i18n.t('Search Collection')}
on:focus={() => {
selectedFileId = null;
}}
/>
<div>
<AddContentMenu
on:upload={(e) => {
if (e.detail.type === 'directory') {
uploadDirectoryHandler();
} else if (e.detail.type === 'text') {
showAddTextContentModal = true;
} else {
document.getElementById('files-input').click();
}
}}
on:sync={(e) => {
showSyncConfirmModal = true;
}}
/>
</div>
</div>
<hr class=" mt-2 mb-1 border-gray-50 dark:border-gray-850" />
</div>
{#if filteredItems.length > 0}
<div class=" flex overflow-y-auto h-full w-full scrollbar-hidden text-xs">
<Files
files={filteredItems}
{selectedFileId}
on:click={(e) => {
selectedFileId = selectedFileId === e.detail ? null : e.detail;
}}
on:delete={(e) => {
console.log(e.detail);
selectedFileId = null;
deleteFileHandler(e.detail);
}}
/>
</div>
{:else}
<div class="m-auto text-gray-500 text-xs">{$i18n.t('No content found')}</div>
{/if}
</div>
</div>
</div>
{#if largeScreen}
<div class="flex-1 flex justify-start h-full max-h-full pl-3">
{#if selectedFile}
<div class=" flex flex-col w-full h-full max-h-full">
<div class="flex-shrink-0 mb-2 flex items-center">
<div class=" flex-1 text-xl line-clamp-1">
{selectedFile?.meta?.name}
</div>
<div>
<button
class="self-center w-fit text-sm py-1 px-2.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-lg"
on:click={() => {
updateFileContentHandler();
}}
>
{$i18n.t('Save')}
</button>
</div>
</div>
<div
class=" flex-1 w-full h-full max-h-full py-2.5 px-3.5 rounded-xl text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none overflow-y-auto scrollbar-hidden"
>
{#key selectedFile.id}
<RichTextInput
className="input-prose-sm"
bind:value={selectedFile.data.content}
placeholder={$i18n.t('Add content here')}
/>
{/key}
</div>
</div>
{:else}
<div class="m-auto pb-32">
<div>
<div class=" flex w-full mt-1 mb-3.5">
<div class="flex-1">
<div class="flex items-center justify-between w-full px-0.5 mb-1">
<div class="w-full">
<input
type="text"
class="text-center w-full font-medium text-3xl font-primary bg-transparent outline-none"
bind:value={knowledge.name}
on:input={() => {
changeDebounceHandler();
}}
<PaneGroup direction="horizontal">
<Pane
bind:pane
defaultSize={minSize}
collapsible={true}
maxSize={50}
{minSize}
class="h-full"
onExpand={() => {
showSidepanel = true;
}}
onCollapse={() => {
showSidepanel = false;
}}
>
<div
class="{largeScreen ? 'flex-shrink-0' : 'flex-1'}
flex
py-2
rounded-2xl
border
border-gray-50
h-full
dark:border-gray-850"
>
<div class=" flex flex-col w-full space-x-2 rounded-lg h-full">
<div class="w-full h-full flex flex-col">
<div class=" px-3">
<div class="flex py-1">
<div class=" self-center ml-1 mr-3">
<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="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
clip-rule="evenodd"
/>
</div>
</svg>
</div>
<input
class=" w-full text-sm pr-4 py-1 rounded-r-xl outline-none bg-transparent"
bind:value={query}
placeholder={$i18n.t('Search Collection')}
on:focus={() => {
selectedFileId = null;
}}
/>
<div class="flex w-full px-1">
<input
type="text"
class="text-center w-full text-gray-500 bg-transparent outline-none"
bind:value={knowledge.description}
on:input={() => {
changeDebounceHandler();
<div>
<AddContentMenu
on:upload={(e) => {
if (e.detail.type === 'directory') {
uploadDirectoryHandler();
} else if (e.detail.type === 'text') {
showAddTextContentModal = true;
} else {
document.getElementById('files-input').click();
}
}}
on:sync={(e) => {
showSyncConfirmModal = true;
}}
/>
</div>
</div>
</div>
</div>
<div class=" mt-2 text-center text-sm text-gray-200 dark:text-gray-700 w-full">
{$i18n.t('Select a file to view or drag and drop a file to upload')}
{#if filteredItems.length > 0}
<div class=" flex overflow-y-auto h-full w-full scrollbar-hidden text-xs">
<Files
files={filteredItems}
{selectedFileId}
on:click={(e) => {
selectedFileId = selectedFileId === e.detail ? null : e.detail;
}}
on:delete={(e) => {
console.log(e.detail);
selectedFileId = null;
deleteFileHandler(e.detail);
}}
/>
</div>
{:else}
<div class="m-auto text-gray-500 text-xs">{$i18n.t('No content found')}</div>
{/if}
</div>
</div>
{/if}
</div>
{/if}
</div>
</Pane>
{#if largeScreen}
<PaneResizer class="relative flex w-2 items-center justify-center bg-background group">
<div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
<EllipsisVertical className="size-4 invisible group-hover:visible" />
</div>
</PaneResizer>
<Pane>
<div class="flex-1 flex justify-start h-full max-h-full">
{#if selectedFile}
<div class=" flex flex-col w-full h-full max-h-full ml-2">
<div class="flex-shrink-0 mb-2 flex items-center">
{#if !showSidepanel}
<div class="-translate-x-2">
<button
class="w-full text-left text-sm p-1.5 rounded-lg dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-gray-850"
on:click={() => {
pane.expand();
}}
>
<ChevronLeft strokeWidth="2.5" />
</button>
</div>
{/if}
<div class=" flex-1 text-2xl font-medium line-clamp-1">
{selectedFile?.meta?.name}
</div>
<div>
<button
class="self-center w-fit text-sm py-1 px-2.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-lg"
on:click={() => {
updateFileContentHandler();
}}
>
{$i18n.t('Save')}
</button>
</div>
</div>
<div
class=" flex-1 w-full h-full max-h-full text-sm bg-transparent outline-none overflow-y-auto scrollbar-hidden"
>
{#key selectedFile.id}
<RichTextInput
className="input-prose-sm"
bind:value={selectedFile.data.content}
placeholder={$i18n.t('Add content here')}
/>
{/key}
</div>
</div>
{:else}
<div class="m-auto pb-32">
<div>
<div class=" flex w-full mt-1 mb-3.5">
<div class="flex-1">
<div class="flex items-center justify-between w-full px-0.5 mb-1">
<div class="w-full">
<input
type="text"
class="text-center w-full font-medium text-3xl font-primary bg-transparent outline-none"
bind:value={knowledge.name}
on:input={() => {
changeDebounceHandler();
}}
/>
</div>
</div>
<div class="flex w-full px-1">
<input
type="text"
class="text-center w-full text-gray-500 bg-transparent outline-none"
bind:value={knowledge.description}
on:input={() => {
changeDebounceHandler();
}}
/>
</div>
</div>
</div>
</div>
<div class=" mt-2 text-center text-sm text-gray-200 dark:text-gray-700 w-full">
{$i18n.t('Select a file to view or drag and drop a file to upload')}
</div>
</div>
{/if}
</div>
</Pane>
{:else if !largeScreen && selectedFileId !== null}
<Drawer
className="h-full"
show={selectedFileId !== null}
on:close={() => {
selectedFileId = null;
}}
>
<div class="flex flex-col justify-start h-full max-h-full p-2">
<div class=" flex flex-col w-full h-full max-h-full">
<div class="flex-shrink-0 mb-2 flex items-center">
<div class="mr-2">
<button
class="w-full text-left text-sm p-1.5 rounded-lg dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-gray-850"
on:click={() => {
selectedFileId = null;
}}
>
<ChevronLeft strokeWidth="2.5" />
</button>
</div>
<div class=" flex-1 text-xl line-clamp-1">
{selectedFile?.meta?.name}
</div>
<div>
<button
class="self-center w-fit text-sm py-1 px-2.5 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-lg"
on:click={() => {
updateFileContentHandler();
}}
>
{$i18n.t('Save')}
</button>
</div>
</div>
<div
class=" flex-1 w-full h-full max-h-full py-2.5 px-3.5 rounded-xl text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none overflow-y-auto scrollbar-hidden"
>
{#key selectedFile.id}
<RichTextInput
className="input-prose-sm"
bind:value={selectedFile.data.content}
placeholder={$i18n.t('Add content here')}
/>
{/key}
</div>
</div>
</div>
</Drawer>
{/if}
</PaneGroup>
</div>
{:else}
<Spinner />