From 02e600f921870f68a91f9e7069302ec69558244a Mon Sep 17 00:00:00 2001 From: peterino2 Date: Thu, 5 Feb 2026 23:43:46 -0800 Subject: [PATCH] mobile view --- public/index.html | 7 ++ public/styles.css | 223 ++++++++++++++++++++++++++++++++++++++++++++++ public/ui.js | 31 +++++++ 3 files changed, 261 insertions(+) diff --git a/public/index.html b/public/index.html index aafff6f..651a4f3 100644 --- a/public/index.html +++ b/public/index.html @@ -50,6 +50,13 @@
+ +
+ + + +
+
diff --git a/public/styles.css b/public/styles.css index b3b0a3e..dca790f 100644 --- a/public/styles.css +++ b/public/styles.css @@ -260,3 +260,226 @@ button:hover { background: #333; } .history-item.history-warning { color: #ea4; background: #2a2a1a; } .history-item.history-error { color: #e44; background: #2a1a1a; } .history-time { color: #666; margin-right: 0.4rem; } + +/* Mobile tab bar - hidden on desktop */ +#mobile-tabs { display: none; } + +/* Mobile responsive styles */ +@media (max-width: 768px) { + html, body { + height: 100%; + overflow: hidden; + } + #app { + padding: 0.3rem; + height: 100%; + max-height: 100%; + overflow: hidden; + } + #player-content { + flex: 1; + min-height: 0; + overflow: hidden; + } + + /* Header */ + #site-header { margin-bottom: 0.3rem; flex-shrink: 0; } + #site-header h1 { font-size: 0.9rem; } + #btn-report-bug { font-size: 0.7rem; padding: 0.2rem 0.4rem; } + + #header-row { flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.3rem; flex-shrink: 0; } + #auth-section .user-info { flex-wrap: wrap; gap: 0.3rem; } + #btn-kick-others { display: none; } + + /* Mobile tab bar */ + #mobile-tabs { + display: flex; + gap: 2px; + margin-bottom: 0.3rem; + background: #1a1a1a; + border-radius: 6px; + padding: 3px; + flex-shrink: 0; + } + .mobile-tab { + flex: 1; + background: transparent; + border: none; + color: #666; + font-size: 0.8rem; + font-weight: 600; + padding: 0.5rem; + cursor: pointer; + border-radius: 4px; + transition: all 0.2s; + } + .mobile-tab:hover { color: #888; } + .mobile-tab.active { + background: #4e8; + color: #111; + } + + /* Main content - single column, fixed height for scroll */ + #main-content { + flex-direction: column; + gap: 0; + flex: 1; + min-height: 0; + overflow: hidden; + max-width: 100%; + width: 100%; + margin: 0; + } + + /* Panels - only show active one on mobile */ + #channels-panel, #library-panel, #queue-panel { + flex: 1 1 auto !important; + width: 100% !important; + max-width: 100% !important; + min-width: 0 !important; + max-height: none; + min-height: 0; + display: none; + overflow: hidden; + } + #channels-panel.mobile-active, + #library-panel.mobile-active, + #queue-panel.mobile-active { + display: flex; + } + + /* Library panel - fixed header, scrollable content */ + #library-panel .panel-tabs { + flex-shrink: 0; + } + #library-panel .panel-views { + flex: 1; + min-height: 0; + min-width: 0; + overflow: hidden; + width: 100%; + } + #library-panel .panel-view.active { + display: flex; + flex: 1; + min-height: 0; + min-width: 0; + overflow: hidden; + width: 100%; + } + #library-panel .panel-header { + flex-shrink: 0; + } + #library { + flex: 1; + min-height: 0; + min-width: 0; + overflow-y: auto; + width: 100%; + } + .add-btn { + flex-shrink: 0; + width: auto; + align-self: stretch; + } + + /* Queue panel - fixed header, scrollable content */ + #queue-panel #queue-title, + #queue-panel #now-playing-bar { + flex-shrink: 0; + } + #queue { + flex: 1; + min-height: 0; + overflow-y: auto; + } + + /* Channels panel - scrollable list */ + #channels-panel #channels-list { + flex: 1; + min-height: 0; + overflow-y: auto; + } + + /* Channel list - larger touch targets */ + #channels-list .channel-item { padding: 0.4rem; } + #channels-list .channel-header { padding: 0.3rem 0; min-height: 44px; } + #channels-list .channel-name { font-size: 0.9rem; } + #channels-list .btn-rename-channel, + #channels-list .btn-delete-channel { + opacity: 0.7; + font-size: 1rem; + padding: 0.3rem; + } + + /* Library/Queue - larger items */ + .track { padding: 0.5rem 0.4rem; min-height: 44px; } + .track-title { font-size: 0.85rem; } + + /* Player bar - stacked layout */ + #player-bar { + flex-direction: column; + gap: 0.4rem; + padding: 0.4rem; + position: sticky; + bottom: 0; + z-index: 100; + margin: 0 -0.3rem -0.3rem -0.3rem; + border-radius: 6px 6px 0 0; + } + #now-playing { + width: 100%; + display: flex; + align-items: center; + gap: 0.5rem; + } + #channel-name { display: none; } + #track-name { + flex: 1; + font-size: 0.85rem; + } + #player-controls { width: 100%; } + #progress-row { gap: 0.5rem; } + #status-icon { + font-size: 1.2rem; + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; + } + #btn-prev, #btn-next { + font-size: 1rem; + padding: 0.3rem; + min-width: 44px; + min-height: 44px; + display: flex; + align-items: center; + justify-content: center; + } + #btn-sync, #btn-mode { + font-size: 0.65rem; + padding: 0.2rem 0.4rem; + } + #volume-controls { + justify-content: flex-end; + gap: 0.3rem; + } + #btn-stream-only { display: none; } + #volume-slider { width: 80px; } + + /* Hide history button on mobile */ + #btn-history { display: none; } + + /* Toast positioning */ + #toast-container { + top: auto; + bottom: 5rem; + left: 0.3rem; + right: 0.3rem; + } + .toast { max-width: none; } + + /* Login panel */ + #login-panel { padding: 1rem; } +} diff --git a/public/ui.js b/public/ui.js index be05807..b5e06c8 100644 --- a/public/ui.js +++ b/public/ui.js @@ -166,4 +166,35 @@ M.renderLibrary(); } }, 5000); + + // Mobile tab switching + M.initMobileTabs = function() { + const tabs = document.querySelectorAll(".mobile-tab"); + const panels = { + "channels-panel": M.$("#channels-panel"), + "library-panel": M.$("#library-panel"), + "queue-panel": M.$("#queue-panel") + }; + + // Restore last active tab + const savedTab = localStorage.getItem("blastoise_mobile_tab") || "channels-panel"; + + function setActiveTab(panelId) { + tabs.forEach(t => t.classList.toggle("active", t.dataset.panel === panelId)); + Object.entries(panels).forEach(([id, panel]) => { + if (panel) panel.classList.toggle("mobile-active", id === panelId); + }); + localStorage.setItem("blastoise_mobile_tab", panelId); + } + + tabs.forEach(tab => { + tab.onclick = () => setActiveTab(tab.dataset.panel); + }); + + // Set initial state + setActiveTab(savedTab); + }; + + // Initialize on load + M.initMobileTabs(); })();