Skip to content

Commit c7ae747

Browse files
HugoGresseclaude
andauthored
feat: add fullscreen toggle to the intermission screen (#266)
Room/kiosk displays want edge-to-edge. Add a fullscreen button next to the settings cog (top-right controls, fades with idle). Uses the Fullscreen API and swaps the enter/exit icon on fullscreenchange. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0e61c05 commit c7ae747

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

src/public/intermission/IntermissionScreen.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ export const IntermissionScreen = ({
8989
return () => clearInterval(id)
9090
}, [intermittent, intervalSec])
9191

92+
// Fullscreen toggle — the intermission runs on a room screen, so let the operator go edge-to-edge
93+
const [isFullscreen, setIsFullscreen] = useState(false)
94+
useEffect(() => {
95+
const onChange = () => setIsFullscreen(Boolean(document.fullscreenElement))
96+
document.addEventListener('fullscreenchange', onChange)
97+
return () => document.removeEventListener('fullscreenchange', onChange)
98+
}, [])
99+
const toggleFullscreen = () => {
100+
if (document.fullscreenElement) {
101+
document.exitFullscreen?.()
102+
} else {
103+
document.documentElement.requestFullscreen?.()
104+
}
105+
}
106+
92107
// Hide the controls (and cursor) after a period of pointer inactivity; reveal on any movement
93108
const [idle, setIdle] = useState(false)
94109
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
@@ -145,6 +160,37 @@ export const IntermissionScreen = ({
145160
pointerEvents: idle && !settingsOpen ? 'none' : 'auto',
146161
transition: 'opacity 0.4s ease',
147162
}}>
163+
<button
164+
style={styles.cog}
165+
aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}
166+
onClick={toggleFullscreen}>
167+
<svg
168+
width="22"
169+
height="22"
170+
viewBox="0 0 24 24"
171+
fill="none"
172+
stroke="currentColor"
173+
strokeWidth="2"
174+
strokeLinecap="round"
175+
strokeLinejoin="round">
176+
{isFullscreen ? (
177+
<>
178+
<path d="M8 3v3a2 2 0 0 1-2 2H3" />
179+
<path d="M21 8h-3a2 2 0 0 1-2-2V3" />
180+
<path d="M3 16h3a2 2 0 0 1 2 2v3" />
181+
<path d="M16 21v-3a2 2 0 0 1 2-2h3" />
182+
</>
183+
) : (
184+
<>
185+
<path d="M8 3H5a2 2 0 0 0-2 2v3" />
186+
<path d="M21 8V5a2 2 0 0 0-2-2h-3" />
187+
<path d="M3 16v3a2 2 0 0 0 2 2h3" />
188+
<path d="M16 21h3a2 2 0 0 0 2-2v-3" />
189+
</>
190+
)}
191+
</svg>
192+
</button>
193+
148194
<button style={styles.cog} aria-label="Settings" onClick={() => setSettingsOpen((v) => !v)}>
149195
<svg
150196
width="22"

0 commit comments

Comments
 (0)