From 23949189f76377e10a314217aa4731fc40fadf9e Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 14 Jun 2026 16:35:59 +0200 Subject: [PATCH] fix(player): stop navbar title/icons overlapping on small screens; show device names in grouping #500: the absolutely-centered page title and the right-aligned icon bar shared the same space in the fixed-height navbar and overlapped on phones (portrait). On <=600px the navbar now wraps into two rows: row 1 keeps the logo with the title beside it (the title fills the remaining width and ellipsizes), and the icon bar drops onto its own centered, full-width row below. CSS-only. #498: the zone/grouping UI showed raw IP addresses instead of device names. Root cause was a field-name casing bug: Zone.js read info.Name (uppercase), but the device info field is info.name (lowercase) everywhere else in the UI (app.js, DeviceList, Library, TTS, ...). So the lookup always missed and fell back to the IP. Fixed the casing in the deviceName() helper, and made the "Add to zone" picker show the device name with the IP as a smaller secondary line (reusing the .picker-device-info/name/ip pattern the other pickers already use). Member/master rows resolve names via deviceName(). Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/service/soundtouchweb/static/css/app.css | 31 +++++++++++++++++++ .../static/js/components/Zone.js | 11 ++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/pkg/service/soundtouchweb/static/css/app.css b/pkg/service/soundtouchweb/static/css/app.css index a7998a9..f4fa05e 100644 --- a/pkg/service/soundtouchweb/static/css/app.css +++ b/pkg/service/soundtouchweb/static/css/app.css @@ -146,6 +146,37 @@ img { display: block; max-width: 100%; } font-family: monospace; } +/* Small screens (phones, portrait): the absolutely-centered page title and the + right-aligned icon bar share the same space in the fixed-height navbar and + collide (#500). Let the navbar wrap into two rows: row 1 keeps the logo with + the title beside it (the title fills the remaining width and ellipsizes), and + the icon bar drops onto its own full-width row below. */ +@media (max-width: 600px) { + .navbar { + flex-wrap: wrap; + height: auto; + min-height: 52px; + row-gap: 0.25rem; + padding-top: 0.4rem; + padding-bottom: 0.4rem; + } + + .page-title { + position: static; + transform: none; + flex: 1 1 auto; /* sit next to the logo and fill the rest of row 1 */ + width: auto; + min-width: 0; /* allow the title to shrink + ellipsize */ + } + + .nav-links { + order: 1; /* force the icon bar onto its own row below */ + width: 100%; + justify-content: center; + flex-wrap: wrap; + } +} + .nav-logo { width: 24px; height: 24px; diff --git a/pkg/service/soundtouchweb/static/js/components/Zone.js b/pkg/service/soundtouchweb/static/js/components/Zone.js index cc547e3..c32dedf 100644 --- a/pkg/service/soundtouchweb/static/js/components/Zone.js +++ b/pkg/service/soundtouchweb/static/js/components/Zone.js @@ -52,7 +52,7 @@ export function Zone({ deviceId, devices }) { const zoneIps = new Set([zone.masterIp, ...(zone.members || []).map(m => m.ip)].filter(Boolean)); const available = Object.entries(devices || {}).filter(([ip]) => !zoneIps.has(ip)); - const deviceName = (ip) => devices[ip]?.info?.Name ?? ip; + const deviceName = (ip) => devices[ip]?.info?.name || ip; return html`
@@ -76,7 +76,7 @@ export function Zone({ deviceId, devices }) { ${(zone.members || []).map(m => html`
Member - ${m.name || m.ip} + ${m.name || deviceName(m.ip)}
@@ -93,7 +93,7 @@ export function Zone({ deviceId, devices }) { ${zone.isSlave && html`
Member - Zone: ${zone.masterName || zone.masterIp} + Zone: ${zone.masterName || deviceName(zone.masterIp)}
`} @@ -105,7 +105,10 @@ export function Zone({ deviceId, devices }) {
${available.map(([ip, d]) => html` `)}