Changeset 6117035 in Klonkt


Ignore:
Timestamp:
06/15/2026 04:02:17 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
11a6871
Parents:
33886fb
Message:

fix: post navigation over ALL posts incl. pinned (no more pinned-only stack)

A pinned post showed only the pinned-stack navigation at the bottom. Now
Newer/Older runs through all posts in canonical feed order: solo = pinned
first by rank, then by date (same as the homepage); hub = globally by date.
Pinned posts simply sit in the continuous sequence. Neighbours determined
by index in that ordered list. The separate pinned-stack navigation
(PREVIOUS PINNED / TOP / BOTTOM) has been removed.

Co-Authored-By: Claude <noreply@…>

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r33886fb r6117035  
    507507  const urlBaseFor = (p) => (isHub && p && p.site_slug) ? `/user/${p.site_slug}` : '';
    508508
    509   const prevPost = isHub
     509  // Newer/Older over ALLE posts, in de canonieke feed-volgorde — niet alleen de
     510  // pinned-stack. Solo: binnen de site, pinned eerst op rank, dan op datum
     511  // (zelfde volgorde als de homepage-feed). Hub: globaal op datum over alle
     512  // sites. De vorige positie in de lijst = "Newer" (← omhoog), de volgende =
     513  // "Older" (→ omlaag). Pinned posts zitten zo gewoon in de doorlopende reeks.
     514  const ordered = isHub
    510515    ? db.prepare(`
    511         SELECT p.slug, p.title, s.slug AS site_slug
     516        SELECT p.id, p.slug, p.title, s.slug AS site_slug
    512517        FROM posts p JOIN sites s ON s.id = p.site_id
    513         WHERE p.status = 'published' AND p.published_at < ? AND p.id != ?
    514         ORDER BY p.published_at DESC LIMIT 1
    515       `).get(post.published_at, post.id)
     518        WHERE p.status = 'published'
     519        ORDER BY p.published_at DESC
     520      `).all()
    516521    : db.prepare(`
    517         SELECT slug, title FROM posts
    518         WHERE site_id = ? AND status = 'published' AND published_at < ? AND id != ?
    519         ORDER BY published_at DESC LIMIT 1
    520       `).get(site.id, post.published_at, post.id);
    521 
    522   const nextPost = isHub
    523     ? db.prepare(`
    524         SELECT p.slug, p.title, s.slug AS site_slug
    525         FROM posts p JOIN sites s ON s.id = p.site_id
    526         WHERE p.status = 'published' AND p.published_at > ? AND p.id != ?
    527         ORDER BY p.published_at ASC LIMIT 1
    528       `).get(post.published_at, post.id)
    529     : db.prepare(`
    530         SELECT slug, title FROM posts
    531         WHERE site_id = ? AND status = 'published' AND published_at > ? AND id != ?
    532         ORDER BY published_at ASC LIMIT 1
    533       `).get(site.id, post.published_at, post.id);
    534   if (prevPost) prevPost._urlBase = urlBaseFor(prevPost);
    535   if (nextPost) nextPost._urlBase = urlBaseFor(nextPost);
     522        SELECT id, slug, title FROM posts
     523        WHERE site_id = ? AND status = 'published'
     524        ORDER BY (pinned = 0) ASC, pinned ASC, published_at DESC
     525      `).all(site.id);
     526  const _idx = ordered.findIndex((p) => p.id === post.id);
     527  const newerPost = _idx > 0 ? ordered[_idx - 1] : null;
     528  const olderPost = (_idx >= 0 && _idx < ordered.length - 1) ? ordered[_idx + 1] : null;
     529  if (newerPost) newerPost._urlBase = urlBaseFor(newerPost);
     530  if (olderPost) olderPost._urlBase = urlBaseFor(olderPost);
    536531
    537532  // ── Related posts: same-tag matching with recency fallback ─────
     
    588583  relatedPosts = relatedPosts.map(({ _overlap, tags, ...rest }) => ({ ...rest, _urlBase: urlBaseFor(rest) }));
    589584
    590   // ── Pinned navigation: prev/next pinned post ───────────────────
    591   // Only meaningful if the current post is pinned. We order by
    592   // published_at DESC (newest pinned first) — same as the homepage feed.
    593   // Pinned navigation: prev/next pinned post by RANK (not by date).
    594   // - prev (← back to) = post with smaller rank, i.e. higher in stack
    595   // - next (→ forward) = post with larger rank, i.e. lower in stack
    596   // BOVENAAN appears when current is rank 1 (no rank 0 above);
    597   // ONDERAAN appears when current is the highest rank (no further down).
    598   let prevPinnedPost = null;
    599   let nextPinnedPost = null;
    600   let pinnedTopOfStack = false;
    601   let pinnedBottomOfStack = false;
    602   if (post.pinned > 0) {
    603     // The rank one step UP the stack (towards #1)
    604     prevPinnedPost = db.prepare(`
    605       SELECT slug, title FROM posts
    606       WHERE site_id = ? AND status = 'published' AND pinned > 0
    607         AND pinned < ? AND id != ?
    608       ORDER BY pinned DESC LIMIT 1
    609     `).get(site.id, post.pinned, post.id) || null;
    610 
    611     // The rank one step DOWN the stack (away from #1)
    612     nextPinnedPost = db.prepare(`
    613       SELECT slug, title FROM posts
    614       WHERE site_id = ? AND status = 'published' AND pinned > 0
    615         AND pinned > ? AND id != ?
    616       ORDER BY pinned ASC LIMIT 1
    617     `).get(site.id, post.pinned, post.id) || null;
    618 
    619     pinnedTopOfStack    = !prevPinnedPost;  // already rank #1 (or nothing higher)
    620     pinnedBottomOfStack = !nextPinnedPost;  // nothing further down the stack
    621   }
    622 
    623585  renderPage(req, res, 'pages/post', {
    624586    post,
    625     prevPost,
    626     nextPost,
     587    newerPost,
     588    olderPost,
    627589    relatedPosts,
    628     prevPinnedPost,
    629     nextPinnedPost,
    630     pinnedTopOfStack,
    631     pinnedBottomOfStack,
    632590    comments: topLevel,
    633591    totalComments,
  • src/views/pages/post.ejs

    r33886fb r6117035  
    233233  <% } %>
    234234
    235   <%# ── Pinned navigation (only when current post is pinned) ───
    236       Two card-style links: "Vorige vastgepinde" / "Volgende vastgepinde".
    237       Edge-of-stack states show "← BOVENAAN — Nieuwste post" or the equivalent
    238       for the bottom. Layout mirrors v9 exactly. %>
    239   <% if (post.pinned) { %>
    240     <nav class="post-pinned-nav" aria-label="Pinned navigation">
    241       <%# LEFT card: post one step UP the pinned stack (towards #1).
    242           Uses prevPinnedPost which now means "smaller rank". %>
    243       <% if (prevPinnedPost) { %>
    244         <a class="post-pinned-card post-pinned-card--prev" href="<%= _base %>/<%= prevPinnedPost.slug %>"
    245            hx-get="<%= _base %>/<%= prevPinnedPost.slug %>?partial=1" hx-target="#pcms-main"
    246            hx-push-url="<%= _base %>/<%= prevPinnedPost.slug %>" hx-indicator="#pcms-loading">
    247           <span class="post-pinned-arrow" aria-hidden="true">←</span>
    248           <span class="post-pinned-body">
    249             <span class="post-pinned-label">📌 Vorige vastgepinde</span>
    250             <span class="post-pinned-title"><%= prevPinnedPost.title %></span>
    251             <span class="post-pinned-cta">Lees deze post →</span>
    252           </span>
    253         </a>
    254       <% } else if (pinnedTopOfStack) { %>
    255         <span class="post-pinned-card post-pinned-card--edge">
    256           <span class="post-pinned-edge-label">— BOVENAAN —</span>
    257           <span class="post-pinned-edge-title">Nieuwste post</span>
    258         </span>
    259       <% } %>
    260 
    261       <%# RIGHT card: post one step DOWN the pinned stack (away from #1).
    262           Uses nextPinnedPost which now means "larger rank". %>
    263       <% if (nextPinnedPost) { %>
    264         <a class="post-pinned-card post-pinned-card--next" href="<%= _base %>/<%= nextPinnedPost.slug %>"
    265            hx-get="<%= _base %>/<%= nextPinnedPost.slug %>?partial=1" hx-target="#pcms-main"
    266            hx-push-url="<%= _base %>/<%= nextPinnedPost.slug %>" hx-indicator="#pcms-loading">
    267           <span class="post-pinned-arrow" aria-hidden="true">→</span>
    268           <span class="post-pinned-body">
    269             <span class="post-pinned-label">📌 Volgende vastgepinde</span>
    270             <span class="post-pinned-title"><%= nextPinnedPost.title %></span>
    271             <span class="post-pinned-cta">← Lees deze post</span>
    272           </span>
    273         </a>
    274       <% } else if (pinnedBottomOfStack) { %>
    275         <span class="post-pinned-card post-pinned-card--edge">
    276           <span class="post-pinned-edge-label">— ONDERAAN —</span>
    277           <span class="post-pinned-edge-title">Oudste post</span>
    278         </span>
    279       <% } %>
    280     </nav>
    281   <% } %>
    282 
    283   <%# ── Chronological prev/next (kept for non-pinned posts) ──────
    284       For pinned posts the pinned-nav above replaces this. Non-pinned
    285       regular posts still get the simple older/newer pair. %>
    286   <% if (!post.pinned && (prevPost || nextPost)) { %>
     235  <%# ── Navigatie over ALLE posts (pinned + niet-pinned in de feed-volgorde) ──
     236      Newer links (← omhoog in de lijst), Older rechts (→ omlaag). Vervangt de
     237      vroegere pinned-only stack-navigatie: pinned posts zitten gewoon in de
     238      doorlopende reeks. .post-nav-prev = linker kolom, .post-nav-next = rechter. %>
     239  <% if (newerPost || olderPost) { %>
    287240    <nav class="post-nav">
    288       <%# Newer links, Older rechts (lijst nieuwste-eerst → naar rechts = ouder).
    289           .post-nav-prev = linker kolom (links uitgelijnd), .post-nav-next =
    290           rechter kolom (rechts uitgelijnd). %>
    291       <% if (nextPost) { %>
    292         <a class="post-nav-prev" href="<%= nextPost._urlBase || '' %>/<%= nextPost.slug %>"<% if (!nextPost._urlBase) { %>
    293            hx-get="/<%= nextPost.slug %>?partial=1" hx-target="#pcms-main"
    294            hx-push-url="/<%= nextPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
     241      <% if (newerPost) { %>
     242        <a class="post-nav-prev" href="<%= newerPost._urlBase || '' %>/<%= newerPost.slug %>"<% if (!newerPost._urlBase) { %>
     243           hx-get="/<%= newerPost.slug %>?partial=1" hx-target="#pcms-main"
     244           hx-push-url="/<%= newerPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
    295245          <span class="post-nav-label">← Newer</span>
    296           <span class="post-nav-title"><%= nextPost.title %></span>
     246          <span class="post-nav-title"><%= newerPost.title %></span>
    297247        </a>
    298248      <% } else { %><span></span><% } %>
    299       <% if (prevPost) { %>
    300         <a class="post-nav-next" href="<%= prevPost._urlBase || '' %>/<%= prevPost.slug %>"<% if (!prevPost._urlBase) { %>
    301            hx-get="/<%= prevPost.slug %>?partial=1" hx-target="#pcms-main"
    302            hx-push-url="/<%= prevPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
     249      <% if (olderPost) { %>
     250        <a class="post-nav-next" href="<%= olderPost._urlBase || '' %>/<%= olderPost.slug %>"<% if (!olderPost._urlBase) { %>
     251           hx-get="/<%= olderPost.slug %>?partial=1" hx-target="#pcms-main"
     252           hx-push-url="/<%= olderPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
    303253          <span class="post-nav-label">Older →</span>
    304           <span class="post-nav-title"><%= prevPost.title %></span>
     254          <span class="post-nav-title"><%= olderPost.title %></span>
    305255        </a>
    306256      <% } %>
Note: See TracChangeset for help on using the changeset viewer.