reaction ticks: hits close together become one pill reading them in order, recomputed from the hit list each time
shots / shots (push) Successful in 2m25s
shots / shots (push) Successful in 2m25s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6
This commit is contained in:
1 parent
cc6ca29cbe
commit
6e3965bf1c
1 file changed
+14
-10
+14
-10
@@ -144,7 +144,7 @@ input,textarea{font:inherit;color:inherit}
|
||||
#bar::before{content:"";position:absolute;left:0;right:0;top:-14px;bottom:-14px} /* a fat finger target around a thin line */
|
||||
#bar i{display:block;height:100%;width:0;background:var(--acc);border-radius:2px;pointer-events:none}
|
||||
#bar:hover,#bar.drag{height:4px;margin:-1px 0}
|
||||
#bar em{position:absolute;top:-16px;transform:translateX(-50%);font-size:11px;font-style:normal;line-height:1;pointer-events:none;opacity:.9}
|
||||
#bar em{position:absolute;top:-18px;transform:translateX(-50%);font-size:11px;font-style:normal;line-height:1;pointer-events:none;opacity:.95;white-space:nowrap;background:var(--card);border:1px solid var(--line);border-radius:999px;padding:2px 5px}
|
||||
#bar b{position:absolute;top:-28px;transform:translateX(-50%);font:11px var(--font);letter-spacing:.1em;color:var(--dim);background:var(--card);border:1px solid var(--line);border-radius:6px;padding:2px 6px;pointer-events:none;display:none;white-space:nowrap}
|
||||
#bar.drag b{display:block}
|
||||
#controls{display:flex;align-items:center;gap:18px}
|
||||
@@ -1196,7 +1196,7 @@ function toCooking(job) {
|
||||
if (!job.stepping) { state.history.push(spec); state.played = (state.played || 0) + 1; spec.stationId ||= state.stationId; }
|
||||
keepLabel();
|
||||
for (const t of $("#bar").querySelectorAll("em")) t.remove();
|
||||
if (spec.hits) { const dur = spec.seconds || 120; for (const h of spec.hits) placeTick($("#bar"), h.e, h.t, dur); }
|
||||
drawTicks(spec, spec.seconds || 120);
|
||||
$("#title").textContent = spec.break ? "✱ " + spec.title : spec.title; $("#tags").textContent = `${spec.bpm} bpm · ${spec.key}${spec.break ? " · " + (spec.sponsored ? "sponsored" : "intermission") : spec.remixOf ? " · remix" : ""}`;
|
||||
$("#lyric").textContent = spec.line || "";
|
||||
showTags(spec);
|
||||
@@ -1410,15 +1410,19 @@ const mmss = (s) => `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart
|
||||
function markReaction(spec, emoji, t) {
|
||||
const dur = state.audio.duration || spec.seconds || 120;
|
||||
spec.hits = (spec.hits || []).concat([{ e: emoji, t: Math.round(t), s: sectionAt(spec, t) }]).slice(-24);
|
||||
const bar = $("#bar"); if (!bar || state.current.spec !== spec) return;
|
||||
placeTick(bar, emoji, t, dur);
|
||||
if (state.current.spec === spec) drawTicks(spec, dur);
|
||||
}
|
||||
/* a tick on the bar; ones within a second of each other stack upward so none hides another */
|
||||
function placeTick(bar, emoji, t, dur) {
|
||||
const tick = document.createElement("em"); tick.textContent = emoji; tick.title = `${emoji} at ${mmss(t)}`;
|
||||
const left = Math.min(100, t / dur * 100);
|
||||
const near = [...bar.querySelectorAll("em")].filter((x) => Math.abs(parseFloat(x.dataset.t) - t) < 1.5).length;
|
||||
tick.dataset.t = t; tick.style.left = left + "%"; tick.style.top = (-16 - near * 13) + "px"; bar.append(tick);
|
||||
/* the ticks above the bar: hits within a few percent of each other become one pill reading them in order */
|
||||
function drawTicks(spec, dur) {
|
||||
const bar = $("#bar"); if (!bar) return;
|
||||
for (const t of bar.querySelectorAll("em")) t.remove();
|
||||
const hits = (spec.hits || []).slice().sort((a, b) => a.t - b.t), groups = [];
|
||||
for (const h of hits) { const g = groups[groups.length - 1]; if (g && h.t - g.at <= dur * 0.04) { g.e.push(h.e); g.last = h.t; } else groups.push({ at: h.t, last: h.t, e: [h.e] }); }
|
||||
for (const g of groups) {
|
||||
const tick = document.createElement("em"); const shown = g.e.slice(0, 3).join("") + (g.e.length > 3 ? "+" + (g.e.length - 3) : "");
|
||||
tick.textContent = shown; tick.title = `${g.e.join(" ")} at ${mmss(g.at)}${g.last !== g.at ? "–" + mmss(g.last) : ""}`;
|
||||
tick.style.left = Math.min(100, (g.at + g.last) / 2 / dur * 100) + "%"; bar.append(tick);
|
||||
}
|
||||
}
|
||||
async function react(emoji, text) {
|
||||
const cur = state.current && state.current.spec; if (!cur) return;
|
||||
|
||||
Reference in new issue
Block a user