mirror of
https://github.com/open-webui/open-webui
synced 2025-01-18 00:30:51 +00:00
refac: collection styling
This commit is contained in:
parent
e8c629a2e2
commit
03282da45c
@ -6,23 +6,11 @@
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let show = false;
|
||||
export let size = 'md';
|
||||
export let className = '';
|
||||
|
||||
let modalElement = null;
|
||||
let mounted = false;
|
||||
|
||||
const sizeToWidth = (size) => {
|
||||
if (size === 'xs') {
|
||||
return 'w-[16rem]';
|
||||
} else if (size === 'sm') {
|
||||
return 'w-[30rem]';
|
||||
} else if (size === 'md') {
|
||||
return 'w-[48rem]';
|
||||
} else {
|
||||
return 'w-[56rem]';
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape' && isTopModal()) {
|
||||
console.log('Escape');
|
||||
@ -76,7 +64,7 @@
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class=" mt-auto max-w-full w-full bg-gray-50 dark:bg-gray-900 max-h-[100dvh] overflow-y-auto scrollbar-hidden"
|
||||
class=" mt-auto max-w-full w-full bg-gray-50 dark:bg-gray-900 dark:text-gray-100 {className} max-h-[100dvh] overflow-y-auto scrollbar-hidden"
|
||||
on:mousedown={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
|
@ -6,11 +6,15 @@
|
||||
|
||||
export let show = true;
|
||||
export let size = 'md';
|
||||
export let className = 'bg-gray-50 dark:bg-gray-900 rounded-2xl';
|
||||
|
||||
let modalElement = null;
|
||||
let mounted = false;
|
||||
|
||||
const sizeToWidth = (size) => {
|
||||
if (size === 'full') {
|
||||
return 'w-full';
|
||||
}
|
||||
if (size === 'xs') {
|
||||
return 'w-[16rem]';
|
||||
} else if (size === 'sm') {
|
||||
@ -68,9 +72,9 @@
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class=" m-auto rounded-2xl max-w-full {sizeToWidth(
|
||||
size
|
||||
)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl max-h-[100dvh] overflow-y-auto scrollbar-hidden"
|
||||
class=" m-auto max-w-full {sizeToWidth(size)} {size !== 'full'
|
||||
? 'mx-2'
|
||||
: ''} shadow-3xl max-h-[100dvh] overflow-y-auto scrollbar-hidden {className}"
|
||||
in:flyAndScale
|
||||
on:mousedown={(e) => {
|
||||
e.stopPropagation();
|
||||
|
@ -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 />
|
||||
|
@ -29,7 +29,7 @@
|
||||
>
|
||||
<Tooltip content={$i18n.t('Add Content')}>
|
||||
<button
|
||||
class=" px-2 py-2 rounded-xl border border-gray-50 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 transition font-medium text-sm flex items-center space-x-1"
|
||||
class=" p-1.5 rounded-xl hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
show = true;
|
||||
|
@ -7,98 +7,75 @@
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
import Modal from '$lib/components/common/Modal.svelte';
|
||||
import RichTextInput from '$lib/components/common/RichTextInput.svelte';
|
||||
import XMark from '$lib/components/icons/XMark.svelte';
|
||||
export let show = false;
|
||||
|
||||
let name = '';
|
||||
let name = 'Untitled';
|
||||
let content = '';
|
||||
</script>
|
||||
|
||||
<Modal size="md" bind:show>
|
||||
<div>
|
||||
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4">
|
||||
<div class=" text-lg font-medium self-center">{$i18n.t('Add Content')}</div>
|
||||
<button
|
||||
class="self-center"
|
||||
on:click={() => {
|
||||
show = false;
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
>
|
||||
<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>
|
||||
<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200">
|
||||
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
|
||||
<form
|
||||
class="flex flex-col w-full"
|
||||
on:submit|preventDefault={() => {
|
||||
if (name.trim() === '' || content.trim() === '') {
|
||||
toast.error($i18n.t('Please fill in all fields.'));
|
||||
name = '';
|
||||
content = '';
|
||||
return;
|
||||
}
|
||||
<Modal size="full" className="h-full bg-white dark:bg-gray-900" bind:show>
|
||||
<div class="absolute top-0 right-0 p-5">
|
||||
<button
|
||||
class="self-center dark:text-white"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
show = false;
|
||||
}}
|
||||
>
|
||||
<XMark className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row w-full h-full md:space-x-4 dark:text-gray-200">
|
||||
<form
|
||||
class="flex flex-col w-full h-full"
|
||||
on:submit|preventDefault={() => {
|
||||
if (name.trim() === '' || content.trim() === '') {
|
||||
toast.error($i18n.t('Please fill in all fields.'));
|
||||
name = name.trim();
|
||||
content = content.trim();
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch('submit', {
|
||||
name,
|
||||
content
|
||||
});
|
||||
show = false;
|
||||
name = '';
|
||||
content = '';
|
||||
}}
|
||||
>
|
||||
<div class="mb-3 w-full">
|
||||
<div class="w-full flex flex-col gap-2.5">
|
||||
<div class="w-full">
|
||||
<div class=" text-sm mb-2">{$i18n.t('Title')}</div>
|
||||
|
||||
<div class="w-full mt-1">
|
||||
<input
|
||||
class="w-full rounded-lg py-2 px-4 text-sm bg-white dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
type="text"
|
||||
bind:value={name}
|
||||
placeholder={`Name your content`}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-sm mb-2">{$i18n.t('Content')}</div>
|
||||
|
||||
<div class=" w-full mt-1">
|
||||
<textarea
|
||||
class="w-full resize-none rounded-lg py-2 px-4 text-sm bg-whites dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
rows="10"
|
||||
bind:value={content}
|
||||
placeholder={`Write your content here`}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
dispatch('submit', {
|
||||
name,
|
||||
content
|
||||
});
|
||||
show = false;
|
||||
name = '';
|
||||
content = '';
|
||||
}}
|
||||
>
|
||||
<div class=" flex-1 w-full h-full flex justify-center overflow-auto px-5 py-4">
|
||||
<div class=" max-w-3xl py-2 md:py-14 w-full flex flex-col gap-2">
|
||||
<div class="flex-shrink-0 w-full flex justify-between items-center">
|
||||
<div class="w-full">
|
||||
<input
|
||||
class="w-full text-3xl font-semibold rounded-lg bg-transparent outline-none"
|
||||
type="text"
|
||||
bind:value={name}
|
||||
placeholder={$i18n.t('Title')}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end text-sm font-medium">
|
||||
<button
|
||||
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
|
||||
type="submit"
|
||||
>
|
||||
{$i18n.t('Add Content')}
|
||||
</button>
|
||||
<div class=" flex-1 w-full h-full">
|
||||
<RichTextInput bind:value={content} placeholder={$i18n.t('Content')} />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end text-sm font-medium flex-shrink-0 mt-1 py-3 px-3">
|
||||
<button
|
||||
class=" px-3.5 py-2 bg-black text-white dark:bg-white dark:text-black transition rounded-full"
|
||||
type="submit"
|
||||
>
|
||||
{$i18n.t('Save')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<div class=" max-h-full flex flex-col w-full">
|
||||
{#each files as file}
|
||||
<div class="mt-2 px-2">
|
||||
<div class="mt-1 px-2">
|
||||
<FileItem
|
||||
className="w-full"
|
||||
colorClassName="{selectedFileId === file.id
|
||||
|
@ -110,7 +110,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" pb-1 px-5 flex-1 max-h-full overflow-y-auto">
|
||||
<div class=" pb-1 px-[18px] flex-1 max-h-full overflow-y-auto">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user