Files
Tobias GesellchenandClaude Sonnet 4.6 6723515f54 feat(soundtouch-web): migrate to pkg/service/soundtouchweb with Preact UI
Move soundtouch-web from Bootstrap+vanilla JS to an embedded-asset Go service
using Preact+htm (no build step). Implements Stockholm UI parity: device list,
now playing, transport controls, presets, sources, and TuneIn browser.

- Relocate handlers/websocket/webtypes to pkg/service/soundtouchweb/
- Replace old static/ with CSS-custom-property design system (dark mode)
- Add Preact component tree: DeviceList, NowPlaying, Controls, Presets, Sources, TuneInBrowser
- Wire WebSocket for real-time device status updates
- Slim cmd/soundtouch-web/main.go to a thin CLI wrapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 21:22:57 +02:00

48 lines
1.8 KiB
JavaScript

import { h } from 'preact';
import htm from 'htm';
import { api } from '../api.js';
const html = htm.bind(h);
const SOURCE_ICONS = {
TUNEIN: '📻', SPOTIFY: '🎵', AMAZON: '🛒', PANDORA: '🎶',
BLUETOOTH: '📶', AUX: '🔌', OPTICAL: '💡', HDMI: '📺',
IHEARTRADIO: '❤️', DEEZER: '🎼', LOCAL_INTERNET_RADIO: '📡',
AIRPLAY: '📡', PRODUCT: '🔊',
};
export function Sources({ deviceId, status }) {
const items = status?.sources?.SourceItem ?? [];
const currentSource = status?.nowPlaying?.Source;
const currentAccount = status?.nowPlaying?.SourceAccount;
const ready = items.filter(s => s.Status === 'READY');
if (ready.length === 0) return null;
function select(src) {
api.selectSource(deviceId, src.Source, src.SourceAccount ?? '');
}
return html`
<div class="sources-section">
<h3 class="section-title">Sources</h3>
<div class="source-list">
${ready.map(src => {
const isActive = src.Source === currentSource &&
(!src.SourceAccount || src.SourceAccount === currentAccount);
return html`
<button
key=${src.Source + (src.SourceAccount || '')}
class="source-btn ${isActive ? 'active' : ''} ${src.IsLocal ? 'local' : ''}"
onClick=${() => select(src)}
title=${src.Source}
>
<span class="source-icon">${SOURCE_ICONS[src.Source] || '🔊'}</span>
<span class="source-name">${src.DisplayName || src.Source}</span>
</button>
`;
})}
</div>
</div>
`;
}