Ignore:
Timestamp:
08/16/2026 03:06:18 PM (3 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
a5caa73
Parents:
a5515b4 (diff), 9026de5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Bibliotheek en album-federatie terug op main (shaer-0nh, shaer-756s)

Achttien commits, in drie brokken.

DE BIBLIOTHEEK. Een Library-skelet met een eigen volgerssoort: wie de
bibliotheek volgt krijgt de muziek en met opzet niet de gewone posts, en
die staan daarom in een eigen tabel -- een vlag die iemand vergeet te
filteren bezorgt stilletjes de Krant aan mensen die er niet om vroegen.
Daarna wat er nodig bleek om werkelijk gelezen te worden: audience
(zonder dat gaf hun create() een KeyError en dus een 500 op onze URL),
de ongeordende collectievorm, en paginering op elke collectie die first
belooft -- die laatste vond meteen dat featured hetzelfde gat had.

HET VOCABULAIRE. fw:track in de kleine vorm die Emissary ook stuurt,
artist_credit met de site-actor als Artist (mogelijk geworden door de
MusicBrainz-koppeling), en het album als ingesloten fw:Album met
released, musicbrainzId en een eigen artist_credit. Daarvoor kwamen er
twee kolommen op playlists, alleen bij kind='album' en afgedwongen in
PlaylistService -- niet in het scherm, want de API ligt open.

HET BEHEER. De vijf mediapagina's stonden op drie verschillende
ontwerpen; nu op een gedeelde ax-romp, met de primitieven op een plek in
plaats van in acht kopieen. De playlist-modal ging alsnog door i18n: die
teksten stonden hard in het script, wat niet opviel omdat het toevallig
de brontaal was.

WAT ER NIET IN ZIT: bitrate en size top-level als fw:. Dat is bewust
(shaer-3f8a). Hun eigen outbox zet ze op de Link, net als wij, en het
wordt een gesprek in plaats van een aanpassing -- briefing in
~/bewaard/funkwhale-briefing-en.md.

Gereedschap dat meekomt: scripts/funkwhale-gat.mjs meet het gat naar hun
ingest, admin-css.mjs en admin-css-gelijk.mjs ontleden en vergelijken de
beheer-CSS, render-admin-views.mjs rendert de views gevuld en leeg. Die
laatste drie omdat de testsuite geen enkele view aanraakt.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/admin-playlists.ejs

    ra5515b4 r749605a  
    55const _csrf = (typeof csrfToken !== 'undefined' && csrfToken) || '';
    66%>
     7<%# De gedeelde ax-*-primitieven. MOET boven het eigen style-blok van deze
     8    pagina staan: wat hieronder blijft staan wijkt bewust af en hoort dus
     9    later te komen, anders wint de partial ervan. %>
     10<%- include('../partials/admin-styles') %>
    711<div class="container ax-page">
    812
    9   <p><a href="/admin" class="btn">&larr; <%= t('nav.admin') %></a></p>
     13  <%- include('../partials/admin-back') %>
    1014  <%- include('../partials/media-tabs', { active: 'playlists', audioOn: true }) %>
    1115  <header class="ax-header">
     
    8387
    8488.ax-page { max-width: 880px; margin: 1.5rem auto 4rem; padding: 0 1rem; }
    85 .ax-header { display: flex; align-items: flex-start; gap: 0.75rem; margin-bottom: 1.5rem; }
    86 .ax-header h1 { font-family: var(--font-display, serif); font-size: 1.75rem; margin: 0 0 0.25rem; }
    87 .ax-tagline { color: var(--ink-muted, var(--ink-soft)); margin: 0; font-size: 0.9rem; line-height: 1.5; }
    88 .ax-tagline code { background: var(--paper-2); padding: 0.1em 0.4em; border-radius: 4px; font-size: 0.9em; }
    89 .ax-back {
    90   display: inline-flex; align-items: center; justify-content: center;
    91   width: 40px; height: 40px;
    92   border: 1px solid var(--rule); border-radius: 8px;
    93   background: var(--paper); color: var(--ink); text-decoration: none;
    94   font-size: 1.1rem; flex-shrink: 0; transition: border-color 120ms;
    95 }
    96 .ax-back:hover { border-color: var(--accent); }
    97 
    98 .ax-actions-bar {
    99   display: flex;
    100   margin-bottom: 1rem;
    101 }
    102 
    103 .ax-card {
    104   background: var(--paper);
    105   border: 1px solid var(--rule);
    106   border-radius: 12px;
    107   padding: 1.25rem;
    108   margin-bottom: 1rem;
    109 }
    110 
    111 /* ─── Buttons (same primitives as admin-audio) ─────────────────── */
    112 .ax-btn {
    113   display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
    114   padding: 0.6rem 1.1rem;
    115   border: 1px solid var(--rule); background: var(--paper-2);
    116   color: var(--ink);
    117   font-family: var(--font-ui, system-ui), sans-serif;
    118   font-size: 0.95rem; font-weight: 500;
    119   text-decoration: none; border-radius: 8px; cursor: pointer;
    120   min-height: 44px;
    121   transition: background 120ms, border-color 120ms;
    122   -webkit-tap-highlight-color: transparent;
    123 }
    124 .ax-btn:hover { border-color: var(--accent); }
    125 .ax-btn-primary { background: var(--accent); color: white; border-color: var(--accent); }
    126 .ax-btn-primary:hover { opacity: 0.92; }
    127 
    128 .ax-icon-btn {
    129   display: inline-flex; align-items: center; justify-content: center;
    130   width: 40px; height: 40px;
    131   border: 1px solid var(--rule); border-radius: 8px;
    132   background: var(--paper-2); color: var(--ink);
    133   cursor: pointer; font-size: 1rem;
    134   transition: background 120ms, border-color 120ms, color 120ms;
    135 }
    136 .ax-icon-btn:hover { border-color: var(--accent); }
    137 .ax-icon-btn-danger:hover { color: #dc2626; border-color: #dc2626; }
    138 
    139 /* ─── Empty state ──────────────────────────────────────────────── */
    140 .ax-empty { text-align: center; padding: 2rem 1rem; color: var(--ink-muted, var(--ink-soft)); }
    141 .ax-empty-icon { font-size: 2.5rem; margin-bottom: 0.5rem; opacity: 0.5; }
    142 .ax-empty p { margin: 0; }
    143 .ax-empty-sub { font-size: 0.85rem; margin-top: 0.5rem !important; }
    144 
    145 /* ─── List items (same as audio tracks) ───────────────────────── */
    146 .ax-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.6rem; }
    147 .ax-track {
    148   display: grid;
    149   grid-template-columns: 64px 1fr auto;
    150   gap: 0.85rem; align-items: center;
    151   padding: 0.85rem;
    152   background: var(--paper);
    153   border: 1px solid var(--rule);
    154   border-radius: 12px;
    155   transition: border-color 120ms;
    156 }
    157 .ax-track:hover { border-color: var(--accent); }
    158 .ax-track-cover {
    159   width: 64px; height: 64px; border-radius: 8px;
    160   background: var(--paper-2);
    161   display: flex; align-items: center; justify-content: center;
    162   font-family: var(--font-display, serif);
    163   font-size: 1.5rem; color: var(--accent);
    164   flex-shrink: 0;
    165 }
    166 .ax-track-meta { min-width: 0; display: flex; flex-direction: column; gap: 0.25rem; }
    167 .ax-track-title {
    168   font-family: var(--font-display, serif);
    169   font-weight: 600; font-size: 1.05rem; color: var(--ink);
    170   display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap;
    171 }
    172 .ax-pill {
    173   font-family: var(--font-ui);
    174   font-size: 0.7rem; font-weight: 500;
    175   color: var(--ink-soft);
    176   background: var(--paper-2);
    177   padding: 0.15em 0.55em; border-radius: 999px;
    178   letter-spacing: 0;
    179 }
    180 .ax-track-sub {
    181   font-size: 0.85rem;
    182   color: var(--ink-muted, var(--ink-soft));
    183   display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center;
    184 }
    185 .ax-track-sep { opacity: 0.5; }
    186 .ax-embed {
    187   display: inline-block;
    188   background: var(--paper-2);
    189   padding: 0.15rem 0.5rem;
    190   border-radius: 4px;
    191   font-family: var(--font-mono, ui-monospace, monospace);
    192   font-size: 0.75rem;
    193   color: var(--ink-soft);
    194   cursor: pointer; user-select: all;
    195   margin-top: 0.15rem;
    196   word-break: break-all;
    197   align-self: flex-start;
    198   transition: background 120ms;
    199 }
    200 .ax-embed:hover { background: var(--rule); }
    201 .ax-embed.is-copied { background: rgba(40,160,90,0.2); color: #2a9d5e; }
    202 
    203 .ax-track-actions { display: flex; gap: 0.4rem; flex-shrink: 0; }
    20489
    20590/* ─── Mobile ──────────────────────────────────────────────────── */
    20691@media (max-width: 480px) {
    207   .ax-track {
    208     grid-template-columns: 56px 1fr;
    209     grid-template-areas: "cover meta" "actions actions";
    210     gap: 0.6rem;
    211   }
    212   .ax-track-cover { grid-area: cover; width: 56px; height: 56px; }
    213   .ax-track-meta  { grid-area: meta; }
    214   .ax-track-actions {
    215     grid-area: actions;
    216     justify-content: flex-end;
    217     border-top: 1px solid var(--rule);
    218     padding-top: 0.5rem;
    219     margin-top: 0.25rem;
    220   }
    22192}
    22293</style>
Note: See TracChangeset for help on using the changeset viewer.