Changeset 834bcc3 in Klonkt for src/views/partials


Ignore:
Timestamp:
06/23/2026 06:14:27 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
d774679
Parents:
bb42dfb
Message:

i18n: translate Dutch code comments to English across src/

Comments in routes/services/views/config/middleware/assets translated to
English for the public repo. A few dev-facing throw/console message strings
were Englished too. No user-facing UI strings or i18n dictionary values changed
(src/services/i18n.js untouched). Logic unchanged.

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

Location:
src/views/partials
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/views/partials/bottom-tab.ejs

    rbb42dfb r834bcc3  
    1515const _ownProfile  = user ? ('/users/' + user.username) : null;
    1616const _isHub       = (typeof tenancy !== 'undefined' && tenancy === 'hub');
    17 // Home gaat in hub-modus ALTIJD naar de hub-root (/), niet naar de sub-home van
    18 // een artiest. In solo/circle is _siteUrlBase leeg, dus dat blijft '/'.
     17// Home in hub mode ALWAYS goes to the hub root (/), not to an artist's sub-home.
     18// In solo/circle _siteUrlBase is empty, so it stays '/'.
    1919const _homeHref    = (_isHub ? '' : _siteUrlBase) + '/';
    2020
     
    2727
    2828let _active = null;
    29 // In hub is Home alleen actief op de échte hub-root, niet op een artiest-sub-home.
     29// In hub, Home is only active on the real hub root, not on an artist sub-home.
    3030if (_isHub ? (_path === '/') : (_p === '/' || _p === '')) _active = 'home';
    3131else if (_p.indexOf('/search') === 0 || _p.indexOf('/tag/') === 0 || _p.indexOf('/type/') === 0) _active = 'search';
     
    3838
    3939  <!-- Home -->
    40   <%# htmx-navigatie (geen full reload): de persistente audioplayer in document.body
    41       overleeft dan, dus de muziek verspringt niet bij het navigeren. Op mobiel is de
    42       top-balk toch verborgen, dus een context-reset via full-load is hier niet nodig. %>
     40  <%# htmx navigation (no full reload): the persistent audio player in document.body
     41      survives, so music does not skip when navigating. On mobile the top bar is hidden
     42      anyway, so a context reset via full-load is not needed here. %>
    4343  <a class="bottom-tab-item<%= _active === 'home' ? ' is-active' : '' %>"
    4444     href="<%= _homeHref %>"
     
    308308
    309309<script>
    310 // Bottom-tab zoekknop → opent #search-overlay. Via event-delegatie + de overlay
    311 // ELKE klik opnieuw opzoeken: de overlay zit in de chrome die bij htmx-navigatie
    312 // OOB vervangen wordt, dus een één-keer-opgevangen referentie verschaalt
    313 // (knop deed daarna niets). Guard tegen dubbel-wiren.
     310// Bottom-tab search button → opens #search-overlay. Using event delegation + looking
     311// up the overlay on EVERY click: the overlay lives in the chrome that is OOB-replaced
     312// during htmx navigation, so a once-captured reference goes stale
     313// (button did nothing afterwards). Guard against double-wiring.
    314314(function() {
    315315  if (window.__btSearchWired) return;
  • src/views/partials/footer.ejs

    rbb42dfb r834bcc3  
    1313      <span>© <%= new Date().getFullYear() %> <%= (site && site.title) || 'Klonkt' %></span>
    1414    </div>
    15     <%# Install-app knop — in de footer-rij (midden), bespaart een hele extra rij.
    16         JS detecteert platform & opent een modal met PWA-install-stappen. %>
     15    <%# Install-app button — placed in the footer row (centre), saves a whole extra row.
     16        JS detects the platform & opens a modal with PWA install steps. %>
    1717    <button type="button" class="install-app-btn install-app-btn--footer" data-pcms-install-app>
    1818      <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M5 20h14v-2H5v2zm7-18L5.33 9h3.84v6h5.66V9h3.84L12 2z" fill="currentColor"/></svg>
     
    114114}
    115115.footer-lang:hover { border-color: var(--accent); }
    116 /* Open dropdown-opties leesbaar (anders wit-op-wit op dark mode). */
     116/* Make open dropdown options readable (otherwise white-on-white in dark mode). */
    117117.footer-lang option { background: var(--paper); color: var(--ink); }
    118 /* Op desktop staat de taalkeuze in de header-nav → footer-versie verbergen. */
     118/* On desktop the language picker lives in the header nav → hide the footer version. */
    119119@media (min-width: 768px) { .footer-lang { display: none; } }
    120120.footer-version { color: inherit; text-decoration: none; }
     
    144144}
    145145
    146 /* Compacte install-knop ín de footer-rij (midden) i.p.v. een grote losse CTA
    147    op een eigen regel — bespaart verticale ruimte. */
     146/* Compact install button inside the footer row (centre) instead of a large standalone
     147   CTA on its own line — saves vertical space. */
    148148.install-app-btn--footer {
    149149  flex: 0 0 auto;
    150   width: auto !important;          /* override de mobile .install-app-btn width:100% */
     150  width: auto !important;          /* override the mobile .install-app-btn width:100% */
    151151  padding: 0.42rem 0.95rem;
    152152  font-size: 0.82rem;
     
    154154}
    155155.install-app-btn--footer svg { width: 15px; height: 15px; }
    156 /* Op smal scherm: laat de drie items netjes centreren als ze wrappen. */
     156/* On narrow screens: let the three items centre neatly when they wrap. */
    157157@media (max-width: 600px) {
    158158  .site-footer-inner { justify-content: center; text-align: center; }
  • src/views/partials/like-button.ejs

    rbb42dfb r834bcc3  
    1 <%# Like-/favorietknop voor een post. Ingelogd → htmx-toggle (POST /posts/:id/like,
    2     swap outerHTML met deze partial terug). Niet ingelogd → link naar login.
    3     Verwacht: post (met .id), likedByMe, likeCount, loggedIn, loginNext. %>
     1<%# Like/favourite button for a post. Logged in → htmx toggle (POST /posts/:id/like,
     2    swaps outerHTML back with this partial). Not logged in → link to login.
     3    Expects: post (with .id), likedByMe, likeCount, loggedIn, loginNext. %>
    44<%
    55  var _liked = (typeof likedByMe !== 'undefined' && likedByMe);
  • src/views/partials/post-nav.ejs

    rbb42dfb r834bcc3  
    1 <%# Post-navigatie (Newer links / Older rechts) — gedeeld door post.ejs én
    2     fan-gate.ejs. Verwacht newerPost + olderPost in scope. Ontbreekt een buur,
    3     dan een uitgegrijsde placeholder zodat elke post dezelfde structuur houdt. %>
     1<%# Post navigation (Newer link left / Older right) — shared by post.ejs and
     2    fan-gate.ejs. Expects newerPost + olderPost in scope. If a neighbour is missing,
     3    a greyed-out placeholder keeps every post in the same two-card structure. %>
    44<% if ((typeof newerPost !== 'undefined' && newerPost) || (typeof olderPost !== 'undefined' && olderPost)) { %>
    55  <nav class="post-nav post-nav--top">
     
    3535<style>
    3636.post-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--rule); }
    37 /* Boven de post: geen lijn/gap erboven, maar een scheidingslijn ERONDER (naar de content). */
     37/* Above the post: no line/gap above it, but a dividing line BELOW (toward the content). */
    3838.post-nav--top { margin-top: 0; padding-top: 0; border-top: 0; margin-bottom: 2rem; padding-bottom: 2rem; border-bottom: 1px solid var(--rule); }
    3939.post-nav-prev, .post-nav-next { display: flex; flex-direction: column; padding: 1rem; background: var(--paper-2); border-radius: 6px; text-decoration: none; color: var(--ink); }
    40 /* Lege plek (geen nieuwere/oudere post): zelfde kaart, uitgegrijsd + niet klikbaar,
    41    zodat elke post dezelfde twee-kaarten-structuur houdt. */
     40/* Empty slot (no newer/older post): same card, greyed out + not clickable,
     41   so every post keeps the same two-card structure. */
    4242.post-nav-prev.is-empty, .post-nav-next.is-empty { opacity: 0.4; cursor: default; }
    4343.post-nav-prev.is-empty .post-nav-title, .post-nav-next.is-empty .post-nav-title { font-weight: 400; font-style: italic; color: var(--ink-muted); }
  • src/views/partials/shared-styles.ejs

    rbb42dfb r834bcc3  
    66  border-bottom: 1px solid var(--rule);
    77  background: var(--paper);
    8   /* Geen extra margin-top: de pill wordt zo gecentreerd tussen de profielkop-
    9      streep (boven) en de eigen border (onder). De gelijke lucht boven/onder de
    10      pill komt uit de symmetrische container-padding hieronder. De margin-bottom
    11      (1.5rem in style.css) blijft lucht naar de feed. */
     8  /* No extra margin-top: this centres the pill between the profile-header
     9     rule (above) and the own border (below). Equal space above/below the
     10     pill comes from the symmetric container padding below. The margin-bottom
     11     (1.5rem in style.css) keeps breathing room toward the feed. */
    1212  margin-top: 0;
    1313}
    1414.view-switcher-wrap .container {
    1515  display: flex; align-items: center; justify-content: center; gap: 0.75rem;
    16   /* Symmetrische padding → even veel lucht boven als onder de pill (≈8px),
    17      gecentreerd tussen de twee lijnen. */
     16  /* Symmetric padding → equal space above and below the pill (≈8px),
     17     centred between the two dividing lines. */
    1818  padding: 0.5rem 1rem;
    1919  max-width: 1200px; margin: 0 auto;
     
    3636}
    3737.view-switch-btn:hover { color: var(--ink); }
    38 /* Actief = wit (lichte achtergrond, donkere tekst). Via aria-selected (element-
    39    attribuut, door syncAria gezet + op htmx:afterSettle) → htmx-robuust. Op niet-
    40    feed-pagina's zet syncAria aria-selected=false → beide grijs. */
     38/* Active = white (light background, dark text). Via aria-selected (element
     39   attribute, set by syncAria + on htmx:afterSettle) → htmx-robust. On non-
     40   feed pages syncAria sets aria-selected=false → both grey. */
    4141.view-switch-btn[aria-selected="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
    4242
    43 /* Agenda = een EIGEN pill (los van Tijdlijn/Grid, zodat de feed-toggle nooit
    44    verstoord raakt). Zelfde look als de view-switcher-pill. Zichtbaar in alle modi. */
    45 .agenda-pill { display: inline-flex; align-items: center; }   /* geen box — losse icoon+tekst link */
     43/* Agenda = its OWN pill (separate from Timeline/Grid, so the feed-toggle is never
     44   disturbed). Same look as the view-switcher pill. Visible in all modes. */
     45.agenda-pill { display: inline-flex; align-items: center; }   /* no box — standalone icon+text link */
    4646.vs-agenda {
    4747  display: inline-flex; align-items: center; gap: 0.4rem;
     
    5353}
    5454.vs-agenda:hover { color: var(--ink); }
    55 /* Actief (op de agendapagina) = helder/wit. Element-class (in de OOB-gerenderde
    56    chrome) i.p.v. body-class-CSS → werkt betrouwbaar ook na htmx-navigatie. */
     55/* Active (on the agenda page) = bright/white. Element-class (in the OOB-rendered
     56   chrome) rather than body-class CSS → stays reliable after htmx navigation. */
    5757.vs-agenda.is-active { color: var(--ink); font-weight: 600; }
    5858
    59 /* Mobiel: Agenda op een eigen rij bovenaan, en Solo/Cirkel + Tijdlijn/Grid samen
    60    op de rij eronder (samen ~330px → past binnen een telefoon, i.p.v. de oude
    61    onevenwichtige split Agenda+Solo / Tijdlijn). */
     59/* Mobile: Agenda on its own row at the top, Solo/Circle + Timeline/Grid together
     60   on the row below (together ~330px → fits within a phone, instead of the old
     61   unbalanced split Agenda+Solo / Timeline). */
    6262@media (max-width: 520px) {
    6363  .view-switcher-wrap .agenda-pill { flex: 0 0 100%; justify-content: center; }
     
    9292.on-admin .view-switcher-wrap { display: none; }
    9393
    94 /* Op een losse post is er geen feed om te schakelen, dus geen knop hoort "actief"
    95    (gekleurd) te ogen. De actieve staat zit in style.css op body[data-feed-view]
    96    / body[data-grid-cols] (background:var(--ink)); we overrulen die SPECIFIEKER
    97    via body.on-post zodat de knoppen neutraal/grijs worden — maar wél klikbaar
    98    blijven (de klik-handler navigeert dan naar de feed in die weergave). De
    99    body-class wisselt client-side bij HTMX-nav, dus dit werkt ook zonder reload. */
     94/* On a standalone post there is no feed to switch, so no button should look "active"
     95   (coloured). The active state lives in style.css on body[data-feed-view]
     96   / body[data-grid-cols] (background:var(--ink)); we override that MORE SPECIFICALLY
     97   via body.on-post so the buttons become neutral/grey — but remain clickable
     98   (the click-handler then navigates to the feed in that view). The
     99   body-class switches client-side on HTMX-nav, so this works without a reload too. */
    100100body.on-post[data-feed-view="timeline"] .view-switch-btn[data-view="timeline"],
    101101body.on-post[data-feed-view="grid"] .view-switch-btn[data-view="grid"],
  • src/views/partials/topnav.ejs

    rbb42dfb r834bcc3  
    2727        <a href="<%= _siteUrlBase %>/" class="nav-link nav-link-admin"><%= t('nav.back_to_site') %></a>
    2828      <% } else if (typeof tenancy !== 'undefined' && tenancy === 'hub') { %>
    29         <%# Hub: de brand gaat naar de hub-home via HTMX. De chrome wordt in hub-modus
    30             altijd gerenderd en via body.on-hub (CSS) verborgen op de landing, dus htmx
    31             kan schakelen zonder full-reload → de audioplayer blijft leven. %>
     29        <%# Hub: the brand navigates to the hub home via HTMX. The chrome is always
     30            rendered in hub mode and hidden on the landing via body.on-hub (CSS), so htmx
     31            can switch without a full reload → the audio player stays alive. %>
    3232        <a class="nav-hub-home" href="/" aria-label="Home" title="Home"
    3333           hx-get="/?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="/" hx-indicator="#pcms-loading">
     
    207207<script>
    208208(function() {
    209   // EÉN keer bedraden. Deze chrome (topnav) wordt bij htmx-navigatie out-of-band
    210   // opnieuw ingevoegd → zonder deze guard zou dit script bij elke navigatie EXTRA
    211   // listeners stapelen, waardoor de thema-toggle 2× (of vaker) vuurde = geen netto
    212   // wisseling ("toggle werkt niet meer"). Alles hieronder is event-delegatie op
    213   // body/document, dus het werkt ook voor knoppen die ná deze run (OOB) verschijnen.
     209  // Wired ONCE. This chrome (topnav) is re-inserted out-of-band during htmx navigation
     210  // → without this guard the script would stack EXTRA listeners on every navigation,
     211  // causing the theme toggle to fire 2× (or more) = no net change ("toggle stops working").
     212  // Everything below uses event delegation on body/document, so it also works for
     213  // buttons that appear after this run (OOB).
    214214  if (window.__pcmsChromeWired) return;
    215215  window.__pcmsChromeWired = true;
     
    229229    if (e.target.closest('#search-toggle')) { openSearch(); return; }
    230230    if (e.target.closest('#search-close')) { closeSearch(); return; }
    231     // Open dropdowns (gebruikersmenu + taalkeuze) sluiten bij klik erbuiten.
     231    // Close open dropdowns (user menu + language picker) on click outside.
    232232    document.querySelectorAll('.user-menu[open], .lang-menu[open]').forEach(function(d) {
    233233      if (!d.contains(e.target)) d.removeAttribute('open');
     
    239239  });
    240240
    241   // ── Live resultaten tijdens typen ───────────────────────────────
     241  // ── Live results while typing ───────────────────────────────────
    242242  var _ST = {
    243243    posts: '<%= t('search.section_posts') %>', tracks: '<%= t('search.section_tracks') %>',
     
    280280    }, 200);
    281281  });
    282   // Klik op een suggestie → overlay sluiten (de link/boost doet de navigatie).
     282  // Click on a suggestion → close the overlay (the link/boost handles navigation).
    283283  document.addEventListener('click', function(e) {
    284284    if (e.target.closest && e.target.closest('#search-suggest a')) { var o = overlay(); if (o) o.hidden = true; }
     
    313313}
    314314
    315 /* Hub-home brand is WÉL zichtbaar — de thuisknop op artiest-/hub-pagina's. */
     315/* Hub-home brand IS visible — the home button on artist/hub pages. */
    316316.masthead-brand .nav-hub-home {
    317317  display: inline-flex; align-items: center; justify-content: center;
     
    436436  min-width: 220px;
    437437  padding: .35rem;
    438   /* Frosted glass: transparant + zware blur zodat het frosted effect duidelijk is. */
     438  /* Frosted glass: transparent + heavy blur so the frosted effect is clearly visible. */
    439439  background: color-mix(in srgb, var(--paper) 60%, transparent);
    440440  backdrop-filter: blur(34px) saturate(190%);
     
    565565.ss-all { display: block; margin-top: .35rem; padding: .55rem .6rem; border-top: 1px solid var(--rule); color: var(--accent); font-weight: 600; text-decoration: none; font-size: .9rem; }
    566566.ss-all:hover { text-decoration: underline; }
    567 /* Meldingen-bel + ongelezen-badge */
     567/* Notification bell + unread badge */
    568568.nav-notif { position: relative; }
    569569.notif-badge {
  • src/views/partials/track-editor.ejs

    rbb42dfb r834bcc3  
    195195}
    196196
    197 /* ── Credit-veld met ©-invoegknop ──────────────────────────── */
     197/* ── Credit field with © insert button ──────────────────────────── */
    198198.te-credit-row { display: flex; gap: 0.4rem; align-items: stretch; }
    199199.te-credit-row input { flex: 1; min-width: 0; }
     
    638638    }
    639639
    640     // ── ©-teken invoegen in het credit-veld ─────────────────
     640    // ── Insert © symbol into the credit field ─────────────────
    641641    const copyrBtn = $('#te-credit-copyr');
    642642    if (copyrBtn) {
     
    693693    });
    694694
    695     // ── Auto-duur ───────────────────────────────────────────
    696     // De server bepaalt de duur al automatisch bij upload. Dit is de vangnet/
    697     // UX-laag: opent een admin een bestaande track zónder duur, dan lezen we 'm
    698     // hier uit de audio-metadata en vullen het veld — zodat je nooit seconden
    699     // hoeft te typen. Bestaande waarde wordt nooit overschreven. We halen de
    700     // bytes via dezelfde header-gate als de speler (X-Audio-Player).
     695    // ── Auto-duration ───────────────────────────────────────────
     696    // The server already determines duration automatically on upload. This is the
     697    // fallback/UX layer: if an admin opens an existing track without a duration,
     698    // we read it from the audio metadata and fill the field — so you never need
     699    // to type seconds manually. An existing value is never overwritten. We fetch
     700    // the bytes via the same header gate as the player (X-Audio-Player).
    701701    (async function autoDuration() {
    702702      const durEl = $('#te-duration');
    703703      if (!durEl || !track.stream_url) return;
    704       if (durEl.value && Number(durEl.value) > 0) return;  // al ingevuld → met rust laten
     704      if (durEl.value && Number(durEl.value) > 0) return;  // already filled → leave it alone
    705705      let objUrl = null;
    706706      try {
Note: See TracChangeset for help on using the changeset viewer.