feat(collections): enhance collections page with sorting, filtering, and pagination features

- Updated the collections loading logic to include sorting and pagination parameters from the URL.
- Refactored the collections page to manage owned, shared, and archived collections with a tabbed interface.
- Added sorting functionality to allow users to sort collections by different attributes.
- Implemented a sidebar for filtering and sorting options.
- Improved the UI for better user experience, including a floating action button for creating new collections.
- Added a not found page for collections that do not exist, enhancing error handling.
This commit is contained in:
Sean Morley
2025-06-13 12:11:42 -04:00
parent 7eb96bcc2a
commit 14eb4ca802
23 changed files with 1691 additions and 1251 deletions

View File

@@ -9,7 +9,7 @@
import ShareVariant from '~icons/mdi/share-variant';
import { goto } from '$app/navigation';
import type { Adventure, Collection } from '$lib/types';
import type { Adventure, Collection, User } from '$lib/types';
import { addToast } from '$lib/toasts';
import { t } from 'svelte-i18n';
@@ -25,6 +25,7 @@
export let type: String | undefined | null;
export let linkedCollectionList: string[] | null = null;
export let user: User | null;
let isShareModalOpen: boolean = false;
function editAdventure() {
@@ -168,76 +169,78 @@
<Launch class="w-4 h-4" />
{$t('adventures.open_details')}
</button>
<div class="dropdown dropdown-end">
<button type="button" class="btn btn-square btn-sm btn-base-300">
<DotsHorizontal class="w-5 h-5" />
</button>
<ul
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-64 p-2 shadow-xl border border-base-300"
>
{#if type != 'viewonly'}
<li>
<button class="flex items-center gap-2" on:click={editAdventure}>
<FileDocumentEdit class="w-4 h-4" />
{$t('adventures.edit_collection')}
</button>
</li>
<li>
<button
class="flex items-center gap-2"
on:click={() => (isShareModalOpen = true)}
>
<ShareVariant class="w-4 h-4" />
{$t('adventures.share')}
</button>
</li>
{#if collection.is_archived}
{#if user && user.uuid == collection.user_id}
<div class="dropdown dropdown-end">
<button type="button" class="btn btn-square btn-sm btn-base-300">
<DotsHorizontal class="w-5 h-5" />
</button>
<ul
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-64 p-2 shadow-xl border border-base-300"
>
{#if type != 'viewonly'}
<li>
<button
class="flex items-center gap-2"
on:click={() => archiveCollection(false)}
>
<ArchiveArrowUp class="w-4 h-4" />
{$t('adventures.unarchive')}
<button class="flex items-center gap-2" on:click={editAdventure}>
<FileDocumentEdit class="w-4 h-4" />
{$t('adventures.edit_collection')}
</button>
</li>
{:else}
<li>
<button
class="flex items-center gap-2"
on:click={() => archiveCollection(true)}
on:click={() => (isShareModalOpen = true)}
>
<ArchiveArrowDown class="w-4 h-4" />
{$t('adventures.archive')}
<ShareVariant class="w-4 h-4" />
{$t('adventures.share')}
</button>
</li>
{#if collection.is_archived}
<li>
<button
class="flex items-center gap-2"
on:click={() => archiveCollection(false)}
>
<ArchiveArrowUp class="w-4 h-4" />
{$t('adventures.unarchive')}
</button>
</li>
{:else}
<li>
<button
class="flex items-center gap-2"
on:click={() => archiveCollection(true)}
>
<ArchiveArrowDown class="w-4 h-4" />
{$t('adventures.archive')}
</button>
</li>
{/if}
<div class="divider my-1"></div>
<li>
<button
id="delete_collection"
data-umami-event="Delete Collection"
class="text-error flex items-center gap-2"
on:click={() => (isWarningModalOpen = true)}
>
<TrashCan class="w-4 h-4" />
{$t('adventures.delete')}
</button>
</li>
{/if}
<div class="divider my-1"></div>
<li>
<button
id="delete_collection"
data-umami-event="Delete Collection"
class="text-error flex items-center gap-2"
on:click={() => (isWarningModalOpen = true)}
>
<TrashCan class="w-4 h-4" />
{$t('adventures.delete')}
</button>
</li>
{/if}
{#if type == 'viewonly'}
<li>
<button
class="flex items-center gap-2"
on:click={() => goto(`/collections/${collection.id}`)}
>
<Launch class="w-4 h-4" />
{$t('adventures.open_details')}
</button>
</li>
{/if}
</ul>
</div>
{#if type == 'viewonly'}
<li>
<button
class="flex items-center gap-2"
on:click={() => goto(`/collections/${collection.id}`)}
>
<Launch class="w-4 h-4" />
{$t('adventures.open_details')}
</button>
</li>
{/if}
</ul>
</div>
{/if}
</div>
{/if}
</div>