Changeset 16fd4fe in Klonkt for src/services/AudioEmbedService.js


Ignore:
Timestamp:
08/22/2026 09:32:29 AM (3 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
e679bce
Parents:
8e1af9c
Message:

De cassettespeler: draaiende spoelen, vooruit en achteruit

Een album toont een genummerde lijst waar je in prikt. Een cassette is het
tegenovergestelde: je spoelt, en je hoort wat er komt in de volgorde waarin het
is opgenomen. Vandaar een eigen vorm en niet het albumjasje met een plaatje.

DE SPELER IS DE BESTAANDE SPELER. De afspeelknop draagt exact dezelfde
data-attributen als een albumhoes, dus audio-player.js pakt hem op; spoelen is
next()/prev(). Een tweede speler ernaast bouwen zou twee dingen tegelijk laten
klinken en de sessie weggooien die een paginawissel overleeft. Daarom spoelt
het per NUMMER en niet per seconde: die speler denkt in een wachtrij.

De nummers staan er als inhoud, niet als knoppen. Geen speel-url, geen knop,
geen hover -- op een cassette kun je niet naar nummer zeven springen. Wat er
speelt lees je op de statusregel, en dat is meteen de toegankelijke kant.

Verder:

  • De pauzeknop vangt zijn klik in de CAPTURE-fase, want audio-player.js luistert in de bubbelfase en zou de wachtrij anders opnieuw vanaf een zetten.
  • Spoelen doet niets als dit bandje niet loopt; anders verzet een spoelknop de wachtrij van een ander blok.
  • init() ruimt de tikker altijd eerst op, ook zonder bandje op de pagina. Zonder dat blijft hij lopen na een paginawissel -- dezelfde fout die in de leesweergave ooit de hele site heeft vastgezet.
  • prefers-reduced-motion zet het draaien uit; de statusregel blijft.

Opmaak in dezelfde familie als .post-album: zelfde rand, radius en papier, en
alleen bestaande variabelen, dus licht, donker en het accent volgen vanzelf.

MOD_V 52, style.css v106.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/AudioEmbedService.js

    r8e1af9c r16fd4fe  
    545545      // uitkomsten, en dan draagt een mixtape het jasje en het woord van een
    546546      // album -- dezelfde vorm die op vier andere plekken al misging.
    547       // DE SPELER IS ER NOG NIET. Een mixtape rendert voorlopig als de gewone
    548       // lijst; wat hier af is, is dat hij zichzelf goed noemt.
    549547      const kind = SOORTEN.includes(pl.kind) ? pl.kind : 'album';
    550548      const KIND_LABEL = { album: '💿 Album', playlist: '📃 Playlist', mixtape: '📼 Mixtape' };
     
    630628    </li>`;
    631629      }).join('\n');
     630
     631      // HET BANDJE HEEFT ZIJN EIGEN VORM. Een album toont een genummerde lijst
     632      // waar je in kunt prikken; een cassette is juist het tegenovergestelde --
     633      // je hoort wat er komt, in de volgorde waarin het is opgenomen. Alles
     634      // hierboven (de wachtrij, de metaregel, de duur) is gedeeld; alleen de
     635      // opmaak splitst hier.
     636      if (kind === 'mixtape') {
     637        return this.renderTape({
     638          domId: albumDomId, id, titleH, artistH, coverH, metaLine, firstUrl,
     639          albumJson, tracks: pl.tracks, isAdmin,
     640        });
     641      }
    632642
    633643      return `<div class="post-album" id="${albumDomId}"
     
    673683
    674684  /**
     685   * Het bandje (Robins idee, 21-8).
     686   *
     687   * WAT HET ANDERS MAAKT DAN EEN ALBUM, en dat is de hele reden dat dit een
     688   * eigen vorm heeft: bij een album prik je in een genummerde lijst en spring
     689   * je naar nummer zeven. Op een cassette kan dat niet. Je spoelt vooruit of
     690   * terug, en wat er komt hoor je in de volgorde waarin het is opgenomen. De
     691   * lijst staat er dus wel -- je mag zien wat erop staat -- maar hij is geen
     692   * knoppenrij.
     693   *
     694   * DE SPELER IS DE BESTAANDE SPELER. De knop hieronder draagt exact dezelfde
     695   * data-attributen als de albumhoes (data-pcms-track-url + data-pcms-album-id),
     696   * dus audio-player.js pakt hem op zonder dat hier iets nieuws bij komt. Vooruit
     697   * en terug lopen via window.pcmsAudioPlayer.next()/prev(), en dat is meteen de
     698   * reden dat spoelen per NUMMER gaat en niet per seconde: die speler denkt in
     699   * een wachtrij, en een tweede speler ernaast bouwen om een band na te doen zou
     700   * twee dingen tegelijk laten afspelen.
     701   */
     702  static renderTape({ domId, id, titleH, artistH, coverH, metaLine, firstUrl, albumJson, tracks, isAdmin }) {
     703    // De nummers als tekst, niet als knoppen. Bewust geen data-pcms-track-url:
     704    // een aanklikbaar nummer is precies wat een bandje niet heeft.
     705    const lijst = tracks.map((t, i) => {
     706      const tTitle = this.escape(t.title || ('Track ' + (i + 1)));
     707      const dur = t.duration > 0
     708        ? `${Math.floor(t.duration / 60)}:${String(t.duration % 60).padStart(2, '0')}`
     709        : '—:—';
     710      return `      <li class="tape-track" data-tape-index="${i}"><span class="tape-track-title">${tTitle}</span><span class="tape-track-dur">${dur}</span></li>`;
     711    }).join('\n');
     712
     713    const spoel = (richting, label, pad) => `    <button type="button" class="tape-btn tape-btn--${richting}" data-tape-go="${richting}" aria-label="${label}">
     714      <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">${pad}</svg>
     715    </button>`;
     716
     717    return `<div class="post-tape" id="${domId}"
     718     data-pcms-album='${albumJson}'
     719     data-pcms-album-title="${titleH}"
     720     data-pcms-album-kind="mixtape"
     721     data-pcms-playlist-id="${this.escape(id)}">
     722${isAdmin ? `  <div class="post-album-actions" role="group" aria-label="Mixtape beheren">
     723    <a class="post-album-action" href="/admin/playlists?edit=${this.escape(id)}" title="Bewerk mixtape" aria-label="Bewerk mixtape">
     724      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>
     725    </a>
     726  </div>
     727` : ''}  <div class="tape-shell">
     728    <div class="tape-window" aria-hidden="true">
     729      <span class="tape-reel tape-reel--left"><span class="tape-reel-hub"></span></span>
     730      <span class="tape-band"></span>
     731      <span class="tape-reel tape-reel--right"><span class="tape-reel-hub"></span></span>
     732    </div>
     733    <div class="tape-label"${coverH ? ` style="background-image:url('${coverH}')"` : ''}>
     734      <p class="tape-kind">📼 Mixtape</p>
     735      <h3 class="tape-title">${titleH}</h3>
     736      ${artistH ? `<p class="tape-artist">${artistH}</p>` : ''}
     737      <p class="tape-meta">${metaLine}</p>
     738    </div>
     739  </div>
     740  <div class="tape-controls" role="group" aria-label="Bandje bedienen">
     741${spoel('back', 'Terugspoelen', '<path d="M11 12l9-7v14zM2 12l9-7v14z"/>')}
     742    <button type="button" class="tape-btn tape-btn--play"
     743            data-pcms-track-url="${firstUrl}"
     744            data-pcms-album-id="${domId}"
     745            data-tape-play
     746            aria-label="Afspelen">
     747      <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M8 4l12 8-12 8z"/></svg>
     748    </button>
     749${spoel('fwd', 'Vooruitspoelen', '<path d="M13 12L4 5v14zM22 12l-9-7v14z"/>')}
     750  </div>
     751  <p class="tape-now" data-tape-now aria-live="polite"></p>
     752  <ol class="tape-tracks">
     753${lijst}
     754  </ol>
     755</div>`;
     756  }
     757
     758  /**
    675759   * Human-readable label for a provider slug. Used by external-link buttons.
    676760   */
Note: See TracChangeset for help on using the changeset viewer.