Changeset 3f9f71d in Klonkt


Ignore:
Timestamp:
06/29/2026 10:36:16 PM (2 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
054b603
Parents:
f2796d3
Message:

feat(circle): "+N" members modal when a circle has more than 5 sites

The Circle header capped at 5 chips and otherwise showed only a dead count pill.
Now the count pill is a button that opens a modal listing every circle member
(avatar + name + link to their site). CSS-only (hidden-checkbox toggle) so it
needs no JS — CSP- and htmx-safe.

  • src/views/pages/circle-feed.ejs — the >5 branch is now a clickable count pill + a member modal (backdrop + card + member list); modal/button CSS added to the page <style>
  • src/services/i18n.js — new cfeed.close label (nl/en/de)

Co-Authored-By: Claude <noreply@…>

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/i18n.js

    rf2796d3 r3f9f71d  
    871871    'cfeed.count': '{n} sites in mijn cirkel',
    872872    'cfeed.empty': 'Nog niets in mijn cirkel.',
     873    'cfeed.close': 'Sluiten',
    873874    'cfeed.grid_view': 'Grid-weergave',
    874875    'cpost.back': 'Cirkel',
     
    17821783    'cfeed.count': '{n} sites in my circle',
    17831784    'cfeed.empty': 'Nothing in my circle yet.',
     1785    'cfeed.close': 'Close',
    17841786    'cfeed.grid_view': 'Grid view',
    17851787    'cpost.back': 'Circle',
     
    26932695    'cfeed.count': '{n} Seiten in meinem Zirkel',
    26942696    'cfeed.empty': 'Noch nichts in meinem Zirkel.',
     2697    'cfeed.close': 'Schließen',
    26952698    'cfeed.grid_view': 'Rasteransicht',
    26962699    'cpost.back': 'Zirkel',
  • src/views/pages/circle-feed.ejs

    rf2796d3 r3f9f71d  
    2626    </div>
    2727    <% } else { %>
    28       <%# More than 5: no chips (would become a wall) — show the count only. %>
    29       <span class="cirkel-count"><%= t('cfeed.count', { n: sites.length }) %></span>
     28      <%# More than 5: the count pill becomes a button that opens a modal listing every
     29          member (avatar + name + link). CSS-only via a hidden checkbox — no JS, so it's
     30          CSP- (no inline handler) and htmx-safe. Checkbox must precede .cirkel-modal so
     31          the `:checked ~` sibling selector matches. %>
     32      <input type="checkbox" id="cirkel-more-cb" class="cirkel-more-cb" hidden>
     33      <label for="cirkel-more-cb" class="cirkel-count cirkel-count-btn" role="button" tabindex="0"><%= t('cfeed.count', { n: sites.length }) %></label>
     34      <div class="cirkel-modal" role="dialog" aria-modal="true" aria-label="<%= t('cfeed.title') %>">
     35        <label for="cirkel-more-cb" class="cirkel-modal-backdrop" aria-label="<%= t('cfeed.close') %>"></label>
     36        <div class="cirkel-modal-card">
     37          <label for="cirkel-more-cb" class="cirkel-modal-x" aria-label="<%= t('cfeed.close') %>" role="button" tabindex="0">&times;</label>
     38          <h2 class="cirkel-modal-h"><%= t('cfeed.count', { n: sites.length }) %></h2>
     39          <ul class="cirkel-modal-list">
     40            <% sites.forEach(function(s){ %>
     41              <li>
     42                <% if (s.url) { %><a class="cirkel-modal-link" href="<%= s.url %>" target="_blank" rel="noopener"><% } else { %><span class="cirkel-modal-link"><% } %>
     43                  <span class="cirkel-avatar"<% if (s.avatar) { %> style="background-image:url('<%= s.avatar %>');background-color:transparent"<% } %>><% if (!s.avatar) { %><%= (s.name || '?').charAt(0).toUpperCase() %><% } %></span>
     44                  <span class="cirkel-member-name"><%= s.name %></span>
     45                  <% if (s.url) { %><span class="cirkel-modal-go" aria-hidden="true">↗</span><% } %>
     46                <% if (s.url) { %></a><% } else { %></span><% } %>
     47              </li>
     48            <% }); %>
     49          </ul>
     50        </div>
     51      </div>
    3052    <% } %>
    3153  <% } %>
     
    83105.cirkel-count { display: inline-block; color: var(--ink-muted); font-size: .92rem; font-weight: 600;
    84106  padding: .35rem 1rem; border: 1px solid var(--rule); border-radius: 999px; background: var(--paper-2); }
     107.cirkel-count-btn { cursor: pointer; user-select: none; transition: border-color .15s, color .15s, transform .15s; }
     108.cirkel-count-btn:hover { border-color: var(--accent); color: var(--ink); transform: translateY(-1px); }
    85109.cirkel-empty { color: var(--ink-muted); text-align: center; margin: 2rem auto; }
    86110.cirkel-empty a { color: var(--accent); }
     111/* CSS-only "more members" modal (toggled by the hidden checkbox, no JS) */
     112.cirkel-more-cb { position: absolute; width: 0; height: 0; opacity: 0; pointer-events: none; }
     113.cirkel-modal { display: none; position: fixed; inset: 0; z-index: 1000; align-items: center; justify-content: center; padding: 1rem; }
     114.cirkel-more-cb:checked ~ .cirkel-modal { display: flex; }
     115.cirkel-modal-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.45); cursor: pointer; }
     116.cirkel-modal-card { position: relative; background: var(--paper); color: var(--ink); border-radius: 18px;
     117  padding: 1.4rem 1.2rem; width: min(420px, 92vw); max-height: 78vh; overflow-y: auto; text-align: left;
     118  box-shadow: 0 20px 60px rgba(0,0,0,.32); }
     119.cirkel-modal-x { position: absolute; top: .55rem; right: .65rem; width: 34px; height: 34px; border-radius: 50%;
     120  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; font-size: 1.45rem;
     121  line-height: 1; color: var(--ink-muted); background: var(--paper-2); }
     122.cirkel-modal-x:hover { color: var(--ink); }
     123.cirkel-modal-h { font-family: var(--font-display, serif); font-size: 1.3rem; margin: .1rem 0 1rem; text-align: center; }
     124.cirkel-modal-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
     125.cirkel-modal-link { display: flex; align-items: center; gap: .6rem; padding: .45rem .5rem; border-radius: 12px;
     126  text-decoration: none; color: var(--ink); transition: background .15s; }
     127.cirkel-modal-link:hover { background: var(--paper-2); }
     128.cirkel-modal-go { margin-left: auto; color: var(--accent); font-weight: 700; }
    87129</style>
Note: See TracChangeset for help on using the changeset viewer.