Changeset 952baf3 in Klonkt for src/views/pages/messages.ejs
- Timestamp:
- 08/07/2026 05:15:52 PM (5 weeks ago)
- Branches:
- main
- Children:
- ba76bf5
- Parents:
- f85b2c3 (diff), 0d5bd2c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
src/views/pages/messages.ejs (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/views/pages/messages.ejs
rf85b2c3 r952baf3 2 2 <%- include('../partials/fedi-tabs', { active: 'berichten' }) %> 3 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><% } %>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 === 'reply_sent' ? t('msg.reply_sent') : success))) %></div><% } %> 5 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error === 'guardianship' ? t('msg.guard_failed') : (error === 'reply_empty' ? t('msg.reply_empty') : ((error === 'reply_failed' || error === 'reply_target') ? t('msg.reply_failed') : error)) %></div><% } %> 6 6 7 7 <%# FEP-633c: a pending guardianship offer is a special message: the kid … … 25 25 26 26 <div class="msg-filters" role="tablist" aria-label="<%= t('msg.title') %>"> 27 <%# Vier chips, geen zes: Berichten, Gesprekken en Verzonden gingen op in 28 een enkele Gesprekken-view, waarin verzonden en ontvangen in dezelfde 29 draad staan. Activiteit en Moderatie blijven wat ze waren. %> 27 30 <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 31 <button type="button" class="msg-chip" data-show="conv"><%= t('msg.filter_conv') %></button> 30 32 <button type="button" class="msg-chip" data-show="act"><%= t('msg.filter_act') %></button> 31 33 <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 34 </div> 34 35 <div class="msg-search"> … … 59 60 </div> 60 61 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> 62 <%# Filteren, zoeken en het in-/uitklappen zitten in assets/js/mod/messages.js. 63 Inline script hier wordt door de CSP geweigerd zodra je deze pagina via een 64 link BINNEN de site opent -- zie shaer-0i6. De shell laadt de module op 65 body[data-js]; deze pagina vraagt erom met pageJs (routes/posts.js). %> 119 66 120 67 <style> … … 138 85 139 86 .msg-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .55rem; } 87 140 88 141 89 .msg-item { display: flex; gap: .8rem; padding: .85rem .95rem; border-radius: 14px; align-items: flex-start; … … 148 96 background: color-mix(in srgb, var(--accent, #06c) 4%, transparent); } 149 97 .msg-sent { border-left: 3px solid color-mix(in srgb, var(--accent, #06c) 55%, transparent); } 98 99 /* ── Gesprekken ────────────────────────────────────────────────────── 100 NA .msg-item, en dat is geen smaak: .msg-item zet display:flex, en bij 101 gelijke specificiteit wint de laatste regel. Stond dit ervoor, dan kwam de 102 draadkop NAAST de bubbels te staan in plaats van erboven. */ 103 .msg-thread { display: block; } 104 .msg-thread-head { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-bottom: .4rem; } 105 /* De tegenpartij is een labeltje bij het gesprek, geen kop erboven: een 106 kleine verzonken uitsparing, zodat de bubbels eronder de ruimte krijgen. 107 Het aantal zit in dezelfde uitsparing in plaats van ernaast. */ 108 /* Ook de knop die het gesprek in- en uitklapt. Een button erft geen font en 109 geen kleur, dus die staan hier expliciet; zonder dat wordt het ineens 110 systeemblauw in 13px. */ 111 .msg-thread-who { display: inline-flex; align-items: center; gap: .3rem; min-width: 0; 112 font: inherit; font-size: .78em; line-height: 1.5; font-weight: 500; 113 padding: .05rem .5rem; border-radius: 999px; border: 0; cursor: pointer; 114 color: color-mix(in srgb, var(--ink, #000) 62%, transparent); 115 background: color-mix(in srgb, var(--ink, #000) 5%, transparent); 116 box-shadow: inset 0 1px 2px color-mix(in srgb, var(--ink, #000) 9%, transparent); 117 max-width: 100%; overflow: hidden; white-space: nowrap; 118 /* Ruimer aanraakvlak dan de tekst: een chip van 18px hoog is op een telefoon 119 niet te raken. De uitsparing blijft klein, het doel wordt groter. */ 120 min-height: 32px; } 121 .msg-thread-who:hover { background: color-mix(in srgb, var(--ink, #000) 9%, transparent); } 122 .msg-thread-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 123 .msg-thread-chevron { width: 12px; height: 12px; flex: none; opacity: .55; 124 transition: transform .18s ease; } 125 /* Ingeklapt: de bubbels en het antwoordveld verdwijnen, de uitsparing met de 126 naam en het AANTAL blijft staan -- dat aantal is juist ingeklapt het meest 127 waard. */ 128 .msg-thread.is-collapsed .msg-thread-msgs, 129 .msg-thread.is-collapsed .msg-thread-foot { display: none; } 130 /* Tijdens het zoeken wint de treffer van de dichtgeklapte stand. */ 131 .msg-thread.is-collapsed.is-search-open .msg-thread-msgs { display: flex; } 132 .msg-thread.is-collapsed.is-search-open .msg-thread-foot { display: flex; } 133 .msg-thread.is-collapsed .msg-thread-chevron { transform: rotate(-90deg); } 134 .msg-thread.is-collapsed .msg-thread-head { margin-bottom: 0; } 135 @media (prefers-reduced-motion: reduce) { .msg-thread-chevron { transition: none; } } 136 .msg-thread-count { font-variant-numeric: tabular-nums; opacity: .75; flex: 0 0 auto; 137 padding-inline-start: .3rem; border-inline-start: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent); } 138 .msg-thread-post { display: inline-flex; align-items: center; gap: .3rem; font-size: .85em; 139 margin-inline-start: auto; min-width: 0; max-width: 100%; 140 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } 141 .msg-thread-post svg { width: 13px; height: 13px; flex: none; } 142 .msg-thread-msgs { list-style: none; margin: 0; padding: 0 0 0 .7rem; display: flex; flex-direction: column; gap: .5rem; 143 border-inline-start: 2px solid color-mix(in srgb, var(--ink, #000) 10%, transparent); } 144 .msg-sub { display: flex; gap: .6rem; align-items: flex-start; min-width: 0; } 145 .msg-sub > .msg-body { min-width: 0; } 146 /* Jouw eigen bijdrage onderscheidt zich met een tint en de accentlijn die 147 .msg-sent al had -- niet met row-reverse: dat duwde de avatar buiten de 148 kaart zodra de regel smaller werd dan zijn inhoud. */ 149 .msg-sub.msg-sent { border-radius: 10px; padding: .3rem .45rem; 150 background: color-mix(in srgb, var(--accent, #06c) 5%, transparent); } 151 /* Een lange naam of tijd mag de bubbel niet uit de kaart duwen. */ 152 .msg-sub .msg-line { flex-wrap: wrap; } 153 154 /* De voet van een gesprek: antwoorden en zwaaien naast elkaar, ingeklapt. 155 Een open editor onder elk gesprek maakt de lijst weer onleesbaar -- precies 156 wat deze weergave moest oplossen. */ 157 .msg-thread-foot { display: flex; align-items: flex-start; gap: .5rem; margin-top: .5rem; flex-wrap: wrap; } 158 .msg-reply { flex: 1 1 12rem; min-width: 0; } 159 .msg-reply > summary { cursor: pointer; font-size: .82rem; color: var(--ink-soft, #888); } 160 .msg-reply[open] > summary { margin-bottom: .4rem; } 161 .msg-reply-form { min-width: 0; } 162 .msg-wave button { line-height: 1.2; } 163 164 @media (max-width: 560px) { 165 /* Op een telefoon is 40px avatar per bubbel puur verlies: de naam staat er 166 al naast, en de inhoud heeft de breedte harder nodig. */ 167 .msg-sub > .msg-av { display: none; } 168 .msg-thread-msgs { padding-inline-start: .55rem; } 169 .msg-thread-post { margin-inline-start: 0; } 170 .msg-item { padding: .7rem .6rem; gap: .6rem; } 171 } 150 172 151 173 .msg-av { position: relative; flex: 0 0 40px; width: 40px; height: 40px; border-radius: 50%;
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)