mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 04:15:25 +00:00
refac: styling
This commit is contained in:
parent
103ff0c5e4
commit
a4fe823893
1 changed files with 188 additions and 176 deletions
|
|
@ -435,36 +435,164 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if (items ?? []).length > 0}
|
{#if items !== null && total !== null}
|
||||||
{@const notes = groupNotes(items)}
|
{#if (items ?? []).length > 0}
|
||||||
|
{@const notes = groupNotes(items)}
|
||||||
|
|
||||||
<div class="@container h-full py-2.5 px-2.5">
|
<div class="@container h-full py-2.5 px-2.5">
|
||||||
<div class="">
|
<div class="">
|
||||||
{#each Object.keys(notes) as timeRange, idx}
|
{#each Object.keys(notes) as timeRange, idx}
|
||||||
<div
|
|
||||||
class="w-full text-xs text-gray-500 dark:text-gray-500 font-medium px-2.5 pb-2.5"
|
|
||||||
>
|
|
||||||
{$i18n.t(timeRange)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if displayOption === null}
|
|
||||||
<div
|
<div
|
||||||
class="{Object.keys(notes).length - 1 !== idx
|
class="w-full text-xs text-gray-500 dark:text-gray-500 font-medium px-2.5 pb-2.5"
|
||||||
? 'mb-3'
|
|
||||||
: ''} gap-1.5 flex flex-col"
|
|
||||||
>
|
>
|
||||||
{#each notes[timeRange] as note, idx (note.id)}
|
{$i18n.t(timeRange)}
|
||||||
<div
|
</div>
|
||||||
class=" flex cursor-pointer w-full px-3.5 py-1.5 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
|
||||||
>
|
{#if displayOption === null}
|
||||||
<a href={`/notes/${note.id}`} class="w-full flex flex-col justify-between">
|
<div
|
||||||
<div class="flex-1">
|
class="{Object.keys(notes).length - 1 !== idx
|
||||||
<div class=" flex items-center gap-2 self-center justify-between">
|
? 'mb-3'
|
||||||
<div class=" text-sm font-medium capitalize flex-1 w-full">
|
: ''} gap-1.5 flex flex-col"
|
||||||
{note.title}
|
>
|
||||||
|
{#each notes[timeRange] as note, idx (note.id)}
|
||||||
|
<div
|
||||||
|
class=" flex cursor-pointer w-full px-3.5 py-1.5 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
||||||
|
>
|
||||||
|
<a href={`/notes/${note.id}`} class="w-full flex flex-col justify-between">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class=" flex items-center gap-2 self-center justify-between">
|
||||||
|
<div class=" text-sm font-medium capitalize flex-1 w-full">
|
||||||
|
{note.title}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex shrink-0 items-center text-xs gap-2.5">
|
||||||
|
<div>
|
||||||
|
{dayjs(note.updated_at / 1000000).fromNow()}
|
||||||
|
</div>
|
||||||
|
<Tooltip
|
||||||
|
content={note?.user?.email ?? $i18n.t('Deleted User')}
|
||||||
|
className="flex shrink-0"
|
||||||
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<div class="shrink-0 text-gray-500">
|
||||||
|
{$i18n.t('By {{name}}', {
|
||||||
|
name: capitalizeFirstLetter(
|
||||||
|
note?.user?.name ??
|
||||||
|
note?.user?.email ??
|
||||||
|
$i18n.t('Deleted User')
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<NoteMenu
|
||||||
|
onDownload={(type) => {
|
||||||
|
selectedNote = note;
|
||||||
|
|
||||||
|
downloadHandler(type);
|
||||||
|
}}
|
||||||
|
onCopyLink={async () => {
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const res = await copyToClipboard(
|
||||||
|
`${baseUrl}/notes/${note.id}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
toast.success($i18n.t('Copied link to clipboard'));
|
||||||
|
} else {
|
||||||
|
toast.error($i18n.t('Failed to copy link'));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDelete={() => {
|
||||||
|
selectedNote = note;
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<EllipsisHorizontal className="size-5" />
|
||||||
|
</button>
|
||||||
|
</NoteMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else if displayOption === 'grid'}
|
||||||
|
<div
|
||||||
|
class="{Object.keys(notes).length - 1 !== idx
|
||||||
|
? 'mb-5'
|
||||||
|
: ''} gap-2.5 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5"
|
||||||
|
>
|
||||||
|
{#each notes[timeRange] as note, idx (note.id)}
|
||||||
|
<div
|
||||||
|
class=" flex space-x-4 cursor-pointer w-full px-4.5 py-4 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
||||||
|
>
|
||||||
|
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
|
||||||
|
<a
|
||||||
|
href={`/notes/${note.id}`}
|
||||||
|
class="w-full -translate-y-0.5 flex flex-col justify-between"
|
||||||
|
>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div
|
||||||
|
class=" flex items-center gap-2 self-center mb-1 justify-between"
|
||||||
|
>
|
||||||
|
<div class=" font-semibold line-clamp-1 capitalize">
|
||||||
|
{note.title}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<NoteMenu
|
||||||
|
onDownload={(type) => {
|
||||||
|
selectedNote = note;
|
||||||
|
|
||||||
|
downloadHandler(type);
|
||||||
|
}}
|
||||||
|
onCopyLink={async () => {
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const res = await copyToClipboard(
|
||||||
|
`${baseUrl}/notes/${note.id}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
toast.success($i18n.t('Copied link to clipboard'));
|
||||||
|
} else {
|
||||||
|
toast.error($i18n.t('Failed to copy link'));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDelete={() => {
|
||||||
|
selectedNote = note;
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<EllipsisHorizontal className="size-5" />
|
||||||
|
</button>
|
||||||
|
</NoteMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class=" text-xs text-gray-500 dark:text-gray-500 mb-3 line-clamp-3 min-h-10"
|
||||||
|
>
|
||||||
|
{#if note.data?.content?.md}
|
||||||
|
{note.data?.content?.md}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('No content')}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex shrink-0 items-center text-xs gap-2.5">
|
<div class=" text-xs px-0.5 w-full flex justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
{dayjs(note.updated_at / 1000000).fromNow()}
|
{dayjs(note.updated_at / 1000000).fromNow()}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -483,171 +611,55 @@
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<div>
|
|
||||||
<NoteMenu
|
|
||||||
onDownload={(type) => {
|
|
||||||
selectedNote = note;
|
|
||||||
|
|
||||||
downloadHandler(type);
|
|
||||||
}}
|
|
||||||
onCopyLink={async () => {
|
|
||||||
const baseUrl = window.location.origin;
|
|
||||||
const res = await copyToClipboard(
|
|
||||||
`${baseUrl}/notes/${note.id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
toast.success($i18n.t('Copied link to clipboard'));
|
|
||||||
} else {
|
|
||||||
toast.error($i18n.t('Failed to copy link'));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onDelete={() => {
|
|
||||||
selectedNote = note;
|
|
||||||
showDeleteConfirm = true;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<EllipsisHorizontal className="size-5" />
|
|
||||||
</button>
|
|
||||||
</NoteMenu>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{:else if displayOption === 'grid'}
|
|
||||||
<div
|
|
||||||
class="{Object.keys(notes).length - 1 !== idx
|
|
||||||
? 'mb-5'
|
|
||||||
: ''} gap-2.5 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5"
|
|
||||||
>
|
|
||||||
{#each notes[timeRange] as note, idx (note.id)}
|
|
||||||
<div
|
|
||||||
class=" flex space-x-4 cursor-pointer w-full px-4.5 py-4 border border-gray-50 dark:border-gray-850/30 bg-transparent dark:hover:bg-gray-850 hover:bg-white rounded-2xl transition"
|
|
||||||
>
|
|
||||||
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
|
|
||||||
<a
|
|
||||||
href={`/notes/${note.id}`}
|
|
||||||
class="w-full -translate-y-0.5 flex flex-col justify-between"
|
|
||||||
>
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class=" flex items-center gap-2 self-center mb-1 justify-between">
|
|
||||||
<div class=" font-semibold line-clamp-1 capitalize">{note.title}</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<NoteMenu
|
|
||||||
onDownload={(type) => {
|
|
||||||
selectedNote = note;
|
|
||||||
|
|
||||||
downloadHandler(type);
|
|
||||||
}}
|
|
||||||
onCopyLink={async () => {
|
|
||||||
const baseUrl = window.location.origin;
|
|
||||||
const res = await copyToClipboard(
|
|
||||||
`${baseUrl}/notes/${note.id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
toast.success($i18n.t('Copied link to clipboard'));
|
|
||||||
} else {
|
|
||||||
toast.error($i18n.t('Failed to copy link'));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onDelete={() => {
|
|
||||||
selectedNote = note;
|
|
||||||
showDeleteConfirm = true;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="self-center w-fit text-sm p-1 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<EllipsisHorizontal className="size-5" />
|
|
||||||
</button>
|
|
||||||
</NoteMenu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class=" text-xs text-gray-500 dark:text-gray-500 mb-3 line-clamp-3 min-h-10"
|
|
||||||
>
|
|
||||||
{#if note.data?.content?.md}
|
|
||||||
{note.data?.content?.md}
|
|
||||||
{:else}
|
|
||||||
{$i18n.t('No content')}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-xs px-0.5 w-full flex justify-between items-center">
|
|
||||||
<div>
|
|
||||||
{dayjs(note.updated_at / 1000000).fromNow()}
|
|
||||||
</div>
|
|
||||||
<Tooltip
|
|
||||||
content={note?.user?.email ?? $i18n.t('Deleted User')}
|
|
||||||
className="flex shrink-0"
|
|
||||||
placement="top-start"
|
|
||||||
>
|
|
||||||
<div class="shrink-0 text-gray-500">
|
|
||||||
{$i18n.t('By {{name}}', {
|
|
||||||
name: capitalizeFirstLetter(
|
|
||||||
note?.user?.name ?? note?.user?.email ?? $i18n.t('Deleted User')
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/each}
|
||||||
{/each}
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{/each}
|
||||||
{/each}
|
|
||||||
|
|
||||||
{#if !allItemsLoaded}
|
{#if !allItemsLoaded}
|
||||||
<Loader
|
<Loader
|
||||||
on:visible={(e) => {
|
on:visible={(e) => {
|
||||||
if (!itemsLoading) {
|
if (!itemsLoading) {
|
||||||
loadMoreItems();
|
loadMoreItems();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="w-full flex justify-center py-4 text-xs animate-pulse items-center gap-2"
|
|
||||||
>
|
>
|
||||||
<Spinner className=" size-4" />
|
<div
|
||||||
<div class=" ">{$i18n.t('Loading...')}</div>
|
class="w-full flex justify-center py-4 text-xs animate-pulse items-center gap-2"
|
||||||
</div>
|
>
|
||||||
</Loader>
|
<Spinner className=" size-4" />
|
||||||
{/if}
|
<div class=" ">{$i18n.t('Loading...')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Loader>
|
||||||
{:else}
|
{/if}
|
||||||
<div class="w-full h-full flex flex-col items-center justify-center">
|
|
||||||
<div class="py-20 text-center">
|
|
||||||
<div class=" text-sm text-gray-400 dark:text-gray-600">
|
|
||||||
{$i18n.t('No Notes')}
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="w-full h-full flex flex-col items-center justify-center">
|
||||||
|
<div class="py-20 text-center">
|
||||||
|
<div class=" text-sm text-gray-400 dark:text-gray-600">
|
||||||
|
{$i18n.t('No Notes')}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-1 text-xs text-gray-300 dark:text-gray-700">
|
<div class="mt-1 text-xs text-gray-300 dark:text-gray-700">
|
||||||
{$i18n.t('Create your first note by clicking on the plus button below.')}
|
{$i18n.t('Create your first note by clicking on the plus button below.')}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<div class="w-full h-full flex justify-center items-center py-10">
|
||||||
|
<Spinner className="size-4" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="w-full h-full flex justify-center items-center">
|
<div class="w-full h-full flex justify-center items-center">
|
||||||
<Spinner className="size-5" />
|
<Spinner className="size-4" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue