refac: styling

This commit is contained in:
Timothy Jaeryang Baek 2025-12-09 19:45:13 -05:00
parent 103ff0c5e4
commit a4fe823893

View file

@ -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>