Changeset 834bcc3 in Klonkt for src/middleware/render.js
- Timestamp:
- 06/23/2026 06:14:27 PM (3 months ago)
- Branches:
- main
- Children:
- d774679
- Parents:
- bb42dfb
- File:
-
- 1 edited
-
src/middleware/render.js (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/middleware/render.js
rbb42dfb r834bcc3 27 27 const VIEWS_DIR = path.join(__dirname, '..', 'views'); 28 28 29 // App -versie (uit package.json) + korte commit-hash (uit .klonkt-version, door de30 // deploy geschreven) — getoond in de footer naast "Klonkt Beta". De hash loopt31 // automati sch mee bij élke deploy, dus de versie is nooit meer stale.29 // App version (from package.json) + short commit hash (from .klonkt-version, written by 30 // the deploy script) — shown in the footer next to "Klonkt Beta". The hash is updated 31 // automatically on every deploy, so the displayed version is never stale. 32 32 let APP_VERSION = ''; 33 33 try { … … 36 36 const sha = fs.readFileSync(path.join(__dirname, '..', '..', '.klonkt-version'), 'utf8').trim().slice(0, 7); 37 37 if (sha) APP_VERSION += ' · ' + sha; 38 } catch { /* geen .klonkt-version (lokale dev) */ } 39 } catch { /* geen versie beschikbaar */ } 40 41 // Site-tijdzone (Beheer → Instellingen). Leeg = server-default (UTC). Wordt 42 // toegepast op álle server-side geformatteerde datums zodat ze in de zone van 43 // de site staan i.p.v. UTC. 38 } catch { /* no .klonkt-version (local dev) */ } 39 } catch { /* no version available */ } 40 41 // Site timezone (Admin → Settings). Empty = server default (UTC). Applied to 42 // all server-side formatted dates so they display in the site's timezone instead of UTC. 44 43 const siteTimezone = () => getSetting('timezone') || undefined; 45 44 … … 58 57 const isPartial = req.headers['hx-request'] === 'true' || req.query.partial === '1'; 59 58 60 // Voorkom dat de browser een htmx-PARTIAL (alleen #pcms-main, zónder<head>/CSS)61 // onder dezelfde URL cachet en bij "terug" als volledige pagina serveert →62 // ongestylede HTML. Vary: HX-Request scheidt partial- en full-responses in de63 // cache; no-store op de partial zelf laat "terug" altijd de volledige pagina64 // opnieuw ophalen. (Vary geldt ook voor tussenliggende caches/Cloudflare.)59 // Prevent the browser from caching an htmx PARTIAL (only #pcms-main, without <head>/CSS) 60 // under the same URL and serving it as a full page on "back" → unstyled HTML. 61 // Vary: HX-Request separates partial and full responses in the cache; 62 // no-store on the partial forces "back" to always re-fetch the full page. 63 // (Vary also applies to intermediate caches / Cloudflare.) 65 64 res.setHeader('Vary', 'HX-Request'); 66 65 if (isPartial) res.setHeader('Cache-Control', 'no-store'); 67 66 68 // Bezit deze (niet-god) user een eigen site? Bepaalt of 'ie een "Beheer"-69 // ingang ziet (artiest-zelfbeheer). god ziet beheer sowieso (op rol).67 // Does this (non-god) user own a site? Determines whether they see an "Admin" 68 // entry (artist self-manage). god always sees admin (by role). 70 69 let _u = req.session?.user || null; 71 // Ververs avatar + rol uit de DB zodat een stale sessie (bv. na een72 // avatar -wijziging of rolwissel) zichzelf herstelt zonder opnieuw inloggen.70 // Refresh avatar + role from the DB so a stale session (e.g. after an 71 // avatar change or role switch) heals itself without a new login. 73 72 if (_u && _u.id) { 74 73 const _fresh = db.prepare('SELECT avatar_url, role, lang FROM users WHERE id = ?').get(_u.id); … … 78 77 db.prepare('SELECT 1 FROM sites WHERE owner_id = ? LIMIT 1').get(_u.id)); 79 78 80 // De avatar van de SITE-EIGENAAR (niet de kijker!) — voor de Klonkt-site-kop,81 // zodat de artiest z'n eigen account-foto als sitefoto kan gebruiken.79 // The avatar of the SITE OWNER (not the viewer!) — for the Klonkt site header, 80 // so the artist can use their own account photo as the site photo. 82 81 const _site = data.site || res.locals.site || null; 83 82 const siteOwnerAvatar = (_site && _site.owner_id) … … 85 84 : null; 86 85 87 // Kijker-modus: alles bekijken mag, niets wijzigen. Views gebruikencanMutate88 // om schrijf-knoppen (posten, opslaan, verwijderen) te verbergen/uit te zetten.86 // Viewer mode: may view everything, change nothing. Views use canMutate 87 // to hide/disable write buttons (post, save, delete). 89 88 const _isViewer = isViewer(_u); 90 89 91 // W ie ziet de "Beheer"-link? god/admin, een site-eigenaar (artiest-zelfbeheer),92 // én een kijker (mag het Beheer alleen-lezen inzien). Eén bron van waarheid,93 // gespiegeld in topnav/hub-nav/profielsheet — anders raakt de link verborgen94 // voor wie 'm wél mag zien (kijker zag 'm eerst nergens).90 // Who sees the "Admin" link? god/admin, a site owner (artist self-manage), 91 // and a viewer (may view Admin read-only). One source of truth, 92 // mirrored in topnav/hub-nav/profile sheet — otherwise the link gets hidden 93 // for those who should see it (viewer didn't see it anywhere before). 95 94 const _role = _u ? _u.role : null; 96 95 const canSeeBeheer = !!(_u && (_role === 'god' || _role === 'admin' || _role === 'kijker' || userOwnsSite)); 97 96 98 // Interface -taal: sessie-keuze (deze sessie) → eigen voorkeur van de ingelogde99 // gebruiker (users.lang) → admin-ingestelde standaard (Beheer) → env → browser → nl.97 // Interface language: session choice (this session) → logged-in user's own preference 98 // (users.lang) → admin-set default (Admin → Settings) → env → browser → nl. 100 99 const _lang = resolveLang(req, { 101 100 userLang: _u && _u.lang, … … 125 124 tenancy: res.locals.tenancy || 'solo', 126 125 hubTitle: getSetting('hub_title') || '', 127 footerNewsletter: getSetting('footer_newsletter') === '1', // n ieuwsbrief-aanmeldingin footer (premium)128 agendaEnabled: getSetting('agenda_enabled') === '1', // Agenda/evenementen tonen in de pill (premium, opt-in)126 footerNewsletter: getSetting('footer_newsletter') === '1', // newsletter sign-up in footer (premium) 127 agendaEnabled: getSetting('agenda_enabled') === '1', // show agenda/events in the pill (premium, opt-in) 129 128 platforms_catalog: PLATFORMS_CATALOG, 130 129 permissions: PermissionsService, … … 153 152 // looks "unclickable". Escape any non-ASCII to \uXXXX: the header stays 154 153 // ASCII-safe and remains valid JSON that htmx parses back unchanged. 155 // Per-site accent + palette zitten in de shell-<head> (style#pcms-site-accent156 // + html[data-palette]) en worden NIET mee-geswapt bij htmx-nav. Stuur ze mee157 // zodat de client ze bijwerkt — anders erft een artiest de kleuren van de158 // vorige pagina (bv. hub-paars i.p.v. eigen groen). Zelfde afleiding als shell.ejs.154 // Per-site accent + palette live in the shell <head> (style#pcms-site-accent 155 // + html[data-palette]) and are NOT swapped during htmx navigation. Send them along 156 // so the client updates them — otherwise an artist inherits the previous page's 157 // colours (e.g. hub-purple instead of their own green). Same derivation as shell.ejs. 159 158 const _navAccent = (_site && _site.accent && /^#[0-9a-fA-F]{6}$/.test(_site.accent)) 160 159 ? _site.accent : '#e8b04b'; … … 169 168 }).replace(/[-]/g, (ch) => '\\u' + ch.charCodeAt(0).toString(16).padStart(4, '0')); 170 169 res.setHeader('HX-Trigger-After-Settle', triggerJson); 171 // Site-chrome out-of-band mee-renderen, zodat de kop (topnav/profielkop/172 // view-switcher) bij navigatie ALTIJD bij de nieuwe pagina/artiest hoort—173 // terwijl de audioplayer (los in document.body) blijft leven (geen174 // verspringen). htmx vervangt #pcms-chrome via hx-swap-oob. Niet kritisch:175 // faalt 't, dan blijft de oude chrome staan (geencrash).170 // Render the site chrome out-of-band so the header (topnav/profile header/ 171 // view-switcher) ALWAYS matches the new page/artist on navigation — 172 // while the audio player (separate in document.body) keeps playing (no 173 // interruption). htmx replaces #pcms-chrome via hx-swap-oob. Non-critical: 174 // if it fails, the old chrome remains (no crash). 176 175 let oobChrome = ''; 177 176 try { … … 181 180 { async: false }, 182 181 ); 183 } catch (e) { /* chrome-OOB overslaan*/ }182 } catch (e) { /* skip chrome OOB */ } 184 183 return res.send(pageContent + oobChrome); 185 184 }
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)