Gateway page: live-page instructions (layout, audio, rename, group names, maximise); portal: maximise button per tab bar
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,16 @@
|
|||||||
<li>Live: windows open as people go live and close when they stop. Click a window to hear it; the speaker button pins audio on; the slider is per window.</li>
|
<li>Live: windows open as people go live and close when they stop. Click a window to hear it; the speaker button pins audio on; the slider is per window.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
<details><summary>Live page: windows, groups, names</summary>
|
||||||
|
<ul>
|
||||||
|
<li><b>Layout.</b> Windows arrange themselves into an even grid whenever someone goes live or stops. Drag a tab to move a window, drag the bars between windows to resize, drop a tab onto another window to stack them as tabs. <b>Arrange</b> (top bar) snaps everything back to the grid.</li>
|
||||||
|
<li><b>Audio.</b> Sound follows the window you click. The speaker button pins a window's audio on even when you click elsewhere; <b>Mute all</b> silences everything until you click a window; <b>Follow focus</b> clears pins.</li>
|
||||||
|
<li><b>Rename a stream.</b> Double-click its tab, type a name, Enter. Escape cancels; an empty name goes back to <code>user · title</code>. Names stay in your browser and come back the next time that streamer uses the same title.</li>
|
||||||
|
<li><b>Name a group.</b> Every tab bar starts with a <code>+ name</code> slot. Double-click it, type, Enter. Group names last until you reload the page.</li>
|
||||||
|
<li><b>One window big.</b> The ⛶ button at the right of a tab bar maximises that window; click it again to restore. Arranging (a stream joining or leaving, or the Arrange button) restores it too.</li>
|
||||||
|
<li><b>Timecode band.</b> Streams with the timecode band on show it cropped off automatically; recordings never contain it.</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { audio } from './useAudio.js'
|
|||||||
import GoLive from './GoLive.jsx'
|
import GoLive from './GoLive.jsx'
|
||||||
import Tab from './Tab.jsx'
|
import Tab from './Tab.jsx'
|
||||||
import GroupLabel from './GroupLabel.jsx'
|
import GroupLabel from './GroupLabel.jsx'
|
||||||
|
import GroupActions from './GroupActions.jsx'
|
||||||
import { streamLabel } from './names.js'
|
import { streamLabel } from './names.js'
|
||||||
|
|
||||||
const components = { player: Player }
|
const components = { player: Player }
|
||||||
@@ -18,6 +19,7 @@ const POLL_MS = 3000
|
|||||||
export function arrange(api) {
|
export function arrange(api) {
|
||||||
const panels = [...api.panels].sort((a, b) => ((a.params?.since || '').localeCompare(b.params?.since || '')) || a.id.localeCompare(b.id))
|
const panels = [...api.panels].sort((a, b) => ((a.params?.since || '').localeCompare(b.params?.since || '')) || a.id.localeCompare(b.id))
|
||||||
const n = panels.length; if (n < 2) return
|
const n = panels.length; if (n < 2) return
|
||||||
|
if (api.hasMaximizedGroup?.()) api.exitMaximizedGroup?.() // a maximised window would hide the new grid
|
||||||
const cols = Math.ceil(Math.sqrt(n))
|
const cols = Math.ceil(Math.sqrt(n))
|
||||||
for (let i = 1; i < n; i++) {
|
for (let i = 1; i < n; i++) {
|
||||||
const r = Math.floor(i / cols), c = i % cols
|
const r = Math.floor(i / cols), c = i % cols
|
||||||
@@ -92,7 +94,7 @@ export default function App() {
|
|||||||
)}
|
)}
|
||||||
<div className="dock" style={{ display: streams.length ? 'block' : 'none' }}>
|
<div className="dock" style={{ display: streams.length ? 'block' : 'none' }}>
|
||||||
<DockviewReact className="dockview-theme-vanguard" components={components} tabComponents={tabComponents}
|
<DockviewReact className="dockview-theme-vanguard" components={components} tabComponents={tabComponents}
|
||||||
leftHeaderActionsComponent={GroupLabel} onReady={onReady} />
|
leftHeaderActionsComponent={GroupLabel} rightHeaderActionsComponent={GroupActions} onReady={onReady} />
|
||||||
</div>
|
</div>
|
||||||
</>)}
|
</>)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
16
live/src/GroupActions.jsx
Normal file
16
live/src/GroupActions.jsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
// Right end of every tab bar: maximise / restore this group.
|
||||||
|
export default function GroupActions({ api, containerApi }) {
|
||||||
|
const [max, setMax] = useState(() => api.isMaximized())
|
||||||
|
useEffect(() => {
|
||||||
|
const d = containerApi.onDidMaximizedGroupChange?.(() => setMax(api.isMaximized()))
|
||||||
|
return () => d?.dispose?.()
|
||||||
|
}, [api, containerApi])
|
||||||
|
const toggle = e => { e.stopPropagation(); if (api.isMaximized()) api.exitMaximized(); else api.maximize(); setMax(api.isMaximized()) }
|
||||||
|
return (
|
||||||
|
<div className="groupactions" onPointerDown={e => e.stopPropagation()}>
|
||||||
|
<button className="gbtn" onClick={toggle} title={max ? 'restore' : 'maximise this window'}>{max ? '🗗' : '⛶'}</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -71,3 +71,6 @@ html, body, #root { height:100%; margin:0; background:var(--bg); color:var(--fg)
|
|||||||
.grouplabel { display:flex; align-items:center; height:100%; padding:0 10px; font-size:12px; white-space:nowrap; border-right:1px solid #2a2a2a; cursor:default; }
|
.grouplabel { display:flex; align-items:center; height:100%; padding:0 10px; font-size:12px; white-space:nowrap; border-right:1px solid #2a2a2a; cursor:default; }
|
||||||
.grouplabel .gname { color:var(--acc); font-weight:700; }
|
.grouplabel .gname { color:var(--acc); font-weight:700; }
|
||||||
.grouplabel .hint { color:#555; }
|
.grouplabel .hint { color:#555; }
|
||||||
|
.groupactions { display:flex; align-items:center; height:100%; padding:0 6px; }
|
||||||
|
.gbtn { background:transparent; color:var(--mut); border:0; cursor:pointer; font-size:14px; padding:0 6px; line-height:1; }
|
||||||
|
.gbtn:hover { color:var(--fg); }
|
||||||
|
|||||||
Reference in New Issue
Block a user