Changeset 495b019 in Klonkt for src/middleware


Ignore:
Timestamp:
10/25/2026 09:52:01 AM (2 days ago)
Author:
Bart <bart@…>
Children:
b4aaadd
Parents:
5d0d3f35
git-author:
Bart <bart@…> (10/14/2026 02:48:46 PM)
git-committer:
Bart <bart@…> (10/25/2026 09:52:01 AM)
Message:

Lay-outthema's: een pakket, de beheerder kiest, en de zijbalk als eerste

Een lay-out is nu een pakket: een map in src/themes/ met een theme.json (id,
naam, versie, contract, stylesheet) en de stylesheet zelf. De zijbalk is het
eerste ingebouwde thema; een thema van buiten installeren komt later en gaat
door dezelfde lader, zodat er één vorm is.

Dezelfde markup, een ander stelsel: een thema verandert geen template. Het
contract (1) is de afspraak over de ids en klassen waar het op mag bouwen; een
thema op een ander contract valt terug op de gewone kop in plaats van half te
werken. Elke regel staat onder html[data-layout="<id>"], en een toets bewaakt
dat, zodat een thema niets raakt zolang het niet gekozen is.

WIE KIEST: de beheerder, in het sitebeheer (sites.layout). Een bezoeker niet
-- de server zet data-layout zelf, het bezoekersscript met localStorage is
weg, en ?layout= werkt alleen als voorproefje voor wie de site beheert. Het
beheer houdt altijd de gewone kop, ook bij navigeren via htmx (de lay-out reist
mee in pcmsNav): een kapot thema mag je nooit buitensluiten van de instelling
waarmee je het uitzet.

Geserveerd op /themes/<id>/<versie>/<bestand>, met de versie in het pad als
cache-buster; alleen wat het pakket zelf noemt komt eruit. De actor noemt het
gekozen thema als shaer:theme, zodat Shaer het van zijn eigen site kan halen
in plaats van er zelf een te kiezen.

Co-Authored-By: Claude Opus 5.5 <claude@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/middleware/render.js

    r5d0d3f35 r495b019  
    2121import { emojiHtml, emojiName, parseQuote } from '../services/NoteRender.js';
    2222import ActivityPubService from '../services/ActivityPubService.js';
     23import ThemeService from '../services/ThemeService.js';
    2324import { imgProxyUrl } from '../services/ThumbnailService.js';
    2425import { audioEnabled as audioFeatureEnabled } from '../config/features.js';
    … …  
    187188    defaultLang: getSetting('default_lang'),
    188189  });
     190
     191  // Lay-out (experimental/theme): wie de site beheert, mag met ?layout= een
     192  // ander thema voorproeven; een bezoeker kiest niets.
     193  const _canManageSite = !!(_u && (_role === 'god' || _role === 'admin' || userOwnsSite));
     194  const _isAdminPage = String(viewName || '').startsWith('pages/admin')
     195    || String(data.bodyClass || '').split(/\s+/).includes('on-admin');
     196  const _preview = typeof req.query.layout === 'string' ? req.query.layout : null;
     197  const _layout = ThemeService.resolveLayout(_site, { isAdminPage: _isAdminPage, canManage: _canManageSite, preview: _preview });
     198  const _siteLayout = _site && _site.layout ? ThemeService.getLayout(_site.layout) : null;
     199  const _previewLayout = (_canManageSite && _preview) ? ThemeService.getLayout(_preview) : null;
     200  const _layoutSheets = [...new Set([_siteLayout, _previewLayout].filter(Boolean)
     201    .map((m) => ThemeService.layoutStylesheetUrl(m)))];
    189202
    190203  // Common locals
    … …  
    252265    appVersion: APP_VERSION,
    253266    bodyClass: data.bodyClass || 'on-home',
     267    // De lay-out van deze pagina (experimental/theme). null = de gewone kop.
     268    // Beheerpagina's altijd de gewone kop; ?layout= alleen voor wie de site
     269    // beheert (zie ThemeService.resolveLayout).
     270    layoutTheme: _layout ? { id: _layout.id, name: _layout.name } : null,
     271    // De stylesheets die mee moeten: die van de site en, bij een voorproefje,
     272    // die van het voorproefje. Ze staan er ook op een pagina die zelf geen
     273    // lay-out draagt (beheer): hun regels gelden alleen onder data-layout, en
     274    // wie vanuit het beheer naar de site navigeert heeft ze dan al.
     275    layoutSheets: _layoutSheets,
    254276    // Welke module(s) deze pagina nodig heeft (shaer-bqr). De shell zet ze op
    255277    // body[data-js]; de bootstrap daar importeert ze uit /assets/js/mod/.
    … …  
    299321      const _navJs = ('chrome ' + (locals.pageJs || '')).trim();
    300322      const triggerJson = JSON.stringify({
    301         pcmsNav: { bodyClass: locals.bodyClass, accent: _navAccent, palette: _navPalette, js: _navJs },
     323        pcmsNav: { bodyClass: locals.bodyClass, accent: _navAccent, palette: _navPalette, js: _navJs, layout: locals.layoutTheme ? locals.layoutTheme.id : 'top' },
    302324        pcmsPostSwap: data.post ? {
    303325          title: data.post.title,
Note: See TracChangeset for help on using the changeset viewer.