Fix bottom nav full-width layout + add backend URL autofill

- Remove max-width/gap/padding from bottom nav so buttons fill full screen width
- Add NS_BACKEND_URL to config.js entrypoint and autofill backend-url field on setup screen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-25 17:03:34 +02:00
1 parent b6edfcf14b
commit a5461ff92c
6 files changed
+17 -17

No files matched your search

+2 -1
View File
@@ -1,7 +1,8 @@
# Copy to .env and fill in your values # Copy to .env and fill in your values
# Pre-fills the server URL on the setup screen # Pre-fills the URLs on the setup screen
NAVIDROME_URL=https://music.yourdomain.com NAVIDROME_URL=https://music.yourdomain.com
BACKEND_URL=https://novasonic-api.yourdomain.com
# Path to your Navidrome music library on the host # Path to your Navidrome music library on the host
MUSIC_PATH=/path/to/your/navidrome/music MUSIC_PATH=/path/to/your/navidrome/music
+3 -5
View File
@@ -110,11 +110,9 @@ function disconnect(){
window.addEventListener('load',()=>{ window.addEventListener('load',()=>{
const saved=localStorage.getItem('ns_cfg'); const saved=localStorage.getItem('ns_cfg');
if(saved){cfg=JSON.parse(saved);startApp()} if(saved){cfg=JSON.parse(saved);startApp()}
// Autofill server URL from Docker env (set via config.js) // Autofill URLs from Docker env (set via config.js)
if(window.NS_SERVER_URL){ if(window.NS_SERVER_URL){const el=document.getElementById('srv-url');if(el&&!el.value)el.value=window.NS_SERVER_URL;}
const el=document.getElementById('srv-url'); if(window.NS_BACKEND_URL){const el=document.getElementById('backend-url');if(el&&!el.value)el.value=window.NS_BACKEND_URL;}
if(el&&!el.value)el.value=window.NS_SERVER_URL;
}
document.getElementById('srv-pass').addEventListener('keydown',e=>{if(e.key==='Enter')doConnect()}); document.getElementById('srv-pass').addEventListener('keydown',e=>{if(e.key==='Enter')doConnect()});
audio.addEventListener('timeupdate',updateProgress); audio.addEventListener('timeupdate',updateProgress);
audio.addEventListener('ended',onEnded); audio.addEventListener('ended',onEnded);
+1
View File
@@ -9,6 +9,7 @@ services:
- "8080:80" # route this port through your reverse proxy - "8080:80" # route this port through your reverse proxy
environment: environment:
- NAVIDROME_URL=${NAVIDROME_URL} # pre-filled on the setup screen - NAVIDROME_URL=${NAVIDROME_URL} # pre-filled on the setup screen
- BACKEND_URL=${BACKEND_URL} # pre-filled on the setup screen
# ── Backend (yt-dlp download server) ───────────────────────────────────────── # ── Backend (yt-dlp download server) ─────────────────────────────────────────
novasonic-backend: novasonic-backend:
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/sh #!/bin/sh
# Generate runtime config from env vars so the frontend knows the Navidrome URL # Generate runtime config from env vars so the frontend knows the Navidrome URL
cat > /usr/share/nginx/html/config.js <<EOF cat > /usr/share/nginx/html/config.js <<EOF
window.NS_SERVER_URL = "${NAVIDROME_URL:-}"; window.NS_SERVER_URL = "${NAVIDROME_URL:-}";
window.NS_BACKEND_URL = "${BACKEND_URL:-}";
EOF EOF
exec nginx -g "daemon off;" exec nginx -g "daemon off;"
+8 -9
View File
@@ -362,18 +362,17 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
backdrop-filter:blur(28px); backdrop-filter:blur(28px);
border-top:1px solid var(--border2); border-top:1px solid var(--border2);
z-index:200; z-index:200;
padding:0 4px;
padding-bottom:env(safe-area-inset-bottom); padding-bottom:env(safe-area-inset-bottom);
} }
.bottom-nav-inner{ .bottom-nav-inner{
display:flex;flex-direction:column;align-items:stretch; display:flex;flex-direction:column;align-items:stretch;
height:100%;max-width:500px;margin:0 auto; height:100%;width:100%;
} }
.bnav-item{ .bnav-item{
display:flex;flex-direction:column;align-items:center;gap:4px; display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
padding:8px 12px;border-radius:12px;cursor:pointer; padding:6px 4px;border-radius:10px;cursor:pointer;
font-size:10px;font-weight:600;color:var(--text3); font-size:10px;font-weight:600;color:var(--text3);
letter-spacing:.3px;min-width:52px;text-align:center; letter-spacing:.3px;text-align:center;
transition:color .15s,background .15s; transition:color .15s,background .15s;
border:none;background:none;font-family:var(--font); border:none;background:none;font-family:var(--font);
-webkit-tap-highlight-color:transparent; -webkit-tap-highlight-color:transparent;
@@ -384,10 +383,10 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
.bnav-item svg{flex-shrink:0;transition:transform .15s} .bnav-item svg{flex-shrink:0;transition:transform .15s}
.bnav-item:active svg{transform:scale(.88)} .bnav-item:active svg{transform:scale(.88)}
/* Tab strip */ /* Tab strip */
.bnav-tabs{display:flex;justify-content:center;gap:6px;padding:5px 16px 2px;flex-shrink:0} .bnav-tabs{display:flex;width:100%;padding:4px 8px 2px;flex-shrink:0;gap:4px}
.bnav-tab{flex:1;padding:3px 0;border-radius:7px;border:none;font-family:var(--font);font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--text3);cursor:pointer;background:none;transition:color .15s,background .15s;-webkit-tap-highlight-color:transparent} .bnav-tab{flex:1;padding:3px 0;border-radius:7px;border:none;font-family:var(--font);font-size:10px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--text3);cursor:pointer;background:none;transition:color .15s,background .15s;-webkit-tap-highlight-color:transparent}
.bnav-tab.active{background:var(--surface2);color:var(--text)} .bnav-tab.active{background:var(--surface2);color:var(--text)}
.bnav-pages{display:grid;grid-template-columns:repeat(4,1fr);align-items:center;width:100%;gap:6px;flex:1} .bnav-pages{display:grid;grid-template-columns:repeat(4,1fr);align-items:stretch;width:100%;flex:1}
@media(max-width:768px){ @media(max-width:768px){
.bottom-nav{display:flex;flex-direction:column;justify-content:flex-start} .bottom-nav{display:flex;flex-direction:column;justify-content:flex-start}
@@ -400,8 +399,8 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
.preview-bar{bottom:calc(var(--player-h) + 80px)} .preview-bar{bottom:calc(var(--player-h) + 80px)}
.toast-container{bottom:calc(var(--player-h) + 80px + 16px)} .toast-container{bottom:calc(var(--player-h) + 80px + 16px)}
.jobs-panel{bottom:calc(var(--player-h) + 80px + 16px)} .jobs-panel{bottom:calc(var(--player-h) + 80px + 16px)}
.bnav-pages{grid-template-columns:repeat(4,1fr);gap:6px} .bnav-pages{grid-template-columns:repeat(4,1fr)}
.bnav-item{min-width:0;width:100%;padding:8px 0 6px;box-sizing:border-box} .bnav-item{min-width:0;width:100%;padding:6px 2px;box-sizing:border-box}
#settings-modal{align-items:flex-start;padding-top:max(env(safe-area-inset-top),16px);padding-bottom:calc(var(--player-h) + 80px + env(safe-area-inset-bottom) + 8px)} #settings-modal{align-items:flex-start;padding-top:max(env(safe-area-inset-top),16px);padding-bottom:calc(var(--player-h) + 80px + env(safe-area-inset-bottom) + 8px)}
#settings-modal .modal{max-height:100%!important;overflow:hidden} #settings-modal .modal{max-height:100%!important;overflow:hidden}
} }
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'ns-v12'; const CACHE = 'ns-v13';
const PRECACHE = ['/', 'index.html', 'styles.css', 'app.js', 'sw.js']; const PRECACHE = ['/', 'index.html', 'styles.css', 'app.js', 'sw.js'];
const SKIP_URLS = ['/rest/stream', '/rest/download', '/config.js']; const SKIP_URLS = ['/rest/stream', '/rest/download', '/config.js'];