Changeset d54dade in Klonkt


Ignore:
Timestamp:
06/15/2026 03:39:35 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
52badd3
Parents:
7f46817d
Message:

fix: hub mode — related posts + Newer/Older across ALL users

In hub mode "Related posts" and the Newer/Older navigation only pulled from
the current site; now from all sites combined (newest->oldest), with links to
/user/<site-slug>/<post-slug>. Cross-user links use full navigation (the
chrome/header differs per artist); solo + same-context keep the HTMX partial.
Pinned nav stays per-site but now gets the correct siteUrlBase prefix.
Solo mode unchanged.

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

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r7f46817d rd54dade  
    501501  // Prev / next chronological (kept for back-compat — "post-nav" feature
    502502  // below the article still uses these as a simple linear navigation).
    503   const prevPost = db.prepare(`
    504     SELECT slug, title FROM posts
    505     WHERE site_id = ? AND status = 'published' AND published_at < ? AND id != ?
    506     ORDER BY published_at DESC LIMIT 1
    507   `).get(site.id, post.published_at, post.id);
    508 
    509   const nextPost = db.prepare(`
    510     SELECT slug, title FROM posts
    511     WHERE site_id = ? AND status = 'published' AND published_at > ? AND id != ?
    512     ORDER BY published_at ASC LIMIT 1
    513   `).get(site.id, post.published_at, post.id);
     503  // Hub-modus: Gerelateerde posts + Newer/Older trekken uit ALLE users (alle
     504  // sites), nieuwste->oudste. Solo-modus: binnen de huidige site (oud gedrag).
     505  const isHub = res.locals.tenancy === 'hub';
     506  // Per-post URL-basis: in hub wijst een link naar /user/<site-slug>/<post-slug>.
     507  const urlBaseFor = (p) => (isHub && p && p.site_slug) ? `/user/${p.site_slug}` : '';
     508
     509  const prevPost = isHub
     510    ? db.prepare(`
     511        SELECT p.slug, p.title, s.slug AS site_slug
     512        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)
     516    : 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);
    514536
    515537  // ── Related posts: same-tag matching with recency fallback ─────
    516538  // Fetch ~50 candidates, score by tag overlap, take top 3.
    517539  // Excluding self via `id != ?`.
    518   const candidates = db.prepare(`
    519     SELECT id, slug, title, cover_image_url, published_at, tags
    520     FROM posts
    521     WHERE site_id = ? AND status = 'published' AND id != ?
    522     ORDER BY published_at DESC
    523     LIMIT 50
    524   `).all(site.id, post.id);
     540  const candidates = isHub
     541    ? db.prepare(`
     542        SELECT p.id, p.slug, p.title, p.cover_image_url, p.published_at, p.tags, s.slug AS site_slug
     543        FROM posts p JOIN sites s ON s.id = p.site_id
     544        WHERE p.status = 'published' AND p.id != ?
     545        ORDER BY p.published_at DESC LIMIT 50
     546      `).all(post.id)
     547    : db.prepare(`
     548        SELECT id, slug, title, cover_image_url, published_at, tags
     549        FROM posts
     550        WHERE site_id = ? AND status = 'published' AND id != ?
     551        ORDER BY published_at DESC LIMIT 50
     552      `).all(site.id, post.id);
    525553
    526554  // Parse tags JSON safely; missing/malformed → empty array.
     
    558586  }
    559587  // Strip the internal _overlap field before sending to view
    560   relatedPosts = relatedPosts.map(({ _overlap, tags, ...rest }) => rest);
     588  relatedPosts = relatedPosts.map(({ _overlap, tags, ...rest }) => ({ ...rest, _urlBase: urlBaseFor(rest) }));
    561589
    562590  // ── Pinned navigation: prev/next pinned post ───────────────────
  • src/views/pages/post.ejs

    r7f46817d rd54dade  
    212212        <% relatedPosts.forEach(function(rp) { %>
    213213          <li class="post-related-card">
    214             <a href="/<%= rp.slug %>"
     214            <a href="<%= rp._urlBase || '' %>/<%= rp.slug %>"<% if (!rp._urlBase) { %>
    215215               hx-get="/<%= rp.slug %>?partial=1" hx-target="#pcms-main"
    216                hx-push-url="/<%= rp.slug %>" hx-indicator="#pcms-loading">
     216               hx-push-url="/<%= rp.slug %>" hx-indicator="#pcms-loading"<% } %>>
    217217              <% if (rp.cover_image_url) { %>
    218218                <span class="post-related-cover"
     
    242242          Uses prevPinnedPost which now means "smaller rank". %>
    243243      <% if (prevPinnedPost) { %>
    244         <a class="post-pinned-card post-pinned-card--prev" href="/<%= prevPinnedPost.slug %>"
    245            hx-get="/<%= prevPinnedPost.slug %>?partial=1" hx-target="#pcms-main"
    246            hx-push-url="/<%= prevPinnedPost.slug %>" hx-indicator="#pcms-loading">
     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">
    247247          <span class="post-pinned-arrow" aria-hidden="true">←</span>
    248248          <span class="post-pinned-body">
     
    262262          Uses nextPinnedPost which now means "larger rank". %>
    263263      <% if (nextPinnedPost) { %>
    264         <a class="post-pinned-card post-pinned-card--next" href="/<%= nextPinnedPost.slug %>"
    265            hx-get="/<%= nextPinnedPost.slug %>?partial=1" hx-target="#pcms-main"
    266            hx-push-url="/<%= nextPinnedPost.slug %>" hx-indicator="#pcms-loading">
     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">
    267267          <span class="post-pinned-arrow" aria-hidden="true">→</span>
    268268          <span class="post-pinned-body">
     
    287287    <nav class="post-nav">
    288288      <% if (prevPost) { %>
    289         <a class="post-nav-prev" href="/<%= prevPost.slug %>"
     289        <a class="post-nav-prev" href="<%= prevPost._urlBase || '' %>/<%= prevPost.slug %>"<% if (!prevPost._urlBase) { %>
    290290           hx-get="/<%= prevPost.slug %>?partial=1" hx-target="#pcms-main"
    291            hx-push-url="/<%= prevPost.slug %>" hx-indicator="#pcms-loading">
     291           hx-push-url="/<%= prevPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
    292292          <span class="post-nav-label">← Older</span>
    293293          <span class="post-nav-title"><%= prevPost.title %></span>
     
    295295      <% } else { %><span></span><% } %>
    296296      <% if (nextPost) { %>
    297         <a class="post-nav-next" href="/<%= nextPost.slug %>"
     297        <a class="post-nav-next" href="<%= nextPost._urlBase || '' %>/<%= nextPost.slug %>"<% if (!nextPost._urlBase) { %>
    298298           hx-get="/<%= nextPost.slug %>?partial=1" hx-target="#pcms-main"
    299            hx-push-url="/<%= nextPost.slug %>" hx-indicator="#pcms-loading">
     299           hx-push-url="/<%= nextPost.slug %>" hx-indicator="#pcms-loading"<% } %>>
    300300          <span class="post-nav-label">Newer →</span>
    301301          <span class="post-nav-title"><%= nextPost.title %></span>
Note: See TracChangeset for help on using the changeset viewer.