Files
boWave/bordanlage/dashboard/src/components/audio/ZoneCard.jsx
denshooter 946c0a5377 Initial implementation: Bordanlage boat onboard system
Complete multiroom audio + navigation dashboard:
- Docker stack: SignalK, Snapcast (4 zones), librespot, shairport-sync, Mopidy, Jellyfin, Portainer
- React 18 + Vite dashboard with nautical dark theme
- Full mock system (SignalK NMEA simulation, Snapcast zones, Mopidy player)
- Real API clients for all services with reconnect logic
- SVG instruments: Compass, WindRose, Gauge, DepthSounder, SpeedLog
- Pages: Overview, Navigation, Audio (zones/radio/library), Systems
- Dev mode runs fully without hardware (make dev)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 11:47:33 +01:00

54 lines
1.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export default function ZoneCard({ zone, onVolume, onMute, onSource }) {
const { id, name, active, volume, muted, source } = zone
return (
<div style={{
...styles.card,
opacity: active ? 1 : 0.45,
borderColor: active && !muted ? 'var(--accent)' : 'var(--border)',
}}>
<div style={styles.header}>
<span style={styles.name}>{name}</span>
<div style={styles.badges}>
<span style={{ ...styles.badge, background: active ? '#34d39922' : 'var(--border)', color: active ? 'var(--success)' : 'var(--muted)' }}>
{active ? 'ON' : 'OFF'}
</span>
</div>
</div>
<div style={styles.source}>{source}</div>
<div style={styles.volumeRow}>
<button style={styles.muteBtn} onClick={() => onMute(id, !muted)}>
{muted ? '🔇' : '🔊'}
</button>
<input
type="range" min={0} max={100} value={muted ? 0 : volume}
onChange={e => onVolume(id, Number(e.target.value))}
style={{ flex: 1 }}
/>
<span style={styles.volVal}>{muted ? '' : volume}</span>
</div>
</div>
)
}
const styles = {
card: {
padding: 14,
background: 'var(--surface)',
borderRadius: 'var(--radius)',
border: '1px solid var(--border)',
display: 'flex', flexDirection: 'column', gap: 10,
transition: 'border-color 0.2s, opacity 0.2s',
},
header: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' },
name: { fontWeight: 600, fontSize: 14 },
badges: { display: 'flex', gap: 4 },
badge: { fontSize: 10, padding: '2px 6px', borderRadius: 4, fontWeight: 700 },
source: { fontSize: 11, color: 'var(--muted)' },
volumeRow: { display: 'flex', alignItems: 'center', gap: 10 },
muteBtn: { fontSize: 18, minWidth: 44, minHeight: 44 },
volVal: { fontFamily: 'var(--font-mono)', fontSize: 13, minWidth: 26, textAlign: 'right', color: 'var(--muted)' },
}