From 95b1665e19885550dd287028f8623dc70e9abb69 Mon Sep 17 00:00:00 2001
From: Broque Thomas <26755000+Nezreka@users.noreply.github.com>
Date: Fri, 3 Apr 2026 13:11:23 -0700
Subject: [PATCH] =?UTF-8?q?Redesign=20Explorer=20controls=20=E2=80=94=20pr?=
=?UTF-8?q?ominent=20Explore=20button,=20icons,=20polish?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Explore button moved to its own row below playlist cards with gradient,
search icon, and "Explore Selected Playlist" label. Impossible to miss.
Mode toggle redesigned as pill segmented control with grid/list icons.
Action bar buttons get inline SVG icons (checkmark, square, heart).
Primary buttons use gradient + glow shadow treatment.
Build hint shows "Select a playlist above, then explore" → updates to
"Ready: [name]" when playlist selected. Discovery poller refreshes
cards every 5s while active. Button re-enables as "Open" after modal
launch so user can reopen closed discovery modal.
---
webui/index.html | 40 +++++++++++----
webui/static/script.js | 5 ++
webui/static/style.css | 113 +++++++++++++++++++++++++++--------------
3 files changed, 112 insertions(+), 46 deletions(-)
diff --git a/webui/index.html b/webui/index.html
index a90ace01..e42d6e7c 100644
--- a/webui/index.html
+++ b/webui/index.html
@@ -3691,34 +3691,56 @@
-
+
+ onclick="explorerSetMode('albums')">
+
+ Albums
+
+ onclick="explorerSetMode('discographies')">
+
+ Full Discog
+
-
+
+
Select a playlist above, then explore
+
+
-
0 albums selected
+
+ 0 albums selected
+
Scroll to zoom · Right-drag to pan · Double-click album for tracks
diff --git a/webui/static/script.js b/webui/static/script.js
index ad263f1e..8e31ac67 100644
--- a/webui/static/script.js
+++ b/webui/static/script.js
@@ -67137,6 +67137,11 @@ function explorerSelectPlaylist(id, el) {
_explorer.playlistId = id;
document.querySelectorAll('.explorer-picker-card').forEach(c => c.classList.remove('active'));
if (el) el.classList.add('active');
+ // Update hint text
+ const hint = document.getElementById('explorer-build-hint');
+ const pl = _explorer._playlists.find(p => p.id === id);
+ if (hint && pl) hint.textContent = `Ready: ${pl.name}`;
+ else if (hint) hint.textContent = '';
}
function explorerRedirectToDiscover(playlistId) {
diff --git a/webui/static/style.css b/webui/static/style.css
index 15286d8d..1fe6435e 100644
--- a/webui/static/style.css
+++ b/webui/static/style.css
@@ -50757,54 +50757,77 @@ tr.tag-diff-same {
flex-shrink: 0;
}
-/* Mode toggle — segmented control */
+/* Mode toggle — pill segmented control */
.explorer-mode-toggle {
display: flex;
- background: rgba(255, 255, 255, 0.03);
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 10px;
- overflow: hidden;
- position: relative;
+ padding: 3px;
+ gap: 2px;
}
.explorer-mode-btn {
- padding: 10px 18px;
- font-size: 12px;
+ padding: 7px 14px;
+ font-size: 11px;
font-weight: 600;
color: rgba(255, 255, 255, 0.4);
background: none;
border: none;
cursor: pointer;
- transition: all 0.25s;
- position: relative;
- z-index: 1;
+ transition: all 0.2s;
+ border-radius: 7px;
+ display: flex;
+ align-items: center;
+ gap: 5px;
letter-spacing: 0.2px;
}
+.explorer-mode-btn svg { opacity: 0.5; transition: opacity 0.2s; }
.explorer-mode-btn.active {
color: #fff;
- background: rgba(var(--accent-rgb), 0.25);
- border-radius: 8px;
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
+ background: rgba(var(--accent-rgb), 0.2);
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}
+.explorer-mode-btn.active svg { opacity: 1; }
.explorer-mode-btn:hover:not(.active) {
color: rgba(255, 255, 255, 0.65);
+ background: rgba(255, 255, 255, 0.04);
+}
+
+/* Explore button row — prominent CTA below playlist cards */
+.explorer-build-row {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ padding: 14px 0 4px;
+}
+
+.explorer-build-hint {
+ font-size: 12px;
+ color: rgba(255, 255, 255, 0.25);
+ font-style: italic;
}
-/* Explore button — primary CTA */
.explorer-build-btn {
- padding: 10px 24px;
+ padding: 11px 28px;
font-size: 13px;
font-weight: 700;
color: #fff;
- background: var(--accent);
+ background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 80%, #fff));
border: none;
- border-radius: 10px;
+ border-radius: 12px;
cursor: pointer;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
letter-spacing: 0.3px;
position: relative;
overflow: hidden;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ box-shadow: 0 2px 12px rgba(var(--accent-rgb), 0.25);
}
.explorer-build-btn::after {
@@ -50813,11 +50836,12 @@ tr.tag-diff-same {
inset: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 50%);
border-radius: inherit;
+ pointer-events: none;
}
.explorer-build-btn:hover:not(:disabled) {
- transform: translateY(-1px);
- box-shadow: 0 6px 24px rgba(var(--accent-rgb), 0.35);
+ transform: translateY(-2px);
+ box-shadow: 0 8px 28px rgba(var(--accent-rgb), 0.4);
filter: brightness(1.1);
}
@@ -50830,21 +50854,22 @@ tr.tag-diff-same {
opacity: 0.5;
cursor: default;
filter: saturate(0.5);
+ box-shadow: none;
}
-/* Action bar — sticky at top */
+/* Action bar — polished sticky toolbar */
.explorer-action-bar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
- gap: 8px;
- padding: 12px 20px;
- background: rgba(18, 18, 22, 0.9);
+ gap: 10px;
+ padding: 10px 20px;
+ background: linear-gradient(180deg, rgba(18, 18, 26, 0.95) 0%, rgba(18, 18, 22, 0.95) 100%);
border: 1px solid rgba(255, 255, 255, 0.06);
- border-radius: 12px;
+ border-radius: 14px;
margin-bottom: 16px;
- backdrop-filter: blur(12px);
+ backdrop-filter: blur(16px);
position: sticky;
top: 0;
z-index: 20;
@@ -50856,9 +50881,15 @@ tr.tag-diff-same {
to { opacity: 1; transform: none; }
}
+.explorer-action-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
.explorer-nav-hint {
font-size: 10px;
- color: rgba(255, 255, 255, 0.2);
+ color: rgba(255, 255, 255, 0.18);
width: 100%;
text-align: center;
margin-top: 2px;
@@ -50866,44 +50897,51 @@ tr.tag-diff-same {
.explorer-selection-count {
font-size: 13px;
- color: rgba(255, 255, 255, 0.6);
- font-weight: 500;
+ color: rgba(255, 255, 255, 0.5);
+ font-weight: 600;
}
.explorer-action-buttons {
display: flex;
- gap: 8px;
+ gap: 6px;
}
.explorer-action-btn {
- padding: 7px 16px;
+ padding: 7px 14px;
font-size: 11px;
font-weight: 600;
- color: rgba(255, 255, 255, 0.55);
- background: rgba(255, 255, 255, 0.05);
+ color: rgba(255, 255, 255, 0.5);
+ background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
letter-spacing: 0.2px;
+ display: flex;
+ align-items: center;
+ gap: 5px;
}
+.explorer-action-btn svg { opacity: 0.5; }
.explorer-action-btn:hover {
- background: rgba(255, 255, 255, 0.1);
- color: #fff;
- border-color: rgba(255, 255, 255, 0.15);
+ background: rgba(255, 255, 255, 0.08);
+ color: rgba(255, 255, 255, 0.85);
+ border-color: rgba(255, 255, 255, 0.12);
}
+.explorer-action-btn:hover svg { opacity: 0.8; }
.explorer-action-btn.primary {
- background: var(--accent);
+ background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 80%, #fff));
border-color: transparent;
color: #fff;
font-weight: 700;
- padding: 8px 22px;
+ padding: 8px 20px;
font-size: 12px;
position: relative;
overflow: hidden;
+ box-shadow: 0 2px 10px rgba(var(--accent-rgb), 0.2);
}
+.explorer-action-btn.primary svg { opacity: 1; }
.explorer-action-btn.primary::after {
content: '';
@@ -50911,10 +50949,11 @@ tr.tag-diff-same {
inset: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 50%);
border-radius: inherit;
+ pointer-events: none;
}
.explorer-action-btn.primary:hover {
- box-shadow: 0 4px 18px rgba(var(--accent-rgb), 0.4);
+ box-shadow: 0 6px 22px rgba(var(--accent-rgb), 0.4);
filter: brightness(1.1);
transform: translateY(-1px);
}