feat: wire per-port SCTE35, 8-port grid, multi-destination defaults

This commit is contained in:
Zac Gaetano 2026-04-14 10:04:11 -04:00
parent 7cf45ceee8
commit b3f496269c

View file

@ -16,7 +16,7 @@ export default function App() {
const wsUrl = `ws://${window.location.host}/ws`;
const { isConnected, lastMessage } = useWebSocket(wsUrl);
const { startRecording, stopRecording, injectSCTE35 } = useRecorder();
const { startRecording, stopRecording, injectSCTE35, injectSCTE35ForPort } = useRecorder();
// Clock
useEffect(() => {
@ -58,6 +58,15 @@ export default function App() {
await injectSCTE35(eventId, durationSeconds);
};
const handleInjectSCTE35ForPort = async (
portIndex: number,
eventId: number,
durationSeconds: number,
srtDestinationUrl?: string
) => {
await injectSCTE35ForPort(portIndex, eventId, durationSeconds, srtDestinationUrl);
};
const handleSelectPort = (portIndex: number) => {
setSelectedPort(prev => (prev === portIndex ? null : portIndex));
};
@ -120,7 +129,7 @@ export default function App() {
</div>
</header>
<main style={{ padding: 28, maxWidth: 1440, margin: '0 auto' }}>
<main style={{ padding: 28, maxWidth: 1600, margin: '0 auto' }}>
{/* ── SECTION LABEL ── */}
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 18 }}>
@ -134,13 +143,8 @@ export default function App() {
</span>
</div>
{/* ── PORT CARDS ── */}
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
gap: 14,
marginBottom: 32,
}} className="ports-grid">
{/* ── PORT CARDS (8-port grid: 4x2) ── */}
<div className="ports-grid" style={{ marginBottom: 32 }}>
{ports.length === 0 ? (
<div style={{
gridColumn: '1 / -1', display: 'flex', flexDirection: 'column',
@ -165,6 +169,7 @@ export default function App() {
onStartRecording={handleStartRecording}
onStopRecording={stopRecording}
onOpenConfig={setConfigPort}
onInjectSCTE35={handleInjectSCTE35ForPort}
/>
))
)}
@ -198,7 +203,7 @@ export default function App() {
</div>
</div>
{/* SCTE-35 */}
{/* Global SCTE-35 panel */}
<div style={{ background: 'var(--bg-card)', border: '1px solid var(--border)', borderRadius: 4, overflow: 'hidden' }}>
<div style={{
padding: '12px 16px', background: 'var(--bg-panel)',
@ -206,7 +211,7 @@ export default function App() {
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
}}>
<span style={{ fontFamily: 'var(--font-ui)', fontSize: 11, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: 'var(--text-secondary)' }}>
Ad Break Injection
Ad Break All Ports
</span>
<span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--accent-amber)', letterSpacing: '0.08em' }}>
SCTE-35 / 104
@ -236,9 +241,14 @@ export default function App() {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
.ports-grid { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1100px) { .ports-grid { grid-template-columns: repeat(2, 1fr) !important; } }
@media (max-width: 600px) { .ports-grid { grid-template-columns: 1fr !important; } }
.ports-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
}
@media (max-width: 1300px) { .ports-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 900px) { .ports-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 500px) { .ports-grid { grid-template-columns: 1fr; } }
`}</style>
</div>
);
@ -253,6 +263,7 @@ function defaultConfig(portIndex: number): RecorderConfig {
recording_path: `/recordings/port_${portIndex}_{timestamp}.mxf`,
srt_enabled: false,
srt_destination: '',
srt_destinations: [],
preview_enabled: true,
};
}