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