Browse Source

Unbreak pagination

master
Nuša Pukšič 6 months ago committed by buttercat1791
parent
commit
e667cbd3cb
  1. 86
      src/lib/components/Notifications.svelte
  2. 5
      src/lib/components/ZettelEditor.svelte
  3. 300
      src/lib/components/publications/Publication.svelte
  4. 2
      src/lib/components/util/ArticleNav.svelte
  5. 4
      src/routes/new/compose/+page.svelte
  6. 2
      src/routes/profile/notifications/+page.svelte

86
src/lib/components/Notifications.svelte

@ -70,7 +70,7 @@ @@ -70,7 +70,7 @@
let allFromMeNotifications = $state<NDKEvent[]>([]); // All fetched "from-me" notifications
let allPublicMessages = $state<NDKEvent[]>([]); // All fetched public messages
let currentPage = $state(1);
let itemsPerPage = 20; // Show 20 items per page
let itemsPerPage = 10; // Show 20 items per page
let hasFetchedToMe = $state(false); // Track if we've already fetched "to-me" data
let hasFetchedFromMe = $state(false); // Track if we've already fetched "from-me" data
let hasFetchedPublic = $state(false); // Track if we've already fetched public messages
@ -650,27 +650,13 @@ @@ -650,27 +650,13 @@
}
}
// AI-NOTE: Pagination navigation functions
function nextPage() {
if (hasNextPage) {
currentPage++;
updateDisplayedItems();
}
}
function previousPage() {
if (hasPreviousPage) {
currentPage--;
updateDisplayedItems();
}
}
function goToPage(page: number) {
if (page >= 1 && page <= totalPages) {
currentPage = page;
updateDisplayedItems();
}
}
// Pagination navigation
$effect (() => {
console.log(`[Pagination] Mode: ${notificationMode}, Current Page: ${currentPage}, Total Pages: ${totalPages}`);
updateDisplayedItems();
// scroll to top
window.scrollTo({ top: 0, behavior: 'smooth' });
});
// AI-NOTE: Update displayed items based on current page
function updateDisplayedItems() {
@ -845,33 +831,30 @@ @@ -845,33 +831,30 @@
</script>
{#if isOwnProfile && $userStore.signedIn}
<div class="mb-6 w-full">
<div class="flex items-center justify-between mb-4">
<Heading tag="h3" class="h-leather">Notifications</Heading>
<div class="flex flex-row items-center gap-3">
<!-- New Message Button -->
<Button
color="primary"
size="sm"
onclick={() => openNewMessageModal()}
class="flex !mb-0 items-center gap-1.5 px-3 py-1.5 text-sm font-medium"
<Heading tag="h3" class="h-leather">Notifications</Heading>
<div class="flex flex-row items-center gap-3">
<!-- New Message Button -->
<Button
color="primary"
size="sm"
onclick={() => openNewMessageModal()}
class="flex !mb-0 items-center gap-1.5 px-3 py-1.5 text-sm font-medium"
>
New Message
</Button>
<!-- Mode toggle -->
<div class="flex flex-row bg-gray-300 dark:bg-gray-700 rounded-lg p-1">
{#each modes as mode}
{@const modeLabel = mode === "to-me" ? "To Me" : mode === "from-me" ? "From Me" : "Public Messages"}
<button
class={`mode-toggle-button px-3 py-1 text-sm !mb-0 font-medium rounded-md ${notificationMode === mode ? 'active' : 'inactive'}`}
onclick={() => setNotificationMode(mode)}
>
New Message
</Button>
<!-- Mode toggle -->
<div class="flex flex-row bg-gray-300 dark:bg-gray-700 rounded-lg p-1">
{#each modes as mode}
{@const modeLabel = mode === "to-me" ? "To Me" : mode === "from-me" ? "From Me" : "Public Messages"}
<button
class={`mode-toggle-button px-3 py-1 text-sm !mb-0 font-medium rounded-md ${notificationMode === mode ? 'active' : 'inactive'}`}
onclick={() => setNotificationMode(mode)}
>
{modeLabel}
</button>
{/each}
</div>
{modeLabel}
</button>
{/each}
</div>
</div>
@ -1038,11 +1021,11 @@ @@ -1038,11 +1021,11 @@
{/if}
{:else}
{#if notifications.length === 0}
<div class="p-4 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-lg">
<AAlert color="blue">
<P>No notifications {notificationMode === "to-me" ? "received" : "sent"} found.</P>
</div>
</AAlert>
{:else}
<div class="max-h-[72rem] overflow-y-auto overflow-x-hidden space-y-4">
<div class="space-y-4">
{#each notifications.slice(0, 100) as notification}
{@const authorProfile = authorProfiles.get(notification.pubkey)}
<div class="message-container p-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
@ -1147,7 +1130,6 @@ @@ -1147,7 +1130,6 @@
</div>
{/if}
{/if}
</div>
<!-- New Message Modal -->
<Modal bind:open={showNewMessageModal} size="lg" class="w-full">

5
src/lib/components/ZettelEditor.svelte

@ -53,7 +53,8 @@ @@ -53,7 +53,8 @@
ta.selectionStart = ta.selectionEnd = pos;
});
}
const newNoteTemplate = `\n== Note Title\n:author: \n:version: 1.0\n:published_on: 2024-01-01\n:published_by: Alexandria\n:summary: \n:tags: \n:image: \n\nNote content here...\n`;
const today = new Date().toISOString().split('T')[0];
const newNoteTemplate = `\n== Note Title\n:author: \n:version: 1.0\n:published_on: ${today}\n:published_by: Alexandria\n:summary: \n:tags: \n:image: \n\nNote content here...\n`;
function insertNoteTemplate() {
const ta = getTextarea();
if (!ta || ta.disabled) return;
@ -191,7 +192,7 @@ @@ -191,7 +192,7 @@
</div>
{:else}
<!-- Informative text about ZettelEditor purpose -->
<AAlert color="blue" classes="max-w-lg self-center">
<AAlert color="blue" classes="w-full self-center">
{#snippet title()}Note-Taking Tool{/snippet}
<p class="text-sm mb-3">
This editor is for creating individual notes (30041 events) only. Each section becomes a separate note event.

300
src/lib/components/publications/Publication.svelte

@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
import type { SveltePublicationTree } from "./svelte_publication_tree.svelte";
import TableOfContents from "./TableOfContents.svelte";
import type { TableOfContents as TocType } from "./table_of_contents.svelte";
import ArticleNav from "$components/util/ArticleNav.svelte";
let { rootAddress, publicationType, indexEvent, publicationTree, toc } = $props<{
rootAddress: string;
@ -252,164 +253,169 @@ @@ -252,164 +253,169 @@
</script>
<!-- Add gap & items-start so sticky sidebars size correctly -->
<div class="grid grid-cols-[1fr_3fr_1fr] gap-4 items-start">
<!-- Table of contents -->
{#if publicationType !== "blog" && !isLeaf}
<Sidebar
class="z-10 ml-4 bg-transparent sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto
border border-s-4 rounded border-primary-200 dark:border-primary-800
dark:bg-primary-1000"
position="static"
activeUrl={`#${activeAddress ?? ""}`}
classes={{
div: 'bg-transparent', /* inner wrapper neutral */
active: 'bg-primary-100 dark:bg-primary-800 p-2 rounded-lg',
nonactive: 'bg-primary-50 dark:bg-primary-800',
}}
>
<CloseButton
onclick={closeTocSidebar}
class="btn-leather hover:bg-primary-50 dark:hover:bg-primary-800"
/>
<TableOfContents
{rootAddress}
{toc}
depth={2}
onSectionFocused={(address: string) => publicationTree.setBookmark(address)}
onLoadMore={() => {
if (!isLoading && !isDone && publicationTree) {
loadMore(4);
}
<div class="grid gap-4 items-start grid-cols-[1fr_3fr_1fr] grid-rows-[auto_1fr]">
<!-- Full-width ArticleNav row -->
<ArticleNav
publicationType={publicationType}
rootId={indexEvent.id}
indexEvent={indexEvent}
/>
<!-- Three-column row -->
<div class="contents">
<!-- Table of contents -->
{#if publicationType !== "blog" && !isLeaf}
<Sidebar
class="z-10 ml-4 bg-transparent sticky top-[162px] h-[calc(100vh-165px)] overflow-y-auto
border border-s-4 rounded border-primary-200 dark:border-primary-800
dark:bg-primary-1000"
activeUrl={`#${activeAddress ?? ""}`}
classes={{
div: 'bg-transparent',
active: 'bg-primary-100 dark:bg-primary-800 p-2 rounded-lg',
nonactive: 'bg-primary-50 dark:bg-primary-800',
}}
/>
</Sidebar>
{/if}
<div>
<!-- Default publications -->
{#if $publicationColumnVisibility.main}
<!-- Remove overflow-auto so page scroll drives it -->
<div class="flex flex-col p-4 space-y-4 max-w-2xl flex-grow-2">
<div
class="card-leather bg-highlight dark:bg-primary-800 p-4 mb-4 rounded-lg border"
>
<Details event={indexEvent} />
</div>
<!-- Publication sections/cards -->
{#each leaves as leaf, i}
{#if leaf == null}
<Alert class="flex space-x-2">
<ExclamationCircleOutline class="w-5 h-5" />
Error loading content. One or more events could not be loaded.
</Alert>
{:else}
{@const address = leaf.tagAddress()}
<PublicationSection
{rootAddress}
{leaves}
{address}
{publicationTree}
{toc}
ref={(el) => onPublicationSectionMounted(el, address)}
/>
{/if}
{/each}
<div class="flex justify-center my-4">
{#if isLoading}
<Button disabled color="primary">Loading...</Button>
{:else if !isDone}
<Button color="primary" onclick={() => loadMore(1)}>Show More</Button>
{:else}
<p class="text-gray-500 dark:text-gray-400">
You've reached the end of the publication.
</p>
{/if}
</div>
</div>
{/if}
<!-- Blog list -->
{#if $publicationColumnVisibility.blog}
<!-- Remove overflow-auto -->
<div
class={`flex flex-col p-4 space-y-4 max-w-xl flex-grow-1 ${isInnerActive() ? "discreet" : ""}`}
>
<div
class="card-leather bg-highlight dark:bg-primary-800 p-4 mb-4 rounded-lg border"
>
<Details event={indexEvent} />
</div>
<!-- List blog excerpts -->
{#each leaves as leaf, i}
{#if leaf}
<BlogHeader
rootId={leaf.tagAddress()}
event={leaf}
onBlogUpdate={loadBlog}
active={!isInnerActive()}
<SidebarWrapper>
<TableOfContents
{rootAddress}
{toc}
depth={2}
onSectionFocused={(address: string) => publicationTree.setBookmark(address)}
onLoadMore={() => {
if (!isLoading && !isDone && publicationTree) {
loadMore(4);
}
}}
/>
{/if}
{/each}
</div>
</SidebarWrapper>
</Sidebar>
{/if}
{#if isInnerActive()}
{#key currentBlog}
<!-- Remove overflow-auto & sticky; allow page scroll -->
<div class="flex flex-col p-4 max-w-3xl flex-grow-2">
<!-- ...existing code... -->
<div class="mt-[70px]">
<!-- Default publications -->
{#if $publicationColumnVisibility.main}
<!-- Remove overflow-auto so page scroll drives it -->
<div class="flex flex-col p-4 space-y-4 max-w-2xl flex-grow-2">
<div
class="card-leather bg-highlight dark:bg-primary-800 p-4 mb-4 rounded-lg border"
>
<Details event={indexEvent} />
</div>
<!-- Publication sections/cards -->
{#each leaves as leaf, i}
{#if leaf == null}
<Alert class="flex space-x-2">
<ExclamationCircleOutline class="w-5 h-5" />
Error loading content. One or more events could not be loaded.
</Alert>
{:else}
{@const address = leaf.tagAddress()}
<PublicationSection
{rootAddress}
{leaves}
{address}
{publicationTree}
{toc}
ref={(el) => onPublicationSectionMounted(el, address)}
/>
{/if}
{/each}
<div class="flex justify-center my-4">
{#if isLoading}
<Button disabled color="primary">Loading...</Button>
{:else if !isDone}
<Button color="primary" onclick={() => loadMore(1)}>Show More</Button>
{:else}
<p class="text-gray-500 dark:text-gray-400">
You've reached the end of the publication.
</p>
{/if}
</div>
</div>
{/key}
{/if}
</div>
{/if}
{#if $publicationColumnVisibility.discussion}
<Sidebar
position="static"
class="sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto bg-primary-50 dark:bg-primary-1000
border border-primary-200 dark:border-primary-800 rounded"
>
<SidebarWrapper>
<SidebarGroup>
<div class="flex justify-between items-baseline">
<Heading tag="h1" class="h-leather !text-lg">Discussion</Heading>
<Button
class="btn-leather hidden sm:flex z-30 !p-1 bg-primary-50 dark:bg-gray-800"
outline
onclick={closeDiscussion}
>
<CloseOutline />
</Button>
<!-- Blog list -->
{#if $publicationColumnVisibility.blog}
<!-- Remove overflow-auto -->
<div
class={`flex flex-col p-4 space-y-4 max-w-xl flex-grow-1 ${isInnerActive() ? "discreet" : ""}`}
>
<div
class="card-leather bg-highlight dark:bg-primary-800 p-4 mb-4 rounded-lg border"
>
<Details event={indexEvent} />
</div>
<div class="flex flex-col space-y-4">
<!-- TODO
alternative for other publications and
when blog is not opened, but discussion is opened from the list
-->
{#if showBlogHeader() && currentBlog && currentBlogEvent}
<!-- List blog excerpts -->
{#each leaves as leaf, i}
{#if leaf}
<BlogHeader
rootId={currentBlog}
event={currentBlogEvent}
rootId={leaf.tagAddress()}
event={leaf}
onBlogUpdate={loadBlog}
active={true}
active={!isInnerActive()}
/>
{/if}
<div class="flex flex-col w-full space-y-4">
<Card class="ArticleBox card-leather w-full grid max-w-xl">
<div class="flex flex-col my-2">
<span>Unknown</span>
<span class="text-gray-500">1.1.1970</span>
</div>
<div class="flex flex-col flex-grow space-y-4">
This is a very intelligent comment placeholder that applies to
all the content equally well.
</div>
</Card>
</div>
</div>
</SidebarGroup>
</SidebarWrapper>
</Sidebar>
{/if}
{/each}
</div>
{/if}
{#if isInnerActive()}
{#key currentBlog}
<!-- Remove overflow-auto & sticky; allow page scroll -->
<div class="flex flex-col p-4 max-w-3xl flex-grow-2">
<!-- ...existing code... -->
</div>
{/key}
{/if}
</div>
{#if $publicationColumnVisibility.discussion}
<Sidebar
class="z-10 ml-4 bg-transparent sticky top-[162px] h-[calc(100vh-165px)] overflow-y-auto
border border-s-4 rounded border-primary-200 dark:border-primary-800
dark:bg-primary-1000"
>
<SidebarWrapper>
<SidebarGroup>
<div class="flex justify-between items-baseline">
<Heading tag="h1" class="h-leather !text-lg">Discussion</Heading>
<Button
class="btn-leather hidden sm:flex z-30 !p-1 bg-primary-50 dark:bg-gray-800"
outline
onclick={closeDiscussion}
>
<CloseOutline />
</Button>
</div>
<div class="flex flex-col space-y-4">
<!-- TODO
alternative for other publications and
when blog is not opened, but discussion is opened from the list
-->
{#if showBlogHeader() && currentBlog && currentBlogEvent}
<BlogHeader
rootId={currentBlog}
event={currentBlogEvent}
onBlogUpdate={loadBlog}
active={true}
/>
{/if}
<div class="flex flex-col w-full space-y-4">
<Card class="ArticleBox card-leather w-full grid max-w-xl">
<div class="flex flex-col my-2">
<span>Unknown</span>
<span class="text-gray-500">1.1.1970</span>
</div>
<div class="flex flex-col flex-grow space-y-4">
This is a very intelligent comment placeholder that applies to
all the content equally well.
</div>
</Card>
</div>
</div>
</SidebarGroup>
</SidebarWrapper>
</Sidebar>
{/if}
</div>
</div>

2
src/lib/components/util/ArticleNav.svelte

@ -152,7 +152,7 @@ @@ -152,7 +152,7 @@
</script>
<nav
class="Navbar navbar-leather flex fixed top-[100px] sm:top-[92px] w-full min-h-[70px] px-2 sm:px-4 py-2.5 z-10 transition-transform duration-300 {isVisible
class="Navbar navbar-leather col-span-3 flex fixed top-[100px] sm:top-[92px] w-full min-h-[70px] px-2 sm:px-4 py-2.5 z-10 transition-transform duration-300 {isVisible
? 'translate-y-0'
: '-translate-y-full'}"
>

4
src/routes/new/compose/+page.svelte

@ -130,8 +130,8 @@ @@ -130,8 +130,8 @@
<title>Compose Note - Alexandria</title>
</svelte:head>
<!-- Main container with 75% width and centered -->
<div class="flex flex-col self-center items-center w-full px-2 space-y-4">
<!-- Main container with max 1024px width and centered -->
<div class="flex flex-col self-center items-center w-full max-w-[1024px] mx-auto px-2 space-y-4">
<Heading
tag="h1" class="h-leather mb-2">
Compose Notes

2
src/routes/profile/notifications/+page.svelte

@ -4,7 +4,7 @@ import { AAlert } from "$lib/a"; @@ -4,7 +4,7 @@ import { AAlert } from "$lib/a";
import { userStore } from "$lib/stores/userStore";
</script>
<div class="w-full max-w-3xl mx-auto mt-10 px-4">
<div class="flex flex-col w-full max-w-3xl mx-auto px-2 items-center gap-4">
{#if $userStore?.signedIn}
<Notifications />
{:else}

Loading…
Cancel
Save