From 5e98b9fca66ba9f95b368cd439fda62b6fc732a8 Mon Sep 17 00:00:00 2001 From: iamdoubz <> Date: Thu, 30 Jul 2026 10:12:13 -0500 Subject: [PATCH 1/4] Add hamburger menu to house Song List and Waveform Styles --- assets/css/radio.css | 57 +++++++++++++++++++++--------------- assets/js/player.js | 51 +++++++++++++++++++++++++++----- index.php | 69 ++++++++++++++++++++++++++------------------ 3 files changed, 118 insertions(+), 59 deletions(-) diff --git a/assets/css/radio.css b/assets/css/radio.css index 7b7c9d5..3fdc1b1 100644 --- a/assets/css/radio.css +++ b/assets/css/radio.css @@ -160,22 +160,11 @@ audio[controls] { width: 100%; outline: 0; } .waveform { width: 100%; display: block; border-radius: 8px; } .waveform[hidden] { display: none; } /* [hidden] must beat display:block */ -.waveform-picker { position: absolute; top: 6px; right: 6px; z-index: 2; } -.waveform-picker summary { - list-style: none; padding: 4px 12px; - background: rgba(0, 0, 0, 0.55); color: #fff; - font-variant: small-caps; font-size: 0.8rem; - border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 999px; - cursor: pointer; backdrop-filter: blur(4px); - transition: background .15s ease; -} -.waveform-picker summary::-webkit-details-marker { display: none; } -.waveform-picker summary:hover, .waveform-picker summary:focus { background: rgba(0, 0, 0, 0.8); outline: 0; } -.waveform-picker[open] summary { background: var(--accent); color: var(--accent-text); border-color: var(--accent); } - -.waveform-picker[open] { +.waveform-picker { + position: fixed; top: 64px; right: 16px; z-index: 30; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; } +.waveform-picker[hidden] { display: none; } .waveform-picker fieldset { margin: 0; padding: 8px 10px; background: rgba(0, 0, 0, 0.85); color: #fff; @@ -266,15 +255,35 @@ audio[controls] { width: 100%; outline: 0; } width: 0; height: 0; display: none; } -/* ----------------------------------------------------- history panel */ -.history-toggle { - position: fixed; top: 16px; right: 16px; z-index: 30; - padding: 8px 14px; +/* ----------------------------------------------------------------- menu */ +.menu-wrap { position: fixed; top: 16px; right: 16px; z-index: 30; } +.menu-toggle { + width: 40px; height: 40px; + display: flex; align-items: center; justify-content: center; background: var(--accent); color: var(--accent-text); - font-variant: small-caps; border: none; border-radius: 8px; cursor: pointer; + font-size: 1.1rem; line-height: 1; + border: none; border-radius: 8px; cursor: pointer; } -.history-toggle:hover, .history-toggle:focus { background: var(--accent-hover); outline: 0; } +.menu-toggle:hover, .menu-toggle:focus { background: var(--accent-hover); outline: 0; } +.menu-list { + position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; + min-width: 170px; margin: 0; padding: 6px; + list-style: none; + background: rgba(0, 0, 0, 0.85); color: #fff; + border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 10px; + backdrop-filter: blur(4px); +} +.menu-list[hidden] { display: none; } +.menu-item { + display: block; width: 100%; text-align: left; + padding: 8px 10px; margin: 0; + background: none; border: none; border-radius: 6px; + color: inherit; font: inherit; font-size: 0.85rem; cursor: pointer; +} +.menu-item:hover, .menu-item:focus-visible { background: rgba(255, 255, 255, 0.15); outline: 0; } + +/* ----------------------------------------------------- history panel */ .history { position: fixed; top: 0; right: 0; height: 100%; width: min(90vw, 420px); padding: 64px 16px 16px; @@ -308,11 +317,11 @@ audio[controls] { width: 100%; outline: 0; } .history { width: min(96vw, 420px); } /* -webkit-touch-callout is a no-op everywhere except iOS WebKit, so this - @supports check targets iOS phones without any JS/UA sniffing. Picker is - hidden there, so give the art a fake ambient glow (no audio analysis) - in its place. */ + @supports check targets iOS phones without any JS/UA sniffing. The menu + item is hidden there, so give the art a fake ambient glow (no audio + analysis) in its place. */ @supports (-webkit-touch-callout: none) { - .waveform-picker { display: none; } + #menu-waveform { display: none; } .album-art { animation: art-glow-pulse 3.2s ease-in-out infinite; } } } diff --git a/assets/js/player.js b/assets/js/player.js index 1dd68f0..f3b9061 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -39,14 +39,17 @@ lyricsLines: $('lyrics-lines'), lyricsSync: $('lyrics-sync'), lyricsOffset: $('lyrics-offset'), - historyToggle:$('history-toggle'), historyBody: $('history-body'), history: $('history'), listeners: $('listeners'), canvas: $('tint-canvas'), waveform: $('waveform'), artRing: $('art-ring'), - wavePicker: $('waveform-picker') + wavePicker: $('waveform-picker'), + menuToggle: $('menu-toggle'), + menuList: $('menu-list'), + menuHistory: $('menu-history'), + menuWaveform: $('menu-waveform') }; var ICON = { @@ -768,13 +771,47 @@ while (el.historyBody.children.length > 100) el.historyBody.removeChild(el.historyBody.lastChild); } - if (el.historyToggle && el.history) { - el.historyToggle.addEventListener('click', function () { - var open = el.history.classList.toggle('open'); - el.historyToggle.classList.toggle('open', open); - el.historyToggle.textContent = open ? 'Close' : 'Song list'; + /* --------------------------------------------------------- menu / popovers */ + function closeMenu() { + if (!el.menuList) return; + el.menuList.hidden = true; + if (el.menuToggle) el.menuToggle.setAttribute('aria-expanded', 'false'); + } + + if (el.menuToggle && el.menuList) { + el.menuToggle.addEventListener('click', function (e) { + e.stopPropagation(); + var open = el.menuList.hidden; + el.menuList.hidden = !open; + el.menuToggle.setAttribute('aria-expanded', open ? 'true' : 'false'); }); } + if (el.menuHistory && el.history) { + el.menuHistory.addEventListener('click', function (e) { + e.stopPropagation(); + el.history.classList.toggle('open'); + closeMenu(); + }); + } + if (el.menuWaveform && el.wavePicker) { + el.menuWaveform.addEventListener('click', function (e) { + e.stopPropagation(); + el.wavePicker.hidden = !el.wavePicker.hidden; + closeMenu(); + }); + } + // Clicking anywhere outside the menu / history pane / waveform picker + // closes whichever of them is open (the triggers above stop propagation + // so this only fires for genuine outside clicks). + document.addEventListener('click', function (e) { + closeMenu(); + if (el.history && el.history.classList.contains('open') && !el.history.contains(e.target)) { + el.history.classList.remove('open'); + } + if (el.wavePicker && !el.wavePicker.hidden && !el.wavePicker.contains(e.target)) { + el.wavePicker.hidden = true; + } + }); /* ----------------------------------------------------------- listeners */ function updateListeners(data) { diff --git a/index.php b/index.php index ea78d4c..89253d4 100644 --- a/index.php +++ b/index.php @@ -58,33 +58,6 @@ $showArtRing = $waveActive && in_array('circular', $waveTypes, true) && $rich;
- -
- Style -
- Below art - 'None', 'bars' => 'Bars', 'line' => 'Line', 'vu' => 'VU', - 'spectrum' => 'Spectrum', 'spectrum-mirror' => 'Spectrum (mirror)', 'blob' => 'Blob']; - foreach ($stripLabels as $val => $label): - if ($val !== 'none' && !in_array($val, $waveTypes, true)) continue; -?> - - -
- -
- On art - - - - - - -
- -
-
@@ -112,8 +85,48 @@ $showArtRing = $waveActive && in_array('circular', $waveTypes, true) && $rich; + + + + + + + + -