source: Klonkt/src/views/pages/admin-site-edit.ejs@ 598f090

main
Last change on this file since 598f090 was 70e9147, checked in by Bart <bart@…>, 3 weeks ago

Lezen vervangt Tijdlijn: twee keuzes solo, één in de cirkel

De chronologische lijst was de standaardweergave en Lezen de nieuwkomer; nu
andersom, en Tijdlijn verdwijnt als KEUZE. De opmaak zelf blijft bestaan
(.feed-timeline draagt nog het archief, de cirkel en de postpagina) -- alleen
kies je er niet meer voor, want voor hele berichten was Lezen de betere vorm.

Solo: Lezen | Grid. Cirkel: alleen Grid, want Lezen bestaat daar niet (dat zijn
berichten van anderen, van hun servers).

TWEE DINGEN DIE STIL KAPOT WAREN GEGAAN als ik alleen de knop had weggehaald:

  • Wie hier eerder was heeft 'timeline' in zijn localStorage staan. Zonder vertaling houdt die bezoeker een weergave waar geen knop meer bij hoort: de pil helemaal grijs en een feed die niet is wat hij ooit koos. 'timeline' leest nu als 'reader'. Hetzelfde geldt voor sites met feed_view_default='timeline' in de database -- die worden bij het lezen naar reader vertaald, zonder migratie: alles wat geen 'grid' is, is lezen.
  • Op de cirkel is Grid nu de ENIGE knop, en een knop die al actief is doet normaal niets. Dan zit je in Grid zonder weg terug. Is er één knop en staat hij aan, dan brengt hij je nu terug naar de standaard -- daar is dat de gewone lijst.

Nagelopen in de browser: solo toont Lezen|Grid met Lezen actief, een site die
nog 'timeline' opgeslagen heeft rendert als reader, en de cirkelknop gaat aan,
uit, aan.

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

  • Property mode set to 100644
File size: 21.2 KB
Line 
1<div class="container admin-site-edit-page">
2 <p><a href="/admin" class="btn">&larr; <%= t('asite.back_admin') %></a></p>
3 <h1><%= isNew ? t('asite.title_new') : t('asite.title_edit') + ': ' + site.title %></h1>
4
5 <% if (typeof success !== 'undefined' && success) { %><div class="audio-flash audio-flash--ok"><%= success %></div><% } %>
6 <% if (error) { %><div class="audio-flash audio-flash--err"><%= error %></div><% } %>
7
8 <form method="post" action="<%= isNew ? '/admin/sites/create' : '/admin/sites/' + site.slug + '/save' %>" class="site-form">
9
10 <fieldset>
11 <legend><%= t('asite.identity') %></legend>
12 <label>
13 <span><%= t('asite.slug') %> <% if (!isNew) { %><em><%= t('asite.slug_fixed') %></em><% } %></span>
14 <span class="slug-url">
15 <span class="slug-url-host" id="slug-host"
16 data-prefix="/">website.com/</span><input
17 type="text" name="slug" id="slug-input" class="slug-url-input" value="<%= site.slug %>" required <% if (!isNew) { %>readonly<% } %>
18 pattern="[a-z0-9_-]{2,40}" placeholder="<%= t('asite.slug_placeholder') %>"
19 autocapitalize="none" autocorrect="off" spellcheck="false">
20 </span>
21 </label>
22 <label>
23 <span><%= t('asite.field_title') %> <small class="form-hint-inline"><%= t('asite.field_title_hint') %></small></span>
24 <input type="text" name="title" value="<%= site.title || '' %>" required maxlength="200">
25 </label>
26 <label>
27 <span><%= t('asite.tagline') %> <small class="form-hint-inline"><%= t('asite.tagline_hint') %></small></span>
28 <input type="text" name="tagline" value="<%= site.tagline || '' %>" maxlength="200">
29 </label>
30 <label>
31 <span><%= t('asite.bio') %> <small class="form-hint-inline"><%= t('asite.bio_hint') %></small></span>
32 <textarea name="description" rows="3" maxlength="500"><%= site.description || '' %></textarea>
33 </label>
34 <label>
35 <span><%= t('asite.profile_photo') %></span>
36 <div class="photo-picker" id="photo-picker">
37 <div class="photo-thumb" id="photo-thumb" <%= site.profile_photo ? '' : 'data-empty' %>>
38 <img id="photo-preview" src="<%= avatar(site.profile_photo || '', 128) %>" alt="" <%= site.profile_photo ? '' : 'hidden' %>>
39 <span class="photo-empty" aria-hidden="true">
40 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
41 </span>
42 </div>
43 <div class="photo-controls">
44 <input type="text" name="profile_photo" id="photo-url" value="<%= site.profile_photo || '' %>" placeholder="<%= t('asite.photo_url_placeholder') %>">
45 <div class="photo-actions">
46 <button type="button" class="btn" id="photo-upload-trigger"><%= t('asite.photo_upload') %></button>
47 <button type="button" class="btn" id="photo-clear" <%= site.profile_photo ? '' : 'hidden' %>><%= t('asite.photo_clear') %></button>
48 <small id="photo-status" class="form-hint photo-status"></small>
49 </div>
50 <input type="file" id="photo-upload-field" accept="image/jpeg,image/png,image/webp,image/gif" hidden>
51 </div>
52 </div>
53 </label>
54 <label>
55 <span><%= t('asite.language') %></span>
56 <input type="text" name="language" value="<%= site.language || 'nl' %>" maxlength="8">
57 </label>
58 <label class="cb">
59 <input type="checkbox" name="profile_enabled" value="1" <%= site.profile_enabled ? 'checked' : '' %>>
60 <span><%= t('asite.profile_enabled') %></span>
61 </label>
62 </fieldset>
63
64 <fieldset>
65 <legend><%= t('asite.appearance') %></legend>
66
67 <%# ── Curated accent picker ───────────────────────────────────────
68 Was a free-form <input type="color">; now a fixed set of 8 hand-
69 picked colors that work in both light and dark themes. The hex is
70 still what's stored in the DB — we just constrain WHICH hex. %>
71 <fieldset class="accent-grid">
72 <legend><%= t('asite.accent_color') %></legend>
73 <% const _curAccent = (site.accent || '#c2410c').toLowerCase(); %>
74 <% accents.forEach(function(a) { %>
75 <label class="accent-swatch" title="<%= a.name %>">
76 <input type="radio" name="accent" value="<%= a.color %>" <%= a.color.toLowerCase() === _curAccent ? 'checked' : '' %>>
77 <span class="accent-dot" style="background: <%= a.color %>;" aria-hidden="true"></span>
78 <span class="accent-swatch-name"><%= a.name %></span>
79 </label>
80 <% }); %>
81 </fieldset>
82
83 <%# ── Default theme for new visitors ───────────────────────────
84 'auto' (empty value) lets the browser/OS decide via prefers-color-scheme.
85 'light' / 'dark' force the site default for visitors who haven't picked
86 their own preference yet. Logged-in users with users.theme set, and
87 visitors with a localStorage override, still win over this default. %>
88 <fieldset class="theme-default">
89 <legend><%= t('asite.theme_default') %></legend>
90 <% const td = site.theme_override || ''; %>
91 <label class="cb">
92 <input type="radio" name="theme_override" value="" <%= td === '' ? 'checked' : '' %>>
93 <span><%= t('asite.theme_auto') %></span>
94 </label>
95 <label class="cb">
96 <input type="radio" name="theme_override" value="light" <%= td === 'light' ? 'checked' : '' %>>
97 <span><%= t('asite.theme_light') %></span>
98 </label>
99 <label class="cb">
100 <input type="radio" name="theme_override" value="dark" <%= td === 'dark' ? 'checked' : '' %>>
101 <span><%= t('asite.theme_dark') %></span>
102 </label>
103 </fieldset>
104
105 <fieldset class="palette-grid">
106 <legend><%= t('asite.palette') %></legend>
107 <% palettes.forEach(function(p) { %>
108 <label class="palette-swatch">
109 <input type="radio" name="palette" value="<%= p.key %>" <%= (site.palette || 'klonkt') === p.key ? 'checked' : '' %>>
110 <span class="palette-preview" aria-hidden="true">
111 <span class="pp-half pp-light" style="background: <%= p.light.paper %>; color: <%= p.light.ink %>;">
112 <span class="pp-letter">Aa</span>
113 <span class="pp-accent" style="background: <%= p.light.accent %>;"></span>
114 </span>
115 <span class="pp-half pp-dark" style="background: <%= p.dark.paper %>; color: <%= p.dark.ink %>;">
116 <span class="pp-letter">Aa</span>
117 <span class="pp-accent" style="background: <%= p.dark.accent %>;"></span>
118 </span>
119 </span>
120 <span class="palette-swatch-name"><%= p.name %></span>
121 </label>
122 <% }); %>
123 </fieldset>
124 </fieldset>
125
126 <%# Live preview: selecting an accent / theme / palette re-themes this page
127 instantly (reverts on reload; persists on save). %>
128 <%# Het script van deze pagina staat in assets/js/mod/admin-site-edit.js (shaer-bqr). %>
129
130 <fieldset>
131 <legend><%= t('asite.behavior') %></legend>
132 <label class="cb">
133 <input type="checkbox" name="is_public" value="1" <%= site.is_public ? 'checked' : '' %>>
134 <span><%= t('asite.is_public') %></span>
135 </label>
136 <label class="cb">
137 <input type="checkbox" name="robots_index" value="1" <%= site.robots_index ? 'checked' : '' %>>
138 <span><%= t('asite.robots_index') %></span>
139 </label>
140 <% if (typeof audioEnabled === 'undefined' || audioEnabled) { %>
141 <label class="cb">
142 <input type="checkbox" name="enable_audio_player" value="1" <%= site.enable_audio_player ? 'checked' : '' %>>
143 <span><%= t('asite.enable_audio') %></span>
144 </label>
145 <% } %>
146 <label class="cb">
147 <input type="checkbox" name="approve_followers" value="1" <%= site.approve_followers ? 'checked' : '' %>>
148 <span><%= t('asite.approve_followers') %></span>
149 </label>
150 </fieldset>
151
152 <fieldset class="profile-links-fieldset">
153 <legend><%= t('asite.links') %></legend>
154 <p class="form-hint"><%= t('asite.links_hint') %></p>
155
156 <div id="profile-links-rows">
157 <% (parsedLinks || []).forEach(function(l) { %>
158 <div class="profile-link-row">
159 <select name="profile_link_platform[]">
160 <% platforms.forEach(function(p) { %>
161 <option value="<%= p.key %>" <%= l.platform === p.key ? 'selected' : '' %>><%= p.label %></option>
162 <% }); %>
163 </select>
164 <input type="text" name="profile_link_url[]" value="<%= l.url %>" placeholder="https://…" required>
165 <button type="button" class="btn btn-danger pl-remove">×</button>
166 </div>
167 <% }); %>
168 </div>
169
170 <template id="profile-link-template">
171 <div class="profile-link-row">
172 <select name="profile_link_platform[]">
173 <% platforms.forEach(function(p) { %>
174 <option value="<%= p.key %>"><%= p.label %></option>
175 <% }); %>
176 </select>
177 <input type="text" name="profile_link_url[]" placeholder="https://…" required>
178 <button type="button" class="btn btn-danger pl-remove">×</button>
179 </div>
180 </template>
181
182 <button type="button" id="profile-link-add" class="btn"><%= t('asite.link_add') %></button>
183 </fieldset>
184
185 <%# Aliassen en verhuizen staan sinds 14-8 op /admin/migrate, bij elkaar met
186 exporteren, importeren en ophalen (Robin: alle migratie-opties op de
187 migrate-pagina). Ze hoorden hier ook niet thuis: dit scherm gaat over hoe
188 je site eruitziet, en een verhuizing is geen uiterlijk. Alleen de
189 wegwijzer blijft, want wie ze hier zocht moet ze kunnen vinden. %>
190 <fieldset>
191 <legend><%= t('asite.aliases') %></legend>
192 <p class="form-hint"><%= t('asite.moved_to_migrate') %></p>
193 <p><a href="/admin/migrate" class="btn"><%= t('admin.b_migrate') %></a></p>
194 </fieldset>
195
196 <fieldset>
197 <legend><%= t('asite.feed_view') %></legend>
198 <label>
199 <span><%= t('asite.feed_default') %></span>
200 <select name="feed_view_default">
201 <option value="reader" <%= site.feed_view_default !== 'grid' ? 'selected' : '' %>><%= t('asite.feed_reader') %></option>
202 <option value="grid" <%= site.feed_view_default === 'grid' ? 'selected' : '' %>><%= t('asite.feed_grid') %></option>
203 </select>
204 </label>
205 <label class="cb">
206 <input type="checkbox" name="feed_view_switch" value="1" <%= site.feed_view_switch ? 'checked' : '' %>>
207 <span><%= t('asite.feed_switch') %></span>
208 </label>
209 <label class="cb">
210 <input type="checkbox" name="show_search" value="1" <%= site.show_search ? 'checked' : '' %>>
211 <span><%= t('asite.show_search') %></span>
212 </label>
213 <label class="cb">
214 <input type="checkbox" name="show_archive_link" value="1" <%= site.show_archive_link ? 'checked' : '' %>>
215 <span><%= t('asite.show_archive') %></span>
216 </label>
217 </fieldset>
218
219 <fieldset class="seo-pointer">
220 <legend><%= t('asite.seo') %></legend>
221 <p><%= t('asite.seo_pointer') %> <a href="/admin/seo"><%= t('asite.seo_link') %></a>.</p>
222 </fieldset>
223
224 <fieldset>
225 <legend><%= t('asite.custom_legend') %> <em><%= t('asite.optional') %></em></legend>
226 <label>
227 <span><%= t('asite.custom_css') %></span>
228 <textarea name="custom_css" rows="3" placeholder=".foo { color: red; }"><%= site.custom_css || '' %></textarea>
229 </label>
230 <label>
231 <span><%= t('asite.custom_head') %></span>
232 <textarea name="custom_head_html" rows="3" placeholder="<meta name=&quot;...&quot;>"><%= site.custom_head_html || '' %></textarea>
233 </label>
234 <label>
235 <span><%= t('asite.custom_foot') %></span>
236 <textarea name="custom_foot_html" rows="3"><%= site.custom_foot_html || '' %></textarea>
237 </label>
238 </fieldset>
239
240 <button type="submit" class="btn btn-primary"><%= isNew ? t('asite.submit_create') : t('asite.submit_save') %></button>
241 </form>
242
243</div>
244
245
246
247<style>
248.admin-site-edit-page { max-width: 760px; margin: 3rem auto; padding: 0 1rem; }
249.admin-site-edit-page h1 { font-family: var(--font-display, serif); font-size: 1.8rem; margin: 0 0 1.5rem; }
250
251.site-form { display: flex; flex-direction: column; gap: 1.5rem; min-width: 0; }
252/* Mobile: a <fieldset> has a browser-default min-inline-size:min-content and
253 therefore does NOT shrink → the entire form became wider than the screen. min-width:0
254 forces it to shrink; form fields get max-width:100% + border-box so they
255 never overflow their fieldset. */
256.site-form fieldset { min-width: 0; }
257.site-form input, .site-form select, .site-form textarea { min-width: 0; max-width: 100%; box-sizing: border-box; }
258.site-form fieldset {
259 border: 1px solid var(--rule);
260 border-radius: 8px;
261 padding: 1rem 1.25rem;
262 background: var(--paper-2);
263 display: flex;
264 flex-direction: column;
265 gap: 0.75rem;
266}
267.site-form fieldset.palette-grid {
268 display: grid;
269 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
270 background: var(--paper);
271 margin-top: 0.5rem;
272}
273/* Theme default radios — horizontal, sits between accent + palette */
274.site-form fieldset.theme-default {
275 display: flex; flex-direction: row; flex-wrap: wrap; gap: 1rem;
276 background: var(--paper);
277 margin-top: 0.5rem;
278}
279.site-form fieldset.theme-default label.cb { font-size: 0.9rem; color: var(--ink); }
280.site-form fieldset legend { font-family: var(--font-display, serif); font-size: 1rem; padding: 0 0.4rem; }
281.site-form label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; color: var(--ink-muted, var(--ink-soft)); }
282.site-form label.cb { flex-direction: row; align-items: center; gap: 0.5rem; }
283.site-form input[type="text"], .site-form input[type="color"], .site-form textarea {
284 padding: 0.55rem 0.85rem;
285 border: 1px solid var(--rule);
286 border-radius: 5px;
287 background: var(--paper);
288 color: var(--ink);
289 font-family: inherit;
290 font-size: 0.95rem;
291}
292.site-form input[type="color"] { padding: 0.2rem; height: 38px; }
293.site-form textarea { resize: vertical; min-height: 60px; font-family: var(--font-mono, monospace); font-size: 0.85rem; }
294.site-form input[readonly] { opacity: 0.6; cursor: not-allowed; background: var(--paper-2); }
295
296/* Slug as URL field: dimmed host prefix + the slug itself in the accent colour. */
297.slug-url {
298 display: flex; align-items: stretch;
299 border: 1px solid var(--rule); border-radius: 5px;
300 background: var(--paper); overflow: hidden;
301 transition: border-color 120ms;
302}
303.slug-url:focus-within { border-color: var(--accent); }
304.slug-url-host {
305 display: inline-flex; align-items: center;
306 padding-left: 0.85rem;
307 color: var(--ink-muted, var(--ink-soft));
308 white-space: nowrap; user-select: none;
309 font-size: 0.95rem;
310}
311.site-form .slug-url-input {
312 flex: 1 1 auto; min-width: 0;
313 border: none !important; border-radius: 0 !important;
314 background: transparent !important;
315 color: var(--accent) !important; font-weight: 700;
316 padding: 0.55rem 0.85rem 0.55rem 0.1rem;
317}
318.site-form .slug-url-input:focus { outline: none; }
319.site-form .slug-url-input[readonly] {
320 opacity: 1; cursor: default; background: transparent !important;
321}
322
323/* Selects: same look as the inputs, with a custom chevron instead of the bare
324 native arrow. The open option list is still rendered by the browser. */
325.site-form select {
326 appearance: none;
327 -webkit-appearance: none;
328 padding: 0.55rem 2.2rem 0.55rem 0.85rem;
329 border: 1px solid var(--rule);
330 border-radius: 5px;
331 background-color: var(--paper);
332 color: var(--ink);
333 font-family: inherit;
334 font-size: 0.95rem;
335 cursor: pointer;
336 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
337 background-repeat: no-repeat;
338 background-position: right 0.7rem center;
339 transition: border-color 0.15s ease, box-shadow 0.15s ease;
340}
341.site-form select:hover { border-color: var(--ink-soft, #888); }
342.site-form select:focus,
343.site-form input[type="text"]:focus,
344.site-form textarea:focus {
345 outline: none;
346 border-color: var(--accent, #c2410c);
347 box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #c2410c) 22%, transparent);
348}
349
350/* Reuse the palette-swatch styles from account.ejs */
351.palette-swatch {
352 display: flex; flex-direction: column; gap: 0.4rem;
353 padding: 0.5rem;
354 border: 1px solid var(--rule); border-radius: 6px; background: var(--paper);
355 cursor: pointer; font-size: 0.85rem; transition: border-color 120ms;
356}
357.palette-swatch:hover { border-color: var(--accent); }
358.palette-swatch input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
359.palette-swatch:has(input[type="radio"]:checked) { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
360.palette-preview {
361 display: grid; grid-template-columns: 1fr 1fr;
362 width: 100%; height: 44px; border-radius: 4px; overflow: hidden;
363 border: 1px solid var(--rule);
364}
365.pp-half {
366 position: relative;
367 display: flex; align-items: center; justify-content: center;
368 font-family: var(--font-display, serif); font-weight: 600; font-size: 1rem;
369}
370.pp-letter { line-height: 1; }
371.pp-accent {
372 position: absolute; bottom: 4px; right: 4px;
373 width: 9px; height: 9px; border-radius: 50%;
374 border: 1px solid rgba(0,0,0,0.12);
375}
376.palette-swatch-name { font-weight: 500; color: var(--ink); text-align: center; }
377
378/* Accent picker: row of small colored swatches */
379.site-form fieldset.accent-grid {
380 display: grid;
381 grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
382 gap: 0.5rem;
383 background: var(--paper);
384 margin-top: 0.5rem;
385}
386.accent-swatch {
387 display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
388 padding: 0.55rem 0.4rem;
389 border: 1px solid var(--rule); border-radius: 6px; background: var(--paper);
390 cursor: pointer; font-size: 0.78rem;
391 transition: border-color 120ms, box-shadow 120ms;
392}
393.accent-swatch:hover { border-color: var(--accent); }
394.accent-swatch input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
395.accent-swatch:has(input[type="radio"]:checked) {
396 border-color: var(--accent);
397 box-shadow: 0 0 0 2px var(--accent);
398}
399.accent-dot {
400 width: 28px; height: 28px; border-radius: 50%;
401 border: 1px solid rgba(0,0,0,0.1);
402 box-shadow: inset 0 -2px 4px rgba(0,0,0,0.12);
403}
404.accent-swatch-name { color: var(--ink); text-align: center; font-weight: 500; }
405
406.audio-flash { padding: 0.75rem 1rem; border-radius: 6px; margin-bottom: 1rem; font-size: 0.9rem; }
407.audio-flash--ok { background: rgba(40, 160, 90, 0.15); color: #2a9d5e; border: 1px solid rgba(40, 160, 90, 0.3); }
408.audio-flash--err { background: rgba(200, 60, 60, 0.15); color: #c33; border: 1px solid rgba(200, 60, 60, 0.3); }
409
410.form-hint { font-size: 0.8rem; color: var(--ink-muted, var(--ink-soft)); margin: 0; }
411.form-hint-inline { font-size: 0.78rem; color: var(--ink-muted, var(--ink-soft)); font-weight: 400; margin-left: .25rem; }
412
413/* P63 — Profile photo picker
414 Mobile-first: thumb stacks above input/buttons. ≥520px the thumb floats
415 to the left and the controls fill the remaining width. */
416.photo-picker {
417 display: flex;
418 flex-direction: column;
419 gap: .65rem;
420 align-items: stretch;
421}
422.photo-thumb {
423 position: relative;
424 width: 88px; height: 88px;
425 border-radius: 50%;
426 border: 1px solid var(--rule);
427 background: var(--paper-2);
428 overflow: hidden;
429 flex-shrink: 0;
430 display: flex; align-items: center; justify-content: center;
431}
432.photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
433.photo-thumb .photo-empty {
434 display: flex; color: var(--ink-muted, var(--ink-soft)); opacity: .55;
435}
436.photo-thumb .photo-empty svg { width: 36px; height: 36px; }
437.photo-thumb:not([data-empty]) .photo-empty { display: none; }
438.photo-thumb[data-empty] img { display: none; }
439
440.photo-controls {
441 display: flex;
442 flex-direction: column;
443 gap: .5rem;
444 flex: 1;
445 min-width: 0;
446}
447.photo-controls input[type="text"] { width: 100%; }
448.photo-actions {
449 display: flex; align-items: center; flex-wrap: wrap;
450 gap: .4rem;
451}
452.photo-actions .btn { padding: .45rem .75rem; font-size: .85rem; }
453.photo-status { margin-left: .25rem; }
454.photo-status.is-error { color: #c2410c; }
455
456@media (min-width: 520px) {
457 .photo-picker { flex-direction: row; align-items: flex-start; gap: 1rem; }
458 .photo-controls { gap: .55rem; }
459}
460/* Mobile-first: platform selector on its own line (full width), URL input + remove
461 button below. Prevents horizontal overflow on phones (fixed 160px column +
462 non-shrinkable input together ~447px > screen width). */
463.profile-link-row {
464 display: grid; grid-template-columns: 1fr auto; gap: 0.5rem; margin-bottom: 0.5rem;
465}
466.profile-link-row select { padding: 0.45rem 0.6rem; grid-column: 1 / -1; }
467.profile-link-row input { min-width: 0; }
468@media (min-width: 520px) {
469 .profile-link-row { grid-template-columns: 160px 1fr auto; }
470 .profile-link-row select { grid-column: auto; }
471}
472.profile-links-fieldset details > label { margin-top: 0.4rem; }
473</style>
Note: See TracBrowser for help on using the repository browser.