A fullscreen auto-advancing slideshow any user can start. Design:
docs/CONCEPT_DIASHOW.md.
- lib/diashow/queue.ts: SlideQueue state machine — liveQueue drains first
(FIFO, seeded by SSE upload-processed), then shuffleQueue (refilled
from allKnown minus a 5-id ring buffer of recently shown). Pure logic,
unit-testable.
- lib/diashow/wakelock.ts: Screen Wake Lock wrapper that re-acquires on
visibility change (the OS drops the lock when the tab hides).
- lib/diashow/transitions/{index,crossfade,kenburns}.ts: registry +
the v1 transitions. Adding a new animation is one file + one entry —
the extensibility target from docs/FEATURES §2.9.
- routes/diashow/+page.svelte: fullscreen page, hides bottom nav,
6 s default dwell (3/6/10 configurable), keyboard shortcuts
(Escape exits, Space toggles pause), tap-to-reveal overlay with
pause / dwell / transition / exit. Respects $dataMode to choose
preview vs. original URL.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
// Thin wrapper around the Screen Wake Lock API. Held by the diashow page so a phone
|
|
// driving a projector doesn't sleep. No-op on unsupported browsers (Firefox, older
|
|
// Safari).
|
|
//
|
|
// Wake locks die when the document goes hidden; the page re-acquires on visible to
|
|
// keep the screen on across short interruptions.
|
|
|
|
interface SentinelLike {
|
|
release: () => Promise<void>;
|
|
}
|
|
|
|
let sentinel: SentinelLike | null = null;
|
|
let visibilityHandler: (() => void) | null = null;
|
|
|
|
export async function acquireWakeLock(): Promise<void> {
|
|
const wakeLock = (navigator as Navigator & { wakeLock?: { request: (t: string) => Promise<SentinelLike> } }).wakeLock;
|
|
if (!wakeLock) return;
|
|
try {
|
|
sentinel = await wakeLock.request('screen');
|
|
} catch {
|
|
// User denied, or already released — nothing useful to do.
|
|
sentinel = null;
|
|
}
|
|
|
|
// Re-acquire when the page becomes visible again (the OS releases the lock
|
|
// while the tab is hidden).
|
|
if (!visibilityHandler) {
|
|
visibilityHandler = async () => {
|
|
if (document.visibilityState === 'visible' && sentinel === null) {
|
|
try {
|
|
sentinel = await wakeLock.request('screen');
|
|
} catch {
|
|
sentinel = null;
|
|
}
|
|
}
|
|
};
|
|
document.addEventListener('visibilitychange', visibilityHandler);
|
|
}
|
|
}
|
|
|
|
export async function releaseWakeLock(): Promise<void> {
|
|
if (sentinel) {
|
|
try {
|
|
await sentinel.release();
|
|
} catch {
|
|
// ignore — release after release is fine
|
|
}
|
|
sentinel = null;
|
|
}
|
|
if (visibilityHandler) {
|
|
document.removeEventListener('visibilitychange', visibilityHandler);
|
|
visibilityHandler = null;
|
|
}
|
|
}
|