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

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

Beheer: de vijf mediapagina's op een gedeelde ax-romp

admin/media, media/videos en admin/listeners vielen buiten het
ax-*-systeem waar audio en playlists al op zaten. Media en video's
stonden volledig op inline styles, listeners had eigen .lis-*-klassen in
een eigen style-blok. Drie ontwerpen achter vijf tabs.

Nu alle vijf dezelfde romp: dezelfde breedte, dezelfde kop met tagline,
tabs op dezelfde plek (na de terugknop, voor de kop) en dezelfde
terugknop-sleutel -- listeners gebruikte aaud.back waar de rest
nav.admin heeft.

De primitieven staan in partials/admin-styles.ejs. Ze stonden vijf keer
los: .ax-header, .ax-header h1, .ax-back en .ax-back:hover byte voor byte
gelijk in vijf bestanden, .ax-flash-ok/-err in vier. Gelijktrekken zonder
een gedeelde plek is eenmalig -- de volgende die een knop aanpast raakt
een van de kopieen. admin-playlists schreef zelf al boven zijn blok
waarom het misging: "both pages get refreshed independently".

De tabbalk droeg zijn eigen opmaak inline mee en kon daardoor niet
meebewegen; die zit nu ook in de partial. De actieve tab is
aria-current="page" in plaats van een klasse: dat is wat een schermlezer
nodig heeft, en de opmaak haakt er net zo goed op.

audio en playlists zijn NIET aangeraakt. Hun blokken bevatten @media- en
paginaeigen regels door elkaar, en die mechanisch scheiden met een regex
is precies het soort ingreep dat niet faalt maar liegt. Aparte bead.

scripts/render-admin-views.mjs rendert de drie views gevuld en leeg. De
suite stond op 1040 groen terwijl de nieuwe partial niet eens kon parsen
-- hij raakt geen enkele view, dus faalt hij nooit op opmaak.

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

  • Property mode set to 100644
File size: 3.3 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-media': { items: [{ file: 'a.jpg', url: '/m/a.jpg', kb: 12, usedCount: 0, hasVideo: true }], unusedCount: 1 },
30 'admin-videos': { items: [{ file: 'b.mp4', url: '/m/b.mp4', kb: 99, usedCount: 2 }] },
31 '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' }] },
32};
33const leeg = {
34 'admin-media': { items: [], unusedCount: 0 },
35 'admin-videos': { items: [] },
36 'admin-listeners': { luisteraars: [] },
37};
38
39let stuk = 0;
40for (const naam of Object.keys(gevuld)) {
41 for (const [label, data] of [['gevuld', gevuld[naam]], ['leeg', leeg[naam]]]) {
42 try {
43 const html = await ejs.renderFile(`src/views/pages/${naam}.ejs`, { ...basis, ...data });
44 const fouten = [];
45 // Tellen op de MARKUP, niet op de opmaak: het style-blok bevat zelf ook
46 // `aria-current="page"` (als selector) en telde eerst vrolijk mee.
47 const markup = html.replace(/<style>[\s\S]*?<\/style>/g, '');
48 // De vijf tabs moeten er staan, en precies een ervan is de actieve.
49 const tabs = (markup.match(/class="ax-tab"/g) || []).length;
50 const actief = (markup.match(/aria-current="page"/g) || []).length;
51 if (tabs !== 5) fouten.push(`${tabs} tabs i.p.v. 5`);
52 if (actief !== 1) fouten.push(`${actief} actieve tabs i.p.v. 1`);
53 // De gedeelde opmaak moet mee zijn gekomen.
54 if (!html.includes('.ax-tab[aria-current')) fouten.push('admin-styles ontbreekt');
55 if (!html.includes('class="container ax-page"')) fouten.push('ax-page-romp ontbreekt');
56 // Twee vormen van stille schade die er goed uitzien in de bron.
57 if (markup.includes("[object Promise]")) fouten.push('onopgeloste include');
58 if (html.includes('aria-current=&quot;')) fouten.push('aria-current is ge-escaped');
59 if (/undefined/.test(markup)) fouten.push('letterlijke "undefined" in de uitvoer');
60
61 if (fouten.length) { stuk++; console.log(`STUK ${naam} (${label}): ${fouten.join(' · ')}`); }
62 else console.log(`OK ${naam} (${label}) ${html.length} tekens`);
63 } catch (e) {
64 stuk++;
65 console.log(`STUK ${naam} (${label}): ${e.message.split('\n')[0]}`);
66 }
67 }
68}
69console.log(stuk ? `\n${stuk} stuk` : '\nalles rendert');
70process.exit(stuk ? 1 : 0);
Note: See TracBrowser for help on using the repository browser.