source: Klonkt/src/views/pages/messages.ejs@ 6089c53

main
Last change on this file since 6089c53 was 439f095, checked in by Robin Genis <roboburr@…>, 6 weeks ago

De guardians-lijst verhuist van Berichten naar Connect

Connect is de pagina die vertelt met wie je verbonden bent, en een guardian is
precies de verbinding die een kind nooit zou moeten hoeven zoeken. In Berichten
stond hij boven een stroom meldingen, waar hij bij elk bezoek langsschuift; op
Connect staat hij bij de andere relaties, met een eigen kader omdat het geen
mensen zijn die je zelf gekozen hebt te volgen.

De stippen en de labels gaan mee zoals ze waren: beschikbaar, afwezig tot een
datum, offline. In Berichten blijft het guardianship-aanbod staan, want dat is
wel een bericht: er wordt iets aan je gevraagd.

Changed files:
src/routes/posts.js

  • myGuardians van /messages naar /connect, met de handle-helper mee; de helper in /messages was daarmee dood en is weg

src/views/pages/messages.ejs

  • het blok en zijn opmaak eruit

src/views/pages/connect.ejs

  • de guardians-sectie bovenaan, met eigen opmaak

remarks: in de browser nagelopen, ook op 375px: drie guardians in drie staten
op Connect, Berichten houdt alleen nog het aanbod. 276 tests groen.

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

  • Property mode set to 100644
File size: 12.7 KB
Line 
1<div class="msg-wrap">
2 <%- include('../partials/fedi-tabs', { active: 'berichten' }) %>
3 <h1 class="msg-title"><%= t('msg.title') %></h1>
4 <% if (typeof success !== 'undefined' && success) { %><div class="alert alert-success"><%= success === 'guardian_accepted' ? t('msg.guard_accepted') : (success === 'guardian_rejected' ? t('msg.guard_rejected') : (success === 'wave_sent' ? t('msg.wave_sent') : success)) %></div><% } %>
5 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error === 'guardianship' ? t('msg.guard_failed') : error %></div><% } %>
6
7 <%# FEP-633c: a pending guardianship offer is a special message: the kid
8 answers here (accept/reject travels the same C2S pipeline as the apps). %>
9 <% if (typeof guardianOffers !== 'undefined' && guardianOffers.length) { %>
10 <% guardianOffers.forEach(function(o){ %>
11 <div class="alert" style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;border-left:3px solid #ff6b35;">
12 <span style="font-size:1.4em;">&#128735;</span>
13 <div style="flex:1;min-width:200px;">
14 <strong><%= o['shaer:candidateHandle'] || o['shaer:candidate'] %></strong><br>
15 <span><%= t('msg.guard_offer') %></span>
16 </div>
17 <form method="post" action="<%= (typeof moreBase !== 'undefined' ? moreBase : '') %>/messages/guardianship" style="display:flex;gap:8px;">
18 <input type="hidden" name="offer" value="<%= o.id %>">
19 <button class="btn" type="submit" name="answer" value="accept"><%= t('msg.guard_accept') %></button>
20 <button class="btn" type="submit" name="answer" value="reject" style="opacity:.7;"><%= t('msg.guard_reject') %></button>
21 </form>
22 </div>
23 <% }); %>
24 <% } %>
25
26 <div class="msg-filters" role="tablist" aria-label="<%= t('msg.title') %>">
27 <button type="button" class="msg-chip is-on" data-show="all"><%= t('msg.filter_all') %></button>
28 <button type="button" class="msg-chip" data-show="msgs"><%= t('msg.filter_msgs') %></button>
29 <button type="button" class="msg-chip" data-show="conv"><%= t('msg.filter_conv') %></button>
30 <button type="button" class="msg-chip" data-show="act"><%= t('msg.filter_act') %></button>
31 <button type="button" class="msg-chip" data-show="mod"><%= t('msg.filter_mod') %></button>
32 <button type="button" class="msg-chip" data-show="sent"><%= t('msg.filter_sent') %></button>
33 </div>
34 <div class="msg-search">
35 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
36 <input type="search" id="msg-q" placeholder="<%= t('msg.search_ph') %>" autocomplete="off" spellcheck="false" aria-label="<%= t('msg.search_ph') %>">
37 </div>
38
39 <% var _seen = (typeof seenAt !== 'undefined' && seenAt) ? seenAt : 0; %>
40 <% if (!items || !items.length) { %>
41 <p class="msg-empty"><%= t('msg.empty') %></p>
42 <% } else { %>
43 <ul class="msg-list" data-show="all" id="msg-list">
44 <% items.forEach(function(n){ %><%- include('../partials/msg-item', { n: n, seen: _seen }) %><% }); %>
45 </ul>
46 <p class="msg-nomatch" hidden><%= t('msg.no_match') %></p>
47 <%- include('../partials/load-more', { hasMore: hasMore, nextOffset: nextOffset, moreBase: moreBase, moreTarget: '#msg-list', morePath: '/messages' }) %>
48 <% } %>
49
50 <%# Interact bookmarklet — moved here from the old Reacties page. %>
51 <details class="msg-bm">
52 <summary><%= t('fedi.bm_label') %></summary>
53 <p class="msg-bm-help"><%= t('fedi.bm_help') %></p>
54 <a class="fedi-bm-btn" id="fedi-bm-btn" href="#" draggable="true" title="<%= t('fedi.bm_help') %>">
55 <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
56 <%= t('fedi.bm_label') %>
57 </a>
58 </details>
59</div>
60
61<script>
62(function () {
63 if (window.__msgWired) return; window.__msgWired = true;
64
65 // Filtering: kind chip AND free-text search, combined in JS (search over the
66 // sender and the rendered message text). Empty search + "all" = show all.
67 var list = document.querySelector('.msg-list');
68 var noMatch = document.querySelector('.msg-nomatch');
69 var q = document.getElementById('msg-q');
70 var kind = 'all';
71 var items = [];
72 function indexItem(li) {
73 // Index once: sender + message body + linked post title + poll text.
74 var body = li.querySelector('.msg-content');
75 var post = li.querySelector('.msg-post');
76 var poll = li.querySelector('.msg-poll');
77 li._search = ((li.getAttribute('data-who') || '') + ' ' +
78 (body ? body.textContent : '') + ' ' + (post ? post.textContent : '') + ' ' +
79 (poll ? poll.textContent : '')).toLowerCase();
80 }
81 // Re-collect + index; called on load and after each "Load more" append so new
82 // items join the filter/search (and inherit the active chip via apply()).
83 function reindex() {
84 items = list ? Array.prototype.slice.call(list.querySelectorAll('.msg-item')) : [];
85 items.forEach(function (li) { if (!li._search) indexItem(li); });
86 }
87 reindex();
88 function apply() {
89 if (!list) return;
90 var term = (q && q.value || '').trim().toLowerCase();
91 var shown = 0;
92 items.forEach(function (li) {
93 var ok = (kind === 'all' || li.getAttribute('data-kind') === kind) &&
94 (!term || li._search.indexOf(term) !== -1);
95 li.style.display = ok ? '' : 'none';
96 if (ok) shown++;
97 });
98 if (noMatch) noMatch.hidden = shown !== 0;
99 }
100 document.addEventListener('click', function (e) {
101 var chip = e.target.closest('.msg-chip'); if (!chip) return;
102 kind = chip.getAttribute('data-show');
103 document.querySelectorAll('.msg-chip').forEach(function (c) { c.classList.toggle('is-on', c === chip); });
104 apply();
105 });
106 if (q) q.addEventListener('input', apply);
107 // After a "Load more" append (htmx), index the new rows and re-apply the filter.
108 document.body.addEventListener('htmx:afterSettle', function (e) {
109 if (e.target && e.target.id === 'msg-list') { reindex(); apply(); }
110 });
111
112 var a = document.getElementById('fedi-bm-btn');
113 if (a) {
114 a.setAttribute('href', "javascript:void(window.open('" + location.origin + "/authorize_interaction?uri='+encodeURIComponent(window.location.href)))");
115 a.addEventListener('click', function (e) { e.preventDefault(); a.classList.add('nudge'); setTimeout(function(){ a.classList.remove('nudge'); }, 600); });
116 }
117})();
118</script>
119
120<style>
121 .msg-wrap { max-width: 640px; margin: 1rem auto; padding: 0 1rem; }
122 .msg-title { margin: 0 0 .9rem; }
123 .msg-empty { color: var(--ink-soft, #888); }
124
125 .msg-filters { display: flex; gap: .4rem; margin: 0 0 1.1rem; flex-wrap: wrap; }
126 .msg-chip { border: 1px solid color-mix(in srgb, var(--ink, #000) 16%, transparent); background: none;
127 color: var(--ink-soft, #888); font: inherit; font-size: .84rem; font-weight: 600;
128 padding: .3rem .85rem; border-radius: 999px; cursor: pointer; }
129 .msg-chip.is-on { background: var(--accent, #06c); border-color: var(--accent, #06c); color: #fff; }
130
131 .msg-search { display: flex; align-items: center; gap: .5rem; margin: 0 0 1.1rem;
132 padding: .45rem .7rem; border-radius: 10px;
133 border: 1px solid color-mix(in srgb, var(--ink, #000) 16%, transparent); }
134 .msg-search:focus-within { border-color: var(--accent, #06c); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #06c) 18%, transparent); }
135 .msg-search svg { width: 16px; height: 16px; color: var(--ink-soft, #888); flex-shrink: 0; }
136 .msg-search input { flex: 1; border: none; background: none; color: inherit; font: inherit; outline: none; min-width: 0; }
137 .msg-nomatch { color: var(--ink-soft, #888); text-align: center; padding: 1.2rem 0; }
138
139 .msg-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .55rem; }
140
141 .msg-item { display: flex; gap: .8rem; padding: .85rem .95rem; border-radius: 14px; align-items: flex-start;
142 background: color-mix(in srgb, var(--ink, #000) 3.5%, transparent);
143 border: 1px solid color-mix(in srgb, var(--ink, #000) 9%, transparent);
144 transition: border-color .15s ease, box-shadow .15s ease; }
145 .msg-item:hover { border-color: color-mix(in srgb, var(--accent, #888) 30%, transparent);
146 box-shadow: 0 2px 12px color-mix(in srgb, var(--ink, #000) 6%, transparent); }
147 .msg-item.is-new { border-color: color-mix(in srgb, var(--accent, #06c) 45%, transparent);
148 background: color-mix(in srgb, var(--accent, #06c) 4%, transparent); }
149 .msg-sent { border-left: 3px solid color-mix(in srgb, var(--accent, #06c) 55%, transparent); }
150
151 .msg-av { position: relative; flex: 0 0 40px; width: 40px; height: 40px; border-radius: 50%;
152 display: inline-flex; align-items: center; justify-content: center; font-weight: 700;
153 background: color-mix(in srgb, var(--accent, #888) 16%, transparent); color: var(--accent, #06c); overflow: visible; }
154 .msg-av img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; background: #fff; }
155 .msg-av-sent svg { width: 17px; height: 17px; }
156 .msg-dot { position: absolute; right: -3px; bottom: -3px; width: 18px; height: 18px; border-radius: 50%;
157 display: inline-flex; align-items: center; justify-content: center;
158 border: 2px solid var(--paper, #fff); background: var(--accent, #06c); color: #fff; }
159 .msg-dot svg { width: 10px; height: 10px; }
160 .msg-dot-like { background: #e8b04b; } .msg-dot-boost { background: #2fa85a; }
161 .msg-dot-report { background: #c0392b; } .msg-dot-mention { background: #8e6cf0; }
162
163 .msg-body { flex: 1; min-width: 0; }
164 .msg-line { display: flex; align-items: baseline; gap: .4rem; }
165 .msg-who { font-weight: 700; color: var(--ink, inherit); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
166 a.msg-who:hover { text-decoration: underline; }
167 .msg-handle { color: var(--ink-soft, #888); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
168 .msg-new { width: 8px; height: 8px; border-radius: 50%; background: var(--accent, #06c); flex: 0 0 auto; align-self: center; }
169 .msg-time { color: var(--ink-soft, #999); font-size: .76rem; margin-left: auto; flex: 0 0 auto; white-space: nowrap; }
170 .msg-what { color: var(--ink-soft, #aaa); margin-top: .12rem; line-height: 1.4; }
171 .msg-what .msg-post { color: var(--accent, #06c); font-weight: 600; margin-left: .25rem; }
172 .msg-priv { display: inline-block; margin-left: .3rem; padding: .05rem .5rem; border-radius: 999px; font-size: .72rem; font-weight: 700;
173 background: color-mix(in srgb, #8e6cf0 14%, transparent); color: #8e6cf0; }
174 .msg-content { margin: .45rem 0 0; padding: .55rem .75rem; border-radius: 10px; line-height: 1.5;
175 background: color-mix(in srgb, var(--ink, #000) 4%, transparent); color: var(--ink, inherit); overflow-wrap: anywhere; }
176 .msg-content p { margin: .2rem 0; } .msg-content p:first-child { margin-top: 0; } .msg-content p:last-child { margin-bottom: 0; }
177
178 .msg-poll { margin: .5rem 0 0; display: flex; flex-direction: column; gap: .4rem; }
179 .msg-poll-opt { display: flex; flex-direction: column; gap: .2rem; }
180 .msg-poll-top { display: flex; justify-content: space-between; gap: .5rem; font-size: .85rem; }
181 .msg-poll-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
182 .msg-poll-pct { font-variant-numeric: tabular-nums; color: var(--ink-soft, #888); flex-shrink: 0; }
183 .msg-poll-bar { height: 7px; border-radius: 999px; overflow: hidden; background: color-mix(in srgb, var(--ink, #000) 10%, transparent); }
184 .msg-poll-bar span { display: block; height: 100%; border-radius: 999px; background: var(--accent, #06c); }
185 .msg-poll-total { font-size: .78rem; color: var(--ink-soft, #888); margin-top: .1rem; }
186
187 .msg-actions { display: flex; gap: .7rem; align-items: center; margin-top: .45rem; }
188 .msg-edit summary { cursor: pointer; font-size: .8rem; color: var(--ink-soft, #888); font-weight: 600; }
189 .msg-edit-form { margin-top: .4rem; display: flex; flex-direction: column; gap: .4rem; }
190 .msg-edit-form textarea { width: 100%; font: inherit; padding: .5rem .65rem; border-radius: 8px;
191 border: 1px solid color-mix(in srgb, var(--ink, #000) 16%, transparent); background: transparent; color: var(--ink, inherit); }
192 .msg-del { background: none; border: none; padding: 0; font: inherit; font-size: .8rem; font-weight: 600;
193 color: var(--ink-soft, #888); cursor: pointer; }
194 .msg-del:hover { color: #c0392b; }
195
196 .msg-bm { margin: 1.4rem 0 0; border-top: 1px solid color-mix(in srgb, var(--ink, #000) 10%, transparent); padding-top: .8rem; }
197 .msg-bm summary { cursor: pointer; color: var(--ink-soft, #888); font-weight: 600; font-size: .88rem; }
198 .msg-bm-help { color: var(--ink-soft, #888); font-size: .82rem; line-height: 1.5; margin: .5rem 0 .6rem; }
199</style>
Note: See TracBrowser for help on using the repository browser.