components/Screensaver/Screensaver.jsxjavascript
import React from "react";
import { useScreensaver } from "../../services/screensaver";
import { useContent } from "../../services/content";
import { useConfig } from "../../services/config/config";
import { CacheableVideo } from "../CacheableVideo";
import "./Screensaver.scss";
/**
* Full-screen overlay shown while the app is idle (see useScreensaver).
* Stays mounted at all times so the opacity transition plays both when
* fading in and when fading out; visibility is toggled via CSS class.
* Dismissing it needs no handler here - any interaction is already picked
* up by the global listeners in useIdle and flips isIdle back to false.
*
* The video shown depends on `defaultMode` (config-schema.js): each
* presentation mode's own content file (see PRESENTATION_MODES in
* presentationModes.js, loaded per-route by ContentProvider) defines its own
* screensaver under "screensavers", keyed by that mode's key. In multi-app/
* navbar mode (defaultMode "all") or for an unrecognized defaultMode value,
* no entry matches and no video is shown.
*/
export const Screensaver = () => {
const { isIdle, screensaverFadeDuration } = useScreensaver();
const { content } = useContent();
const { defaultMode } = useConfig();
const screensaverSrc = content.screensavers?.[defaultMode];
return (
<div
className={`screensaver${isIdle ? " screensaver--visible" : ""}`}
style={{ transitionDuration: `${screensaverFadeDuration}ms` }}
aria-hidden={!isIdle}>
{screensaverSrc && (
<CacheableVideo src={screensaverSrc} playing={isIdle} loop muted playsInline />
)}
</div>
);
};