source: Klonkt/scripts/render-admin-views.mjs@ d68ee3a

main
Last change on this file since d68ee3a was daa8eb8, checked in by Robin <roboburr@…>, 3 weeks ago

Beheer: de terugknop op alle vijf dezelfde maat

Robin zag het (16-8): de knop naar /admin verschilde van grootte. Drie
pagina's kregen bij de omzetting class="ax-btn", audio en playlists
hielden de globale class="btn". Dat scheelt zichtbaar --

.btn padding 0.55rem 1rem · radius 5 · geen minimumhoogte
.ax-btn padding 0.6rem 1.1rem · radius 8 · min-height 44px

Het wordt .ax-btn: dit zijn ax-pagina's, en 44px is de maat waar een
vinger op past.

Nu een partial, voor een regel van niets, om dezelfde reden als bij de
tabbalk: een gedeeld element dat op elke pagina los staat loopt uiteen.
Dit is de tweede keer vandaag dat dat gebeurt, en de eerste keer had ik
het kunnen zien -- ik heb de tabbalk toen wel gedeeld gemaakt en de knop
ernaast niet.

scripts/render-admin-views.mjs dekt nu alle vijf de pagina's en
controleert de terugknop op zijn KLASSENAAM. Dat verschil ziet er in de
bron uit als hetzelfde, dus een controle die alleen kijkt of er een link
staat zou het niet vinden. Nagelopen dat hij kan falen: met .btn erin
meldt hij 10 stuk, hersteld nul.

Opmaak nagemeten met admin-css-gelijk.mjs: geen regel verdwenen, geen
regel veranderd, geen regel erbij op alle vijf.

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

  • Property mode set to 100644
File size: 4.1 KB
Line 
1/**
2 * Rendert de beheer-views los, gevuld en leeg.
3 *
4 * WAAROM DIT ER IS. De testsuite raakt de EJS-views niet aan: op 16-8 stond hij
5 * op 1040 groen terwijl partials/admin-styles.ejs niet eens kon parsen ("Could
6 * not find matching close tag"). Een controle die niet kan falen op wat je
7 * verandert is geen bewijs -- en aan een view verander je opmaak, dus faalt de
8 * suite er nooit op.
9 *
10 * Hij dekt BEIDE takken: met items en zonder. De lege tak is andere code, en
11 * dat is net de tak die je bij het bouwen niet ziet omdat je scherm vol staat.
12 *
13 * LET OP: rendert bewust ZONDER { async: true }. Met die vlag levert `include`
14 * een Promise op die als "[object Promise]" in de uitvoer belandt -- dat kostte
15 * hier een ronde. De app rendert ook synchroon.
16 *
17 * node scripts/render-admin-views.mjs
18 */
19import ejs from 'ejs';
20
21const t = (k) => k;
22const basis = {
23 t, thumb: (u) => u, formatDate: (d) => String(d || ''),
24 audioOn: true, success: null, error: null, csrfToken: 'x',
25 siteUrlBase: '', locale: 'nl',
26};
27
28const gevuld = {
29 'admin-audio': { tracks: [], playlists: [], maxBytesMb: 20, maxWavMb: 100 },
30 'admin-playlists': { playlists: [] },
31 'admin-media': { items: [{ file: 'a.jpg', url: '/m/a.jpg', kb: 12, usedCount: 0, hasVideo: true }], unusedCount: 1 },
32 'admin-videos': { items: [{ file: 'b.mp4', url: '/m/b.mp4', kb: 99, usedCount: 2 }] },
33 'admin-listeners': { luisteraars: [{ actor_uri: 'https://x/y', name: 'Zoe', handle: '@zoe@x', icon: '/i.png', created_at: '2026-08-01', last_delivery_at: null, last_error_at: '2026-08-02' }] },
34};
35const leeg = {
36 'admin-audio': { tracks: [], playlists: [], maxBytesMb: 20, maxWavMb: 100 },
37 'admin-playlists': { playlists: [] },
38 'admin-media': { items: [], unusedCount: 0 },
39 'admin-videos': { items: [] },
40 'admin-listeners': { luisteraars: [] },
41};
42
43let stuk = 0;
44for (const naam of Object.keys(gevuld)) {
45 for (const [label, data] of [['gevuld', gevuld[naam]], ['leeg', leeg[naam]]]) {
46 try {
47 const html = await ejs.renderFile(`src/views/pages/${naam}.ejs`, { ...basis, ...data });
48 const fouten = [];
49 // Tellen op de MARKUP, niet op de opmaak: het style-blok bevat zelf ook
50 // `aria-current="page"` (als selector) en telde eerst vrolijk mee.
51 const markup = html.replace(/<style>[\s\S]*?<\/style>/g, '');
52 // De vijf tabs moeten er staan, en precies een ervan is de actieve.
53 const tabs = (markup.match(/class="ax-tab"/g) || []).length;
54 const actief = (markup.match(/aria-current="page"/g) || []).length;
55 if (tabs !== 5) fouten.push(`${tabs} tabs i.p.v. 5`);
56 if (actief !== 1) fouten.push(`${actief} actieve tabs i.p.v. 1`);
57 // De gedeelde opmaak moet mee zijn gekomen.
58 if (!html.includes('.ax-tab[aria-current')) fouten.push('admin-styles ontbreekt');
59 if (!html.includes('class="container ax-page"')) fouten.push('ax-page-romp ontbreekt');
60 // De terugknop, met NAAM en al. Robin zag op 16-8 dat hij van grootte
61 // verschilde: drie pagina's hadden ax-btn en twee de globale btn, en dat
62 // scheelt 10px hoogte en een andere radius. Dit is de regel die dat
63 // vasthoudt -- de klasse staat er letterlijk in, want juist zo'n verschil
64 // ziet er in de bron uit als hetzelfde.
65 const terug = /<a href="\/admin" class="([^"]+)">/.exec(markup);
66 if (!terug) fouten.push('geen terugknop naar /admin');
67 else if (terug[1] !== 'ax-btn') fouten.push('terugknop heeft class="' + terug[1] + '" i.p.v. ax-btn');
68 // Twee vormen van stille schade die er goed uitzien in de bron.
69 if (markup.includes("[object Promise]")) fouten.push('onopgeloste include');
70 if (html.includes('aria-current=&quot;')) fouten.push('aria-current is ge-escaped');
71 if (/undefined/.test(markup)) fouten.push('letterlijke "undefined" in de uitvoer');
72
73 if (fouten.length) { stuk++; console.log(`STUK ${naam} (${label}): ${fouten.join(' · ')}`); }
74 else console.log(`OK ${naam} (${label}) ${html.length} tekens`);
75 } catch (e) {
76 stuk++;
77 console.log(`STUK ${naam} (${label}): ${e.message.split('\n')[0]}`);
78 }
79 }
80}
81console.log(stuk ? `\n${stuk} stuk` : '\nalles rendert');
82process.exit(stuk ? 1 : 0);
Note: See TracBrowser for help on using the repository browser.