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>
38 lines
1.1 KiB
JavaScript
38 lines
1.1 KiB
JavaScript
const SOURCES = [
|
|
{ id: 'Spotify', label: 'Spotify', color: 'var(--spotify)', icon: '🎵' },
|
|
{ id: 'AirPlay', label: 'AirPlay', color: 'var(--airplay)', icon: '📡' },
|
|
{ id: 'Mopidy', label: 'Mopidy', color: 'var(--accent)', icon: '📻' },
|
|
]
|
|
|
|
export default function SourcePicker({ activeSource, onSelect }) {
|
|
return (
|
|
<div style={styles.row}>
|
|
{SOURCES.map(s => (
|
|
<button
|
|
key={s.id}
|
|
style={{
|
|
...styles.btn,
|
|
...(activeSource === s.id ? { background: s.color + '22', borderColor: s.color, color: s.color } : {}),
|
|
}}
|
|
onClick={() => onSelect(s.id)}
|
|
>
|
|
<span>{s.icon}</span>
|
|
<span style={{ fontSize: 12 }}>{s.label}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const styles = {
|
|
row: { display: 'flex', gap: 8 },
|
|
btn: {
|
|
flex: 1, height: 52, flexDirection: 'column',
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4,
|
|
background: 'var(--surface)', border: '1px solid var(--border)',
|
|
borderRadius: 'var(--radius)', color: 'var(--muted)',
|
|
transition: 'all 0.15s',
|
|
minHeight: 52,
|
|
},
|
|
}
|