source: Klonkt/src/views/pages/home.ejs@ 22d2dba5

main
Last change on this file since 22d2dba5 was 22d2dba5, checked in by Claude (agent) <aiclaude@…>, 3 weeks ago

wip paginamodus

  • Property mode set to 100644
File size: 5.4 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<%# FEP-7628 slice 3: this account moved. The signpost comes FIRST, before
21 any post: a visitor should not scroll a dead feed to find out we left.
22 typeof-guard because an old route may render this template for one
23 request right after a deploy (view cache fills on first hit). %>
24<% if (typeof movedTo !== 'undefined' && movedTo) { %>
25 <div class="container">
26 <aside class="moved-banner">
27 <p class="moved-banner-lead"><%= t('phome.moved_lead') %></p>
28 <a class="moved-banner-link" href="<%= movedTo %>" rel="me noopener"><%= movedToLabel || movedTo %></a>
29 <p class="moved-banner-hint"><%= t('phome.moved_hint') %></p>
30 </aside>
31 </div>
32<% } %>
33
34<!-- ========== TIMELINE ========== -->
35<div class="container feed-timeline">
36
37 <% if (allPosts.length === 0) { %>
38 <div class="empty">
39 <h1><%= t('phome.empty_title') %></h1>
40 <p><%= t('phome.empty_sub') %></p>
41 <% if (user && canMutate && permissions.canCreatePost(user, site)) { %>
42 <p style="margin-top:2rem">
43 <a class="btn" href="<%= _base %>/posts/new"
44 hx-get="<%= _base %>/posts/new?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
45 hx-push-url="<%= _base %>/posts/new" hx-indicator="#pcms-loading">
46 <%= t('phome.write_first') %> →
47 </a>
48 </p>
49 <% } %>
50 </div>
51 <% } else { %>
52 <ul class="post-list feed-timeline-list" id="post-list">
53 <% allPosts.forEach(function(post) { %>
54 <%- include('../partials/post-card', { post: post }) %>
55 <% }); %>
56 </ul>
57 <% } %>
58
59</div>
60
61<!-- ========== LEZEN (alleen zichtbaar bij body[data-feed-view="reader"]) ==========
62 Hetzelfde stel berichten, maar heel: één per scherm, met de grenzen door
63 CSS-snapping. Geen eigen route en geen eigen shell -- de balken blijven
64 staan, want je bent nog gewoon op de feed en moet terug kunnen schakelen.
65 Leeg? Dan valt de lege staat van de tijdlijn hierboven in beeld; deze
66 sectie rendert dan niet. -->
67<% if (typeof readerItems !== 'undefined' && readerItems && readerItems.length) { %>
68<section class="feed-reader" aria-label="<%= t('switch.reader') %>">
69 <%# Terug naar boven. Staat IN de HTML en niet in JavaScript, zodat hij er ook
70 is als de module niet laadt -- dan doet hij niets, maar hij springt ook niet
71 opeens in beeld. Verschijnt pas als je ver genoeg bent (mod/read.js). %>
72 <%# Een bericht omhoog of omlaag. Alleen in paginamodus zichtbaar (CSS). %>
73 <%# Twee echte balken over de volle breedte. Tikzones zonder zichtbaar element
74 werkten niet: de onderste strook ligt onder de mini-speler en de tabbalk,
75 en die vangen de tik voordat de leesstroom hem ziet. Een balk kan daar wel
76 bovenop. %>
77 <button type="button" class="read-bar read-bar--top" id="read-prev" aria-label="<%= t('read.prev') %>">
78 <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="18 15 12 9 6 15"/></svg>
79 </button>
80 <button type="button" class="read-bar read-bar--bottom" id="read-next-nav" aria-label="<%= t('read.next') %>">
81 <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
82 </button>
83 <button type="button" id="read-top" class="read-top" aria-label="<%= t('read.to_top') %>" title="<%= t('read.to_top') %>">
84 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>
85 </button>
86 <div class="read-stream" id="read-stream" data-base="<%= _base %>">
87 <% readerItems.forEach(function(it) { %>
88 <%- include('../partials/read-article', { post: it.post, entry: it.entry }) %>
89 <% }); %>
90 </div>
91</section>
92<% } %>
93
94<!-- ========== GRID (only visible when body[data-feed-view="grid"]) ========== -->
95<% if (allPosts.length > 0) { %>
96<section class="feed-grid container" aria-label="<%= t('phome.grid_view') %>">
97 <div class="grid-tiles" id="grid-tiles">
98 <% allPosts.forEach(function(post) { %>
99 <%- include('../partials/post-tile', { post: post }) %>
100 <% }); %>
101 </div>
102</section>
103<% } %>
104<% if (typeof hasMore !== 'undefined' && allPosts.length > 0) { %>
105<div class="container feed-more-wrap">
106 <%- include('../partials/load-more', { hasMore: hasMore, nextOffset: nextOffset, moreBase: moreBase, moreTarget: '#post-list', morePath: '/' }) %>
107</div>
108<% } %>
Note: See TracBrowser for help on using the repository browser.