source: Klonkt/src/views/pages/embed-player.ejs@ abb34d2

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

embed player: slim themed scrollbar for the track list (was the chunky default)

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

  • Property mode set to 100644
File size: 5.8 KB
Line 
1<!DOCTYPE html>
2<html lang="nl">
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<title><%= site.title %> — speler</title>
7<style>
8 :root { --ac: <%= (site && site.accent) ? site.accent : '#6b8f71' %>; }
9 * { box-sizing: border-box; }
10 html, body { margin: 0; }
11 body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; background: #14161a; color: #f2f3f5; }
12 .ep { display: flex; flex-direction: column; height: 100vh; }
13 .ep-now { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-bottom: 1px solid rgba(255,255,255,.08); }
14 .ep-play { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; border: none; background: var(--ac); color: #fff; font-size: 18px; cursor: pointer; display: grid; place-items: center; }
15 .ep-meta { flex: 1 1 auto; min-width: 0; }
16 .ep-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
17 .ep-artist { font-size: 12px; opacity: .6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
18 .ep-bar { height: 4px; background: rgba(255,255,255,.12); cursor: pointer; }
19 .ep-fill { height: 100%; width: 0; background: var(--ac); }
20 .ep-list { flex: 1 1 auto; overflow-y: auto; margin: 0; padding: 0; list-style: none; }
21 .ep-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,.05); }
22 .ep-item:hover { background: rgba(255,255,255,.05); }
23 .ep-item.on { color: var(--ac); }
24 .ep-num { width: 20px; text-align: right; opacity: .5; font-size: 13px; font-variant-numeric: tabular-nums; }
25 .ep-it-title { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 14px; }
26 .ep-dur { opacity: .5; font-size: 12px; font-variant-numeric: tabular-nums; }
27 .ep-foot { padding: 8px 14px; font-size: 11px; opacity: .5; text-align: center; border-top: 1px solid rgba(255,255,255,.08); }
28 .ep-foot a { color: inherit; }
29 .ep-empty { padding: 24px; text-align: center; opacity: .6; }
30 /* Slim, themed scrollbar for the track list (instead of the chunky default). */
31 .ep-list { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.28) transparent; }
32 .ep-list::-webkit-scrollbar { width: 8px; }
33 .ep-list::-webkit-scrollbar-track { background: transparent; }
34 .ep-list::-webkit-scrollbar-thumb { background-color: rgba(255,255,255,.22); border-radius: 999px; border: 2px solid transparent; background-clip: content-box; }
35 .ep-list::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--ac) 70%, #fff); }
36</style>
37</head>
38<body>
39<div class="ep">
40 <div class="ep-now">
41 <button class="ep-play" id="ep-play" aria-label="Afspelen">▶</button>
42 <div class="ep-meta">
43 <div class="ep-title" id="ep-title"><%= site.title %></div>
44 <div class="ep-artist" id="ep-artist">Selecteer een nummer</div>
45 </div>
46 </div>
47 <div class="ep-bar" id="ep-bar"><div class="ep-fill" id="ep-fill"></div></div>
48 <% if (!embedTracks.length) { %>
49 <div class="ep-empty">Geen nummers beschikbaar.</div>
50 <% } else { %>
51 <ul class="ep-list" id="ep-list">
52 <% embedTracks.forEach(function(t, i){ %>
53 <li class="ep-item" data-i="<%= i %>">
54 <span class="ep-num"><%= i+1 %></span>
55 <span class="ep-it-title"><%= t.title %><% if (t.artist) { %> — <span style="opacity:.6"><%= t.artist %></span><% } %></span>
56 <span class="ep-dur" data-dur="<%= t.duration || 0 %>"></span>
57 </li>
58 <% }); %>
59 </ul>
60 <% } %>
61 <div class="ep-foot">via <a href="<%= siteUrlBase %>/" target="_blank" rel="noopener"><%= site.title %></a> · Klonkt</div>
62</div>
63<audio id="ep-audio" preload="none" playsinline></audio>
64<script>
65(function(){
66 var TRACKS = <%- JSON.stringify(embedTracks) %>;
67 var audio = document.getElementById('ep-audio');
68 var playBtn = document.getElementById('ep-play');
69 var titleEl = document.getElementById('ep-title');
70 var artistEl = document.getElementById('ep-artist');
71 var fill = document.getElementById('ep-fill');
72 var bar = document.getElementById('ep-bar');
73 var list = document.getElementById('ep-list');
74 var cur = -1;
75 function fmt(s){ s = parseInt(s,10)||0; var m=Math.floor(s/60), x=s%60; return m+':'+String(x).padStart(2,'0'); }
76 // Vul de duur-labels.
77 document.querySelectorAll('.ep-dur').forEach(function(el){ var d=parseInt(el.getAttribute('data-dur'),10)||0; if(d) el.textContent=fmt(d); });
78 function mark(){ document.querySelectorAll('.ep-item').forEach(function(li){ li.classList.toggle('on', parseInt(li.getAttribute('data-i'),10)===cur); }); }
79 function load(i, play){
80 if(i<0||i>=TRACKS.length) return;
81 cur=i; var t=TRACKS[i];
82 titleEl.textContent=t.title||'Naamloos';
83 artistEl.textContent=t.artist||'';
84 audio.src=t.url;
85 mark();
86 if(play){ audio.play().catch(function(){}); }
87 }
88 playBtn.addEventListener('click', function(){
89 if(cur<0){ load(0, true); return; }
90 if(audio.paused) audio.play().catch(function(){}); else audio.pause();
91 });
92 if(list) list.addEventListener('click', function(e){
93 var li=e.target.closest('.ep-item'); if(!li) return;
94 load(parseInt(li.getAttribute('data-i'),10), true);
95 });
96 audio.addEventListener('play', function(){ playBtn.textContent='⏸'; });
97 audio.addEventListener('pause', function(){ playBtn.textContent='▶'; });
98 audio.addEventListener('timeupdate', function(){ if(audio.duration) fill.style.width=(audio.currentTime/audio.duration*100)+'%'; });
99 audio.addEventListener('ended', function(){ if(cur+1<TRACKS.length) load(cur+1, true); else { playBtn.textContent='▶'; fill.style.width='0'; } });
100 bar.addEventListener('click', function(e){ if(!audio.duration) return; var r=bar.getBoundingClientRect(); audio.currentTime=(e.clientX-r.left)/r.width*audio.duration; });
101})();
102</script>
103</body>
104</html>
Note: See TracBrowser for help on using the repository browser.