source: Klonkt/src/views/partials/admin-styles.ejs@ 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: 10.2 KB
Line 
1<%# De ax-*-primitieven voor de beheerpagina's, op EEN plek.
2
3 WAAROM DIT BESTAAT. Deze regels stonden vijf keer los in vijf pagina's, en
4 admin-playlists schreef er zelf boven waarom: "Define them here too so this
5 page is self-contained -- both pages get refreshed independently." Dat is
6 precies wat er daarna gebeurde. Gemeten op 16-8: .ax-header, .ax-header h1,
7 .ax-back en .ax-back:hover stonden in vijf bestanden byte voor byte gelijk,
8 .ax-flash-ok/-err in vier -- terwijl .ax-page in de ene 880px was en in
9 account 720px, en admin-media en admin-videos helemaal buiten het systeem
10 vielen met alles inline.
11
12 Gelijktrekken zonder dit is eenmalig: de volgende die een knop aanpast doet
13 dat in een van de acht kopieen en dan lopen ze weer uiteen. De vorm moet de
14 fout onmogelijk maken, niet alleen onwaarschijnlijk -- zelfde afweging als
15 bij de luisteraarstabel.
16
17 HOE JE HEM GEBRUIKT: neem hem met een include bovenaan de pagina op, en zet
18 daarna alleen nog in een eigen style-blok wat ECHT bij die ene pagina hoort.
19 Staat een regel in twee pagina's, dan hoort hij hier.
20
21 Een <style>-partial en geen los .css-bestand omdat shell.ejs geen
22 pageCss-haak heeft (wel pageJs) en een globale link deze regels op elke
23 pagina van de site zou laden. %>
24<style>
25/* ─── Paginaromp ───────────────────────────────────────────────── */
26.ax-page { max-width: 880px; margin: 1.5rem auto 4rem; padding: 0 1rem; }
27.ax-header { display: flex; align-items: flex-start; gap: 0.75rem; margin-bottom: 1.5rem; }
28.ax-header h1 { font-family: var(--font-display, serif); font-size: 1.75rem; margin: 0 0 0.25rem; }
29.ax-tagline { color: var(--ink-muted, var(--ink-soft)); margin: 0; font-size: 0.9rem; line-height: 1.5; }
30.ax-tagline code { background: var(--paper-2); padding: 0.1em 0.4em; border-radius: 4px; font-size: 0.9em; }
31.ax-back {
32 display: inline-flex; align-items: center; justify-content: center;
33 width: 40px; height: 40px;
34 border: 1px solid var(--rule); border-radius: 8px;
35 background: var(--paper); color: var(--ink); text-decoration: none;
36 font-size: 1.1rem; flex-shrink: 0; transition: border-color 120ms;
37}
38.ax-back:hover { border-color: var(--accent); }
39
40.ax-actions-bar { display: flex; margin-bottom: 1rem; }
41
42/* ─── Tabbalk ──────────────────────────────────────────────────── */
43/* Stond volledig inline in partials/media-tabs.ejs -- een gedeeld element dat
44 zijn eigen opmaak meedroeg, en daardoor niet mee kon met de rest. */
45.ax-tabs {
46 display: flex; gap: 0.4rem; flex-wrap: wrap;
47 margin: 0 0 1.25rem;
48 border-bottom: 1px solid var(--rule);
49}
50.ax-tab {
51 display: inline-flex; align-items: center;
52 padding: 0.55rem 0.9rem;
53 border: 1px solid var(--rule); border-bottom: none;
54 border-radius: 8px 8px 0 0;
55 background: var(--paper-2); color: var(--ink);
56 font-family: var(--font-ui, system-ui), sans-serif;
57 font-size: 0.9rem; text-decoration: none;
58 opacity: 0.8; transition: opacity 120ms, border-color 120ms;
59}
60.ax-tab:hover { opacity: 1; border-color: var(--accent); }
61.ax-tab[aria-current="page"] {
62 opacity: 1; font-weight: 600;
63 background: var(--paper);
64 border-bottom: 2px solid var(--accent);
65}
66
67/* ─── Meldingen ────────────────────────────────────────────────── */
68.ax-flash { padding: 0.75rem 1rem; border-radius: 8px; margin-bottom: 1rem; font-size: 0.9rem; }
69.ax-flash-ok { background: rgba(40,160,90,.15); color: #2a9d5e; border: 1px solid rgba(40,160,90,.3); }
70.ax-flash-err { background: rgba(200,60,60,.15); color: #c33; border: 1px solid rgba(200,60,60,.3); }
71
72/* ─── Kaart ────────────────────────────────────────────────────── */
73.ax-card {
74 background: var(--paper);
75 border: 1px solid var(--rule);
76 border-radius: 12px;
77 padding: 1.25rem;
78 margin-bottom: 1rem;
79}
80
81/* ─── Knoppen ──────────────────────────────────────────────────── */
82.ax-btn {
83 display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
84 padding: 0.6rem 1.1rem;
85 border: 1px solid var(--rule); background: var(--paper-2);
86 color: var(--ink);
87 font-family: var(--font-ui, system-ui), sans-serif;
88 font-size: 0.95rem; font-weight: 500;
89 text-decoration: none; border-radius: 8px; cursor: pointer;
90 min-height: 44px;
91 transition: background 120ms, border-color 120ms;
92 -webkit-tap-highlight-color: transparent;
93}
94.ax-btn:hover { border-color: var(--accent); }
95.ax-btn-primary { background: var(--accent); color: white; border-color: var(--accent); }
96.ax-btn-primary:hover { opacity: 0.92; border-color: var(--accent); }
97/* admin-audio heeft paper-2, admin-playlists transparent. Hier audio's waarde:
98 .ax-btn is al paper-2, dus dit is daar een no-op en verandert niets aan wat
99 er nu staat. Wie de twee ooit echt wil laten verschillen, kies dan bewust. */
100.ax-btn-secondary { background: var(--paper-2); }
101.ax-btn-danger { border-color: #b4452e; color: #b4452e; background: transparent; }
102.ax-btn-danger:hover { background: rgba(180,69,46,.1); border-color: #b4452e; }
103.ax-btn-sm { min-height: 0; padding: 0.3rem 0.6rem; font-size: 0.78rem; }
104
105.ax-icon-btn {
106 display: inline-flex; align-items: center; justify-content: center;
107 width: 40px; height: 40px;
108 border: 1px solid var(--rule); border-radius: 8px;
109 background: var(--paper-2); color: var(--ink);
110 cursor: pointer; font-size: 1rem;
111 transition: background 120ms, border-color 120ms, color 120ms;
112}
113.ax-icon-btn:hover { border-color: var(--accent); }
114.ax-icon-btn-danger:hover { color: #dc2626; border-color: #dc2626; }
115
116/* ─── Lege toestand ────────────────────────────────────────────── */
117.ax-empty { text-align: center; padding: 2rem 1rem; color: var(--ink-muted, var(--ink-soft)); }
118.ax-empty-icon { font-size: 2.5rem; margin-bottom: 0.5rem; opacity: 0.5; }
119.ax-empty p { margin: 0; }
120.ax-empty-sub { font-size: 0.85rem; margin-top: 0.5rem !important; }
121
122/* ─── Lijstrij (audio, playlists, luisteraars) ─────────────────── */
123.ax-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.6rem; }
124.ax-track {
125 display: grid;
126 grid-template-columns: 64px 1fr auto;
127 gap: 0.85rem; align-items: center;
128 padding: 0.85rem;
129 background: var(--paper);
130 border: 1px solid var(--rule);
131 border-radius: 12px;
132 transition: border-color 120ms;
133}
134.ax-track:hover { border-color: var(--accent); }
135.ax-track-cover {
136 width: 64px; height: 64px; border-radius: 8px;
137 background: var(--paper-2);
138 display: flex; align-items: center; justify-content: center;
139 font-family: var(--font-display, serif);
140 font-size: 1.5rem; color: var(--accent);
141 flex-shrink: 0;
142 overflow: hidden;
143}
144.ax-track-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
145.ax-track-meta { min-width: 0; display: flex; flex-direction: column; gap: 0.25rem; }
146.ax-track-title {
147 font-family: var(--font-display, serif);
148 font-weight: 600; font-size: 1.05rem; color: var(--ink);
149 display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap;
150}
151.ax-pill {
152 font-family: var(--font-ui);
153 font-size: 0.7rem; font-weight: 500;
154 color: var(--ink-soft);
155 background: var(--paper-2);
156 padding: 0.15em 0.55em; border-radius: 999px;
157 letter-spacing: 0;
158}
159.ax-track-sub {
160 font-size: 0.85rem;
161 color: var(--ink-muted, var(--ink-soft));
162 display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center;
163}
164.ax-track-sep { opacity: 0.5; }
165.ax-embed {
166 display: inline-block;
167 background: var(--paper-2);
168 padding: 0.15rem 0.5rem;
169 border-radius: 4px;
170 font-family: var(--font-mono, ui-monospace, monospace);
171 font-size: 0.75rem;
172 color: var(--ink-soft);
173 cursor: pointer; user-select: all;
174 margin-top: 0.15rem;
175 word-break: break-all;
176 align-self: flex-start;
177 transition: background 120ms;
178}
179.ax-embed:hover { background: var(--rule); }
180.ax-embed.is-copied { background: rgba(40,160,90,0.2); color: #2a9d5e; }
181.ax-track-actions { display: flex; gap: 0.4rem; flex-shrink: 0; }
182
183/* ─── Tegelraster (afbeeldingen, video's) ──────────────────────── */
184/* Dezelfde randen, hoeken en achtergrond als .ax-track, alleen in een raster
185 in plaats van een rij -- zodat een plaatjespagina en een lijstpagina van
186 hetzelfde ontwerp zijn en niet van twee. */
187.ax-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(var(--ax-tile, 150px), 1fr)); }
188.ax-tile {
189 border: 1px solid var(--rule); border-radius: 12px;
190 overflow: hidden; background: var(--paper);
191 transition: border-color 120ms;
192}
193.ax-tile:hover { border-color: var(--accent); }
194.ax-tile-media { position: relative; background: var(--paper-2); }
195.ax-tile-media img, .ax-tile-media video { width: 100%; height: 100%; display: block; }
196.ax-tile-body { padding: 0.55rem 0.65rem; font-size: 0.8rem; }
197.ax-tile-meta { color: var(--ink-muted, var(--ink-soft)); }
198.ax-tile-actions { display: flex; gap: 0.4rem; margin-top: 0.45rem; }
199.ax-tile-badge {
200 position: absolute; top: 6px; left: 6px; z-index: 1;
201 background: #b4452e; color: #fff;
202 border-radius: 6px; padding: 1px 6px; font-size: 0.68rem;
203}
204.ax-tile-badge-r { left: auto; right: 6px; background: rgba(0,0,0,.6); }
205
206/* ─── Mobiel ───────────────────────────────────────────────────── */
207@media (max-width: 480px) {
208 .ax-track {
209 grid-template-columns: 56px 1fr;
210 grid-template-areas: "cover meta" "actions actions";
211 gap: 0.6rem;
212 }
213 .ax-track-cover { grid-area: cover; width: 56px; height: 56px; }
214 .ax-track-meta { grid-area: meta; }
215 .ax-track-actions {
216 grid-area: actions;
217 justify-content: flex-end;
218 border-top: 1px solid var(--rule);
219 padding-top: 0.5rem;
220 margin-top: 0.25rem;
221 }
222}
223</style>
Note: See TracBrowser for help on using the repository browser.