source: Klonkt/src/views/pages/news.ejs@ 52fc278

main
Last change on this file since 52fc278 was 52fc278, checked in by roboburr <roboburr@…>, 5 weeks ago

De Krant en de downloadpagina, met het data-kanaal in gebruik (shaer-bqr, stap 3d)

De eerste twee die servergegevens nodig hadden. news gebruikte twee vertalingen,
download een berekende URL.

EEN ONTWERPCORRECTIE die het bouwen opleverde: de gegevens horen gedeclareerd te
worden waar ze BEKEND zijn, niet door de route geregen. fileUrl wordt in de
template zelf berekend, en t() bestaat in een route helemaal niet. Dus geeft de
pagina zijn eigen gegevens mee aan de include:

include('../partials/page-data', { pageData: { fileUrl: fileUrl } })

De route noemt alleen nog de module. Dat scheelt in elke volgende pagina een
omweg langs de route, en het houdt de gegevens naast de plek waar ze vandaan
komen.

Gecontroleerd dat er in GEEN enkele module nog een EJS-tag staat -- dat is de
enige manier om zeker te weten dat er niets stilzwijgend is blijven hangen dat
straks als letterlijke tekst in een statisch bestand belandt.

Templates compileren, suite 565/565.

  • Property mode set to 100644
File size: 11.6 KB
Line 
1<div class="tl-wrap">
2 <%- include('../partials/fedi-tabs', { active: 'feed' }) %>
3 <div class="tl-titlebar">
4 <h1 class="tl-title"><%= t('tl.title') %></h1>
5 <button type="button" id="tl-paste-btn" class="tl-paste-btn" title="<%= t('fedi.remote_interact') %>" aria-label="<%= t('fedi.remote_interact') %>">
6 <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
7 </button>
8 </div>
9 <p class="tl-lead"><%= t('tl.lead') %></p>
10
11 <div class="tl-paste" id="tl-paste">
12 <div class="tl-paste-card" role="dialog" aria-label="<%= t('fedi.remote_interact') %>">
13 <button type="button" class="tl-paste-x" aria-label="<%= t('fedi.cancel') %>">&times;</button>
14 <h3 class="tl-paste-title"><%= t('fedi.remote_interact') %></h3>
15 <input type="url" class="tl-paste-input" inputmode="url" autocomplete="off" autocapitalize="none" spellcheck="false" placeholder="<%= t('tl.paste_ph') %>">
16 <div class="tl-paste-actions">
17 <button type="button" class="tl-paste-cancel"><%= t('fedi.cancel') %></button>
18 <button type="button" class="tl-paste-go"><%= t('tl.paste_go') %></button>
19 </div>
20 </div>
21 </div>
22 <style>
23 .tl-titlebar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
24 .tl-boost-by { display: flex; align-items: center; gap: .35rem; font-size: .8rem; color: var(--ink-soft); margin: 0 0 .45rem .2rem; }
25 .tl-boost-by svg { color: #16a34a; flex: 0 0 auto; }
26 .tl-boost-by strong { color: var(--ink); font-weight: 600; }
27 .tl-paste-btn { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px;
28 border: 1px solid var(--rule); border-radius: 999px; background: var(--paper-2); color: var(--ink-soft); cursor: pointer; transition: color .15s, border-color .15s, background .15s; }
29 .tl-paste-btn:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 50%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
30 .tl-paste { position: fixed; inset: 0; z-index: 2147483601; display: none; align-items: center; justify-content: center; padding: 1rem; background: rgba(0,0,0,.55); }
31 .tl-paste.is-open { display: flex; }
32 .tl-paste-card { position: relative; width: 100%; max-width: 460px; background: var(--paper); color: var(--ink); border: 1px solid var(--rule);
33 border-radius: 16px; padding: 1.4rem 1.4rem 1.2rem; box-shadow: 0 18px 50px rgba(0,0,0,.4); }
34 .tl-paste-x { position: absolute; top: .5rem; right: .6rem; width: 2rem; height: 2rem; border: 0; border-radius: 999px; background: transparent; color: var(--ink-soft); font-size: 1.4rem; line-height: 1; cursor: pointer; }
35 .tl-paste-title { margin: 0 0 .8rem; font-size: 1.1rem; }
36 .tl-paste-input { width: 100%; box-sizing: border-box; padding: .6rem .8rem; border: 1.5px solid var(--rule); border-radius: 10px; background: var(--paper-2); color: var(--ink); font: inherit; font-size: .95rem; }
37 .tl-paste-input:focus { outline: none; border-color: var(--accent); }
38 .tl-paste-actions { display: flex; justify-content: flex-end; gap: .6rem; margin-top: 1rem; }
39 .tl-paste-actions button { padding: .5rem 1.1rem; border-radius: 999px; font: inherit; font-weight: 600; font-size: .88rem; cursor: pointer; border: 0; }
40 .tl-paste-cancel { background: transparent; border: 1.5px solid var(--rule); color: var(--ink); }
41 .tl-paste-go { background: var(--accent); color: var(--paper); }
42 </style>
43 <%# Het script staat in assets/js/mod/news.js; de servergegevens gaan via partials/page-data.ejs (shaer-bqr). %>
44 <% if (typeof success !== 'undefined' && success) { %><div class="alert alert-success"><%= success %></div><% } %>
45 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error %></div><% } %>
46
47 <% if (!timeline || !timeline.length) { %>
48 <div class="tl-empty">
49 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>
50 <p><%= t('tl.empty') %></p>
51 </div>
52 <% } else { %>
53 <ol class="tl-feed" id="tl-feed">
54 <% timeline.forEach(function(p){ %>
55 <%- include('../partials/tl-item', { p: p }) %>
56 <% }); %>
57 </ol>
58 <%- include('../partials/load-more', { hasMore: hasMore, nextOffset: nextOffset, moreBase: moreBase, moreTarget: '#tl-feed', morePath: '/news' }) %>
59 <% } %>
60</div>
61
62<style>
63 .tl-wrap { max-width: 640px; margin: 1rem auto 3rem; padding: 0 1rem; }
64 .tl-title { margin: 0 0 .15rem; font-size: clamp(1.5rem, 4vw, 1.8rem); }
65 .tl-lead { color: var(--ink-soft, #888); margin: 0 0 1.5rem; }
66 .tl-empty { text-align: center; color: var(--ink-soft, #888); margin: 3rem auto; }
67 .tl-empty svg { width: 44px; height: 44px; color: color-mix(in srgb, var(--accent, #888) 60%, transparent); margin: 0 auto .75rem; display: block; }
68
69 .tl-feed { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 1rem; }
70 .tl-item { padding: 1.1rem 1.15rem; border-radius: 16px;
71 border: 1px solid color-mix(in srgb, var(--ink, #000) 8%, transparent);
72 background: color-mix(in srgb, var(--ink, #000) 2.5%, transparent);
73 transition: border-color .15s ease, box-shadow .15s ease; }
74 .tl-item:hover { border-color: color-mix(in srgb, var(--accent, #888) 32%, transparent);
75 box-shadow: 0 2px 14px color-mix(in srgb, var(--ink, #000) 6%, transparent); }
76
77 .tl-head { display: flex; align-items: center; gap: .65rem; margin: 0 0 .65rem; }
78 .tl-avatar { flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%; overflow: hidden;
79 display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 1.1rem;
80 background: color-mix(in srgb, var(--accent, #888) 22%, transparent); color: var(--accent, #555);
81 box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #888) 18%, transparent); }
82 .tl-avatar img { width: 100%; height: 100%; object-fit: cover; background: #fff; }
83 .tl-id { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
84 .tl-author { font-weight: 700; color: var(--ink, inherit); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
85 .tl-author:hover { text-decoration: underline; }
86 .tl-handle { color: var(--ink-soft, #888); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
87 .tl-time { color: var(--ink-soft, #999); font-size: .78rem; flex: 0 0 auto; align-self: flex-start; white-space: nowrap; }
88
89 /* .tl-content, .tl-quote* and .tl-media* now live in partials/shared-styles,
90 next to partials/note-body: the markup is shared with Berichten and the
91 Guardian PWA, so the styling has to be too. What stays here is Krant-only. */
92 /* Long posts collapse to a max height with a fade + "read more" (added by JS only when it overflows). */
93 .tl-content.tl-clamp { max-height: 20em; overflow: hidden;
94 -webkit-mask-image: linear-gradient(180deg, #000 72%, transparent);
95 mask-image: linear-gradient(180deg, #000 72%, transparent); }
96 .tl-readmore { display: inline-block; margin: .15rem 0 .1rem; padding: .15rem 0;
97 background: none; border: 0; color: var(--accent, #06c); font: inherit; font-weight: 600;
98 font-size: .85rem; cursor: pointer; }
99 .tl-readmore:hover { text-decoration: underline; }
100
101 .tl-poll { margin: .75rem 0 0; display: flex; flex-direction: column; gap: 8px; }
102 .tl-poll-form { display: flex; flex-direction: column; gap: 8px; }
103 .tl-poll-choice { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--line, rgba(128,128,128,.3)); border-radius: 10px; cursor: pointer; }
104 .tl-poll-choice:hover { border-color: var(--accent); }
105 .tl-poll-choice input { accent-color: var(--accent); }
106 .tl-poll-btn { align-self: flex-start; margin-top: 2px; }
107 .tl-poll-res { position: relative; padding: 9px 12px; border-radius: 10px; overflow: hidden; background: var(--paper-2, rgba(128,128,128,.08)); display: flex; align-items: center; gap: 8px; }
108 .tl-poll-fill { position: absolute; inset: 0 auto 0 0; background: color-mix(in srgb, var(--accent) 22%, transparent); z-index: 0; }
109 .tl-poll-res.is-mine .tl-poll-fill { background: color-mix(in srgb, var(--accent) 40%, transparent); }
110 .tl-poll-name { position: relative; z-index: 1; flex: 1; font-size: .95rem; }
111 .tl-poll-pct { position: relative; z-index: 1; font-variant-numeric: tabular-nums; font-weight: 500; }
112 .tl-poll-foot { font-size: .82rem; color: var(--ink-soft, #888); }
113
114 .tl-embed { margin: .75rem 0 0; border-radius: 12px; overflow: hidden; background: var(--paper-2, #111); }
115 .tl-embed-frame { width: 100%; border: 0; display: block; aspect-ratio: 16 / 9; }
116 .tl-embed-spotify { aspect-ratio: auto; height: 152px; }
117 .tl-embed-sc { aspect-ratio: auto; height: 166px; }
118 .tl-embed-klonkt { aspect-ratio: auto; height: 180px; background: var(--paper, #fff); }
119 .tl-embed-bandcamp { aspect-ratio: auto; height: 470px; }
120 .tl-embed-apple { aspect-ratio: auto; height: 175px; }
121 .tl-embed-open { display: inline-block; margin: .45rem .9rem 0 0; font-size: .82rem; font-weight: 600; color: var(--accent); text-decoration: none; }
122 .tl-embed-open:hover { text-decoration: underline; }
123
124 .tl-orig { display: inline-block; margin: .7rem 0 0; font-size: .82rem; color: var(--accent, #06c); text-decoration: none; }
125 .tl-orig:hover { text-decoration: underline; }
126
127 /* Uniform circular action buttons with coloured icons (no emoji). */
128 .tl-actions { display: flex; gap: .5rem; margin-top: .9rem; align-items: center; }
129 .tl-act-form { margin: 0; display: inline-flex; }
130 .tl-act { width: 36px; height: 36px; flex: 0 0 36px; border-radius: 50%; padding: 0; box-sizing: border-box;
131 display: inline-flex; align-items: center; justify-content: center;
132 border: 1px solid color-mix(in srgb, var(--ink, #000) 12%, transparent);
133 background: color-mix(in srgb, var(--ink, #000) 3%, transparent);
134 color: var(--ink-soft, #888); cursor: pointer; -webkit-tap-highlight-color: transparent;
135 transition: background .12s, border-color .12s, transform .1s; }
136 .tl-act svg { width: 18px; height: 18px; display: block; }
137 .tl-act:active { transform: scale(.9); }
138 .tl-act-like svg { color: #e8b04b; }
139 .tl-act-like:hover { background: color-mix(in srgb, #e8b04b 15%, transparent); border-color: color-mix(in srgb, #e8b04b 50%, transparent); }
140 .tl-act-like.is-on { background: color-mix(in srgb, #e8b04b 18%, transparent); border-color: color-mix(in srgb, #e8b04b 60%, transparent); }
141 .tl-act-boost svg { color: #2fa85a; }
142 .tl-act-boost:hover { background: color-mix(in srgb, #2fa85a 15%, transparent); border-color: color-mix(in srgb, #2fa85a 50%, transparent); }
143 .tl-act-boost.is-on { background: color-mix(in srgb, #2fa85a 18%, transparent); border-color: color-mix(in srgb, #2fa85a 60%, transparent); }
144 .tl-act-reply svg { color: var(--accent, #06c); }
145 .tl-act-reply:hover { background: color-mix(in srgb, var(--accent, #888) 14%, transparent); border-color: color-mix(in srgb, var(--accent, #888) 50%, transparent); }
146 .tl-act-block svg { color: #e0524d; }
147 .tl-act-block:hover { background: color-mix(in srgb, #d9534f 14%, transparent); border-color: color-mix(in srgb, #d9534f 50%, transparent); }
148</style>
149<%- include('../partials/page-data', { pageData: { readMore: t('tl.read_more'), showLess: t('tl.show_less') } }) %>
Note: See TracBrowser for help on using the repository browser.