source: Klonkt/src/views/pages/home.ejs@ 976d36d

main
Last change on this file since 976d36d was 8afbdd6, checked in by roboburr <roboburr@…>, 3 months ago

feat: viewer role + artists directory + Klonkt Hub Beta rebrand

Viewer role (replaces the separate view-mode/readonly toggle):

  • 'kijker' is now a real role (VALID_ROLES) selectable in Admin. May view EVERYTHING including Admin, but cannot modify anything.
  • isViewer(user) (= role kijker or legacy readonly flag) is the source; requireGod/requireSiteManager(BySlug) let a viewer through (viewing), the global guard 403s every write. Existing readonly accounts are migrated on each role change (readonly=0).
  • Write leaks via GET patched: /prutter/new (INSERT) blocks for viewers, /prutter/:id skips markAsRead (UPDATE); WS upgrade rejects viewers (the HTTP guard doesn't cover WebSockets).
  • Clean "Viewer mode" page (viewer-blocked) instead of raw 403 text; styled sticky banner; account page shows read-only UI instead of an upload button that silently 403s. canMutate hides write buttons.

Scalability (>50 artists):

  • Hub home shows max 24 (most active first) + "All N artists ->".
  • New searchable, paginated /artiesten directory (hub only).
  • 'user' + 'artiesten' reserved as slugs.

Rebrand PrutFolio v1 -> Klonkt Hub Beta (footer, PWA manifest, account/
admin texts, default page title, startup, README; internal package +
PWA id 'prutfolio' remain for stability).

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

  • Property mode set to 100644
File size: 2.0 KB
RevLine 
[7bc636b]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];
[b94c08e]13const _base = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
[7bc636b]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>Hier is het nog stil.</h1>
26 <p>Nog geen posts. Spannend.</p>
[8afbdd6]27 <% if (user && canMutate && permissions.canCreatePost(user, site)) { %>
[7bc636b]28 <p style="margin-top:2rem">
[b94c08e]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">
[7bc636b]32 Schrijf je eerste post →
33 </a>
34 </p>
35 <% } %>
36 </div>
37 <% } else { %>
38 <ul class="post-list feed-timeline-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="Grid-weergave">
50 <div class="grid-tiles">
51 <% allPosts.forEach(function(post) { %>
52 <%- include('../partials/post-tile', { post: post }) %>
53 <% }); %>
54 </div>
55</section>
56<% } %>
Note: See TracBrowser for help on using the repository browser.