source: Klonkt/src/views/pages/home.ejs@ 024f4f8

main
Last change on this file since 024f4f8 was 520e477, checked in by Robin <roboburr@…>, 7 weeks ago

Feature: Load more on Solo + Cirkel, page 72 (klonkt-demo-r9u, slice 3/4)

The home feed (Solo) and the Cirkel feed now page in 72s instead of a
hard 30/80 cap. Both render two containers (list + grid, CSS-toggled),
so the append fragment (partials/home-append) sends the post-cards as
the primary beforeend swap into #post-list and OOB-appends the same
posts as tiles into #grid-tiles. htmx 1.9.12 unwraps the OOB wrapper's
children on a positional swap, so the tiles land as direct grid items
(the display:contents wrapper is a belt-and-braces fallback). The
button lives once below both views and OOB-replaces itself with the
next offset, dropping on the last page. Pinned posts stay on page 1
only. getCirkelPosts gains an offset arg; FEED_PAGE hoisted to the top
of posts.js.

Browser-verified both feeds: 72 -> 144 -> 150 in list AND grid, then
the button disappears.

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

  • Property mode set to 100644
File size: 2.3 KB
Line 
1<%
2// Homepage — feed of posts.
3//
4// Renders BOTH a timeline view (.post-list, default) AND a grid view
5// (.feed-grid, square Instagram-style tiles). CSS toggles between the
6// two based on body[data-feed-view="timeline"|"grid"]. This mirrors the
7// v9 pattern in lib/template-content.php so the same view-switcher works.
8//
9// Pinned posts sort first inside the timeline list; they are not given a
10// separate "Pinned" header (v9 just lets order speak for itself + a ★ chip).
11
12const allPosts = [...pinnedPosts, ...posts];
13const _base = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
14%>
15
16<%# View switcher used to be rendered here; moved to shell.ejs (above
17 #pcms-main) so it survives HTMX swaps and is visible on every
18 non-admin page. %>
19
20<!-- ========== TIMELINE ========== -->
21<div class="container feed-timeline">
22
23 <% if (allPosts.length === 0) { %>
24 <div class="empty">
25 <h1><%= t('phome.empty_title') %></h1>
26 <p><%= t('phome.empty_sub') %></p>
27 <% if (user && canMutate && permissions.canCreatePost(user, site)) { %>
28 <p style="margin-top:2rem">
29 <a class="btn" href="<%= _base %>/posts/new"
30 hx-get="<%= _base %>/posts/new?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
31 hx-push-url="<%= _base %>/posts/new" hx-indicator="#pcms-loading">
32 <%= t('phome.write_first') %> →
33 </a>
34 </p>
35 <% } %>
36 </div>
37 <% } else { %>
38 <ul class="post-list feed-timeline-list" id="post-list">
39 <% allPosts.forEach(function(post) { %>
40 <%- include('../partials/post-card', { post: post }) %>
41 <% }); %>
42 </ul>
43 <% } %>
44
45</div>
46
47<!-- ========== GRID (only visible when body[data-feed-view="grid"]) ========== -->
48<% if (allPosts.length > 0) { %>
49<section class="feed-grid container" aria-label="<%= t('phome.grid_view') %>">
50 <div class="grid-tiles" id="grid-tiles">
51 <% allPosts.forEach(function(post) { %>
52 <%- include('../partials/post-tile', { post: post }) %>
53 <% }); %>
54 </div>
55</section>
56<% } %>
57<% if (typeof hasMore !== 'undefined' && allPosts.length > 0) { %>
58<div class="container feed-more-wrap">
59 <%- include('../partials/load-more', { hasMore: hasMore, nextOffset: nextOffset, moreBase: moreBase, moreTarget: '#post-list', morePath: '/' }) %>
60</div>
61<% } %>
Note: See TracBrowser for help on using the repository browser.