Files
Media-Server-Setup/live/src/layout.js
Brandyn / Techy 645f447015 Live portal: custom layouts are left alone — new streams chime and wait in a draggable tray; Arrange re-grids and returns to auto
layout store (auto/custom + pending), marked custom on manual move (onDidMovePanel outside arrange), sash drag,
stream/group rename. Tray chips: HTML5 drag accepted via onUnhandledDragOver/onDidDrop (position -> direction),
click = new column. WebAudio two-note chime. Gateway page instructions updated. Verified headless (custom vs auto).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 14:36:01 -06:00

31 lines
1.7 KiB
JavaScript

import { create } from './tinyStore.js'
// Layout mode. "auto" = untouched grid: streams joining/leaving re-grid everything. The first manual move, resize
// or rename makes it "custom": the grid is left alone, leavers just close, joiners wait in the tray (with a ding)
// until dragged in. "Arrange" re-grids everything and goes back to auto.
export const layout = create({
custom: false,
pending: [], // streams live but not placed yet (custom mode)
markCustom() { return this.custom ? null : { custom: true } },
reset() { return { custom: false, pending: [] } },
addPending(s) { return this.pending.some(p => p.id === s.id) ? null : { pending: [...this.pending, s] } },
dropPending(id) { return this.pending.some(p => p.id === id) ? { pending: this.pending.filter(p => p.id !== id) } : null },
keepPending(ids) { const pending = this.pending.filter(p => ids.has(p.id)); return pending.length === this.pending.length ? null : { pending } },
})
// short two-note chime (WebAudio, no asset). Browsers need one prior click on the page to allow sound.
let ctx
export function ding() {
try {
ctx = ctx || new (window.AudioContext || window.webkitAudioContext)()
if (ctx.state === 'suspended') ctx.resume().catch(() => {})
const t0 = ctx.currentTime
for (const [i, f] of [[0, 880], [0.16, 1320]]) {
const o = ctx.createOscillator(), g = ctx.createGain()
o.type = 'sine'; o.frequency.value = f
g.gain.setValueAtTime(0, t0 + i); g.gain.linearRampToValueAtTime(0.25, t0 + i + 0.02); g.gain.exponentialRampToValueAtTime(0.001, t0 + i + 0.35)
o.connect(g).connect(ctx.destination); o.start(t0 + i); o.stop(t0 + i + 0.4)
}
} catch {}
}