Changeset 297c77d in Klonkt
- Timestamp:
- 06/26/2026 02:14:00 PM (2 months ago)
- Branches:
- main
- Children:
- c27c945
- Parents:
- 1ecbf71
- Location:
- src
- Files:
-
- 9 edited
-
routes/posts.js (modified) (10 diffs)
-
services/ActivityPubService.js (modified) (1 diff)
-
views/pages/admin.ejs (modified) (1 diff)
-
views/pages/blocks.ejs (modified) (2 diffs)
-
views/pages/timeline.ejs (modified) (1 diff)
-
views/pages/volgend.ejs (modified) (2 diffs)
-
views/partials/fedi-tabs.ejs (modified) (1 diff)
-
views/partials/profile-sheet.ejs (modified) (1 diff)
-
views/partials/topnav.ejs (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/posts.js
r1ecbf71 r297c77d 85 85 'tag', 'type', 'user', 'users', 'artiesten', 'leden', 'favorieten', 'feed.xml', 'atom.xml', 'sitemap.xml', 86 86 'manifest.webmanifest', 'sw.js', 'favicon.ico', 'favicon.svg', 'assets', 87 'authorize_interaction', 'fediverse', 'ti jdlijn', 'meldingen', 'blokkeren',87 'authorize_interaction', 'fediverse', 'timeline', 'following', 'notifications', 'blocking', 88 88 ]); 89 89 … … 597 597 } 598 598 599 router.get('/ti jdlijn', requireSiteManager, (req, res) => {599 router.get('/timeline', requireSiteManager, (req, res) => { 600 600 const site = res.locals.site; 601 601 const timeline = (site ? ActivityPubService.getTimeline(site.slug, 60) : []) … … 609 609 610 610 // Volgend — manage the accounts you follow (+ per-account auto-boost toggles). 611 router.get('/ volgend', requireSiteManager, (req, res) => {611 router.get('/following', requireSiteManager, (req, res) => { 612 612 const site = res.locals.site; 613 613 const following = site ? ActivityPubService.listFollowing(site.slug) : []; 614 renderPage(req, res, 'pages/ volgend', {614 renderPage(req, res, 'pages/following', { 615 615 pageTitle: 'Volgend', bodyClass: 'on-special', 616 616 following, … … 619 619 }); 620 620 621 router.post('/ti jdlijn/follow', requireSiteManager, async (req, res) => {621 router.post('/timeline/follow', requireSiteManager, async (req, res) => { 622 622 const site = res.locals.site; 623 623 const handle = (req.body.handle || '').toString(); … … 632 632 } catch (e) { q = 'error=' + encodeURIComponent('Volgen mislukt'); } 633 633 } 634 res.redirect('/ volgend?' + q);635 }); 636 637 router.post('/ti jdlijn/unfollow', requireSiteManager, async (req, res) => {634 res.redirect('/following?' + q); 635 }); 636 637 router.post('/timeline/unfollow', requireSiteManager, async (req, res) => { 638 638 const site = res.locals.site; 639 639 const actorUri = (req.body.actor_uri || '').toString(); 640 640 if (site && actorUri) { try { await ActivityPubService.unfollowActor(site, actorUri); } catch (e) { /* ignore */ } } 641 res.redirect('/ volgend?success=' + encodeURIComponent('Ontvolgd'));641 res.redirect('/following?success=' + encodeURIComponent('Ontvolgd')); 642 642 }); 643 643 644 644 // Toggle "Featured" (show this account's posts in your Cirkel) on an account you follow. 645 router.post('/ti jdlijn/autoboost', requireSiteManager, (req, res) => {645 router.post('/timeline/autoboost', requireSiteManager, (req, res) => { 646 646 const site = res.locals.site; 647 647 const actorUri = (req.body.actor_uri || '').toString(); 648 648 if (site && actorUri) ActivityPubService.setAutoBoost(site.slug, actorUri, !!req.body.auto_boost); 649 res.redirect('/ volgend?success=' + encodeURIComponent(req.body.auto_boost ? 'Uitgelicht ✨' : 'Niet meer uitgelicht'));650 }); 651 652 router.post('/ti jdlijn/like', requireSiteManager, async (req, res) => {649 res.redirect('/following?success=' + encodeURIComponent(req.body.auto_boost ? 'Uitgelicht ✨' : 'Niet meer uitgelicht')); 650 }); 651 652 router.post('/timeline/like', requireSiteManager, async (req, res) => { 653 653 const site = res.locals.site; 654 654 if (site) { try { await ActivityPubService.sendInteraction(site, 'like', (req.body.note || '').toString(), (req.body.author || '').toString()); } catch (e) { /* ignore */ } } 655 res.redirect('/ti jdlijn?success=' + encodeURIComponent('Geliket ⭐'));656 }); 657 658 router.post('/ti jdlijn/boost', requireSiteManager, async (req, res) => {655 res.redirect('/timeline?success=' + encodeURIComponent('Geliket ⭐')); 656 }); 657 658 router.post('/timeline/boost', requireSiteManager, async (req, res) => { 659 659 const site = res.locals.site; 660 660 const note = (req.body.note || '').toString(); … … 663 663 ActivityPubService.markBoosted(site.slug, note); // also surface it in the Cirkel (mixed by date) 664 664 } 665 res.redirect('/ti jdlijn?success=' + encodeURIComponent('Geboost 🔁'));665 res.redirect('/timeline?success=' + encodeURIComponent('Geboost 🔁')); 666 666 }); 667 667 668 668 // Unboost (retract): send Undo(Announce) + clear the local flag. 669 router.post('/ti jdlijn/unboost', requireSiteManager, async (req, res) => {669 router.post('/timeline/unboost', requireSiteManager, async (req, res) => { 670 670 const site = res.locals.site; 671 671 const note = (req.body.note || '').toString(); … … 674 674 ActivityPubService.unmarkBoosted(site.slug, note); 675 675 } 676 res.redirect('/ti jdlijn?success=' + encodeURIComponent('Boost ingetrokken'));676 res.redirect('/timeline?success=' + encodeURIComponent('Boost ingetrokken')); 677 677 }); 678 678 679 679 // Notifications inbox (new followers + replies/likes/boosts on your posts). 680 router.get('/ meldingen', requireSiteManager, (req, res) => {680 router.get('/notifications', requireSiteManager, (req, res) => { 681 681 const site = res.locals.site; 682 682 const items = site ? ActivityPubService.getNotifications(site.slug, 80) : []; … … 688 688 689 689 // Blocking / defederation (owner-only). 690 router.get('/blo kkeren', requireSiteManager, (req, res) => {690 router.get('/blocking', requireSiteManager, (req, res) => { 691 691 const site = res.locals.site; 692 692 const blocks = site ? ActivityPubService.listBlocks(site.slug) : []; … … 694 694 }); 695 695 696 router.post('/blo kkeren/add', requireSiteManager, async (req, res) => {696 router.post('/blocking/add', requireSiteManager, async (req, res) => { 697 697 const site = res.locals.site; 698 698 let q = 'success=' + encodeURIComponent('Geblokkeerd'); … … 705 705 } 706 706 const ref = req.get('Referer') || ''; 707 res.redirect((ref.includes('/ti jdlijn') ? '/tijdlijn?' : '/blokkeren?') + q);708 }); 709 710 router.post('/blo kkeren/remove', requireSiteManager, (req, res) => {707 res.redirect((ref.includes('/timeline') ? '/timeline?' : '/blocking?') + q); 708 }); 709 710 router.post('/blocking/remove', requireSiteManager, (req, res) => { 711 711 const site = res.locals.site; 712 712 if (site) { try { ActivityPubService.unblock(site, (req.body.target || '').toString()); } catch (e) { /* ignore */ } } 713 res.redirect('/blo kkeren?success=' + encodeURIComponent('Deblokkeerd'));713 res.redirect('/blocking?success=' + encodeURIComponent('Deblokkeerd')); 714 714 }); 715 715 -
src/services/ActivityPubService.js
r1ecbf71 r297c77d 1094 1094 // never throws anything into the fediverse automatically" (would surprise-Follow 1095 1095 // for some operators at scale). The dead circle_links table stays as harmless dead 1096 // data; an operator restores an old cirkel by re-following in / volgend(their click).1096 // data; an operator restores an old cirkel by re-following in /following (their click). 1097 1097 async function resolveApActor(siteUrl) { 1098 1098 try { -
src/views/pages/admin.ejs
r1ecbf71 r297c77d 55 55 <% } %> 56 56 <% if (typeof apEnabled === 'undefined' || apEnabled) { %> 57 <a href="/ti jdlijn" class="btn">🌐 <%= t('tl.title') %></a>58 <a href="/ meldingen" class="btn">🔔 <%= t('notif.title') %></a>57 <a href="/timeline" class="btn">🌐 <%= t('tl.title') %></a> 58 <a href="/notifications" class="btn">🔔 <%= t('notif.title') %></a> 59 59 <a href="/fediverse" class="btn">🐘 <%= t('admin.b_fediverse') %></a> 60 <a href="/blo kkeren" class="btn">🚫 <%= t('blk.title') %></a>60 <a href="/blocking" class="btn">🚫 <%= t('blk.title') %></a> 61 61 <% } %> 62 62 <a href="/admin/updates" class="btn"><%= t('admin.b_updates') %></a> -
src/views/pages/blocks.ejs
r1ecbf71 r297c77d 6 6 <% if (typeof error !== 'undefined' && error) { %><div class="alert alert-error"><%= error %></div><% } %> 7 7 8 <form method="post" action="/blo kkeren/add" class="bl-form">8 <form method="post" action="/blocking/add" class="bl-form"> 9 9 <input type="text" name="target" placeholder="@naam@server.social • server.social" autocomplete="off" spellcheck="false" required> 10 10 <button type="submit" class="btn btn-primary"><%= t('blk.block_btn') %></button> … … 19 19 <span class="bl-kind"><%= b.kind === 'domain' ? '🌐' : '👤' %></span> 20 20 <span class="bl-label"><%= b.label || b.target %></span> 21 <form method="post" action="/blo kkeren/remove"><input type="hidden" name="target" value="<%= b.target %>"><button type="submit" class="bl-unblock"><%= t('blk.unblock') %></button></form>21 <form method="post" action="/blocking/remove"><input type="hidden" name="target" value="<%= b.target %>"><button type="submit" class="bl-unblock"><%= t('blk.unblock') %></button></form> 22 22 </li> 23 23 <% }); %> -
src/views/pages/timeline.ejs
r1ecbf71 r297c77d 47 47 48 48 <div class="tl-actions"> 49 <form method="post" action="/ti jdlijn/like" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act" title="<%= t('fedi.likes') %>">⭐</button></form>49 <form method="post" action="/timeline/like" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act" title="<%= t('fedi.likes') %>">⭐</button></form> 50 50 <% if (p.boosted) { %> 51 <form method="post" action="/ti jdlijn/unboost" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act tl-act-on" title="<%= t('tl.unboost') %>">🔁</button></form>51 <form method="post" action="/timeline/unboost" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act tl-act-on" title="<%= t('tl.unboost') %>">🔁</button></form> 52 52 <% } else { %> 53 <form method="post" action="/ti jdlijn/boost" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act" title="<%= t('fedi.boosts') %>">🔁</button></form>53 <form method="post" action="/timeline/boost" class="tl-act-form"><input type="hidden" name="note" value="<%= p.id %>"><input type="hidden" name="author" value="<%= p.author_uri %>"><button type="submit" class="tl-act" title="<%= t('fedi.boosts') %>">🔁</button></form> 54 54 <% } %> 55 55 <button type="button" class="tl-act fedi-remote-reply-btn" data-fedi-uri="<%= p.id %>" data-fedi-ph="<%= t('fedi.remote_ph') %>" title="<%= t('fedi.remote_reply') %>">↩</button> 56 <form method="post" action="/blo kkeren/add" class="tl-act-form" onsubmit="return confirm('<%= t('tl.block') %>?');"><input type="hidden" name="target" value="<%= p.author_uri %>"><button type="submit" class="tl-act tl-act-block" title="<%= t('tl.block') %>">🚫</button></form>56 <form method="post" action="/blocking/add" class="tl-act-form" onsubmit="return confirm('<%= t('tl.block') %>?');"><input type="hidden" name="target" value="<%= p.author_uri %>"><button type="submit" class="tl-act tl-act-block" title="<%= t('tl.block') %>">🚫</button></form> 57 57 </div> 58 58 </li> -
src/views/pages/volgend.ejs
r1ecbf71 r297c77d 10 10 </div> 11 11 12 <form method="post" action="/ti jdlijn/follow" class="tl-follow">12 <form method="post" action="/timeline/follow" class="tl-follow"> 13 13 <input type="text" name="handle" placeholder="@naam@server.social of site.com" autocomplete="off" spellcheck="false" required> 14 14 <button type="submit" class="btn btn-primary"><%= t('tl.follow_btn') %></button> … … 27 27 <% if (f.status === 'pending') { %><span class="tl-pending"><%= t('tl.pending') %></span><% } %> 28 28 </span> 29 <form method="post" action="/ti jdlijn/autoboost" class="tl-foll-ab" title="<%= t('tl.autoboost_hint') %>">29 <form method="post" action="/timeline/autoboost" class="tl-foll-ab" title="<%= t('tl.autoboost_hint') %>"> 30 30 <input type="hidden" name="actor_uri" value="<%= f.actor_uri %>"> 31 31 <label><input type="checkbox" name="auto_boost" value="1" <%= f.auto_boost ? 'checked' : '' %> onchange="this.form.submit()"> ✨ <%= t('tl.autoboost') %></label> 32 32 </form> 33 <form method="post" action="/ti jdlijn/unfollow"><input type="hidden" name="actor_uri" value="<%= f.actor_uri %>"><button type="submit" class="tl-unfollow"><%= t('tl.unfollow') %></button></form>33 <form method="post" action="/timeline/unfollow"><input type="hidden" name="actor_uri" value="<%= f.actor_uri %>"><button type="submit" class="tl-unfollow"><%= t('tl.unfollow') %></button></form> 34 34 </li> 35 35 <% }); %> -
src/views/partials/fedi-tabs.ejs
r1ecbf71 r297c77d 1 1 <%# Shared tab bar for the unified Fediverse section. Owner/admin-only. 2 2 Param: active = 'feed' | 'following' | 'reacties' | 'meldingen' | 'blokkeren'. 3 Responsive: horizontal tabs that scroll on narrow screens. %> 3 All tabs share the content width equally (flex:1) and always fit (ellipsis). 4 "Back to site" lives in the top nav, not here. %> 4 5 <% var _a = (typeof active !== 'undefined') ? active : ''; %> 5 6 <% var _nu = (typeof notifUnread !== 'undefined') ? notifUnread : 0; %> 6 <div class="fedi-bar"> 7 <a class="btn btn-primary fedi-bar-back" href="/"><%= t('nav.back_to_site') %></a> 8 <nav class="fedi-tabs" aria-label="Fediverse"> 9 <a href="/tijdlijn" class="fedi-tab<%= _a === 'feed' ? ' is-active' : '' %>" 10 hx-get="/tijdlijn?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/tijdlijn" hx-indicator="#pcms-loading"><%= t('tl.tab_feed') %></a> 11 <a href="/volgend" class="fedi-tab<%= _a === 'following' ? ' is-active' : '' %>" 12 hx-get="/volgend?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/volgend" hx-indicator="#pcms-loading"><%= t('tl.tab_following') %></a> 13 <a href="/fediverse" class="fedi-tab<%= _a === 'reacties' ? ' is-active' : '' %>" 14 hx-get="/fediverse?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/fediverse" hx-indicator="#pcms-loading"><%= t('tl.tab_replies') %></a> 15 <a href="/meldingen" class="fedi-tab<%= _a === 'meldingen' ? ' is-active' : '' %>" 16 hx-get="/meldingen?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/meldingen" hx-indicator="#pcms-loading"><%= t('notif.title') %><% if (_nu > 0) { %> <span class="fedi-tab-badge"><%= _nu > 9 ? '9+' : _nu %></span><% } %></a> 17 <a href="/blokkeren" class="fedi-tab<%= _a === 'blokkeren' ? ' is-active' : '' %>" 18 hx-get="/blokkeren?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/blokkeren" hx-indicator="#pcms-loading"><%= t('blk.title') %></a> 19 </nav> 20 </div> 7 <nav class="fedi-tabs" aria-label="Fediverse"> 8 <a href="/timeline" class="fedi-tab<%= _a === 'feed' ? ' is-active' : '' %>" 9 hx-get="/timeline?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/timeline" hx-indicator="#pcms-loading"><%= t('tl.tab_feed') %></a> 10 <a href="/following" class="fedi-tab<%= _a === 'following' ? ' is-active' : '' %>" 11 hx-get="/following?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/following" hx-indicator="#pcms-loading"><%= t('tl.tab_following') %></a> 12 <a href="/fediverse" class="fedi-tab<%= _a === 'reacties' ? ' is-active' : '' %>" 13 hx-get="/fediverse?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/fediverse" hx-indicator="#pcms-loading"><%= t('tl.tab_replies') %></a> 14 <a href="/notifications" class="fedi-tab<%= _a === 'meldingen' ? ' is-active' : '' %>" 15 hx-get="/notifications?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/notifications" hx-indicator="#pcms-loading"><span class="fedi-tab-label"><%= t('notif.title') %></span><% if (_nu > 0) { %><span class="fedi-tab-badge"><%= _nu > 9 ? '9+' : _nu %></span><% } %></a> 16 <a href="/blocking" class="fedi-tab<%= _a === 'blokkeren' ? ' is-active' : '' %>" 17 hx-get="/blocking?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/blocking" hx-indicator="#pcms-loading"><%= t('blk.title') %></a> 18 </nav> 21 19 <style> 22 .fedi-bar { margin: 0 0 1.25rem; } 23 /* Big, full-width "back to site" button at the top of the Fediverse section. */ 24 .fedi-bar-back { display: block; width: 100%; box-sizing: border-box; text-align: center; margin: 0 0 1rem; padding: .7rem 1rem; } 25 /* Tabs centered, wrap onto multiple rows on narrow screens (no scrollbar). */ 26 .fedi-tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: .1rem .25rem; 20 /* All 5 tabs share the width equally and always fit (truncate with ellipsis if needed). */ 21 .fedi-tabs { display: flex; margin: 0 0 1.25rem; 27 22 border-bottom: 1px solid color-mix(in srgb, var(--ink, #000) 10%, transparent); } 28 .fedi-tab { padding: .55rem .85rem; white-space: nowrap; text-decoration: none; 29 color: var(--ink-soft, #888); font-weight: 600; border-bottom: 2px solid transparent; margin-bottom: -1px; } 23 .fedi-tab { flex: 1 1 0; min-width: 0; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; 24 padding: .6rem .4rem; text-decoration: none; font-weight: 600; font-size: .95rem; 25 color: var(--ink-soft, #888); border-bottom: 2px solid transparent; margin-bottom: -1px; 26 display: inline-flex; align-items: center; justify-content: center; gap: .3rem; } 30 27 .fedi-tab:hover { color: var(--ink, #000); } 31 28 .fedi-tab.is-active { color: var(--accent, #06c); border-bottom-color: var(--accent, #06c); } 32 .fedi-tab-badge { display: inline-block; min-width: 1.15em; padding: 0 .3em; border-radius: 999px; 33 background: var(--accent, #e8b04b); color: #fff; font-size: .68rem; line-height: 1.5; text-align: center; vertical-align: middle; } 34 @media (max-width: 520px) { .fedi-tab { padding: .55rem .6rem; font-size: .92rem; } } 29 .fedi-tab-label { overflow: hidden; text-overflow: ellipsis; } 30 .fedi-tab-badge { flex: 0 0 auto; min-width: 1.15em; padding: 0 .3em; border-radius: 999px; 31 background: var(--accent, #e8b04b); color: #fff; font-size: .66rem; line-height: 1.5; text-align: center; } 32 @media (max-width: 520px) { .fedi-tab { padding: .55rem .25rem; font-size: .82rem; } } 33 @media (max-width: 380px) { .fedi-tab { font-size: .74rem; } } 35 34 </style> -
src/views/partials/profile-sheet.ejs
r1ecbf71 r297c77d 65 65 <% if (typeof canManageFedi !== 'undefined' && canManageFedi) { %> 66 66 <li role="none"> 67 <a href="/ti jdlijn" class="profile-sheet-item" role="menuitem" data-close-sheet68 hx-get="/ti jdlijn?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/tijdlijn" hx-indicator="#pcms-loading">67 <a href="/timeline" class="profile-sheet-item" role="menuitem" data-close-sheet 68 hx-get="/timeline?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/timeline" hx-indicator="#pcms-loading"> 69 69 <svg class="psi-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" 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> 70 70 <span class="psi-label"><%= t('nav.fediverse') %></span> -
src/views/partials/topnav.ejs
r1ecbf71 r297c77d 14 14 const _siteUrlBase = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : ''; 15 15 const _isAdmin = typeof bodyClass !== 'undefined' && bodyClass.indexOf('on-admin') >= 0; 16 // Fediverse pages (on-special) get the same top-nav "back to site" treatment as admin. 17 const _isSpecial = typeof bodyClass !== 'undefined' && bodyClass.indexOf('on-special') >= 0; 16 18 const _hasSearch = !site || site.show_search === undefined || site.show_search; 17 19 const _canPost = user && (typeof canMutate === 'undefined' || canMutate) … … 24 26 <!-- Brand block (always visible) --> 25 27 <div class="masthead-brand"> 26 <% if (_isAdmin ) { %>28 <% if (_isAdmin || _isSpecial) { %> 27 29 <a href="<%= _siteUrlBase %>/" class="nav-link nav-link-admin"><%= t('nav.back_to_site') %></a> 28 30 <% } else if (typeof tenancy !== 'undefined' && tenancy === 'hub') { %> … … 57 59 <nav class="top-nav top-nav-desktop" aria-label="Hoofdnavigatie"> 58 60 59 <% if (!_isAdmin ) { %>61 <% if (!_isAdmin && !_isSpecial) { %> 60 62 <a class="nav-link" href="<%= _siteUrlBase %>/archive" 61 63 hx-get="<%= _siteUrlBase %>/archive?partial=1" hx-target="#pcms-main" … … 100 102 101 103 <% if (user && typeof canManageFedi !== 'undefined' && canManageFedi) { %> 102 <a class="nav-btn nav-notif" href="/ meldingen" aria-label="<%= t('notif.title') %>" title="<%= t('notif.title') %>"103 hx-get="/ meldingen?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/meldingen" hx-indicator="#pcms-loading">104 <a class="nav-btn nav-notif" href="/notifications" aria-label="<%= t('notif.title') %>" title="<%= t('notif.title') %>" 105 hx-get="/notifications?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/notifications" hx-indicator="#pcms-loading"> 104 106 <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg> 105 107 <% if (typeof notifUnread !== 'undefined' && notifUnread > 0) { %><span class="notif-badge"><%= notifUnread > 9 ? '9+' : notifUnread %></span><% } %> … … 156 158 <% } %> 157 159 <% if (typeof canManageFedi !== 'undefined' && canManageFedi) { %> 158 <a href="/ti jdlijn" role="menuitem" class="udi"159 hx-get="/ti jdlijn?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"160 hx-push-url="/ti jdlijn" hx-indicator="#pcms-loading">160 <a href="/timeline" role="menuitem" class="udi" 161 hx-get="/timeline?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" 162 hx-push-url="/timeline" hx-indicator="#pcms-loading"> 161 163 <svg class="udi-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" 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> 162 164 <span><%= t('nav.fediverse') %></span>
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)