54 lines
1.9 KiB
JavaScript
54 lines
1.9 KiB
JavaScript
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)' },
|
||
}
|