From ec69c85102ff41573685862083c9d60b773d7d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20T=C3=A4kker?= Date: Sat, 22 Aug 2026 20:58:39 +0200 Subject: [PATCH] Applied browser fullscreen --- app/components/Player/Fullscreen.vue | 6 +- .../Player/Fullscreen/LyricsDisplay.vue | 2 +- app/components/Player/index.vue | 4 +- app/composables/useFullscreen.ts | 67 ++++++++++++++++++- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/app/components/Player/Fullscreen.vue b/app/components/Player/Fullscreen.vue index 7404194..6cfbae9 100644 --- a/app/components/Player/Fullscreen.vue +++ b/app/components/Player/Fullscreen.vue @@ -1,5 +1,5 @@ @@ -51,7 +51,7 @@ nuxtApp.hook("page:finish", () => { name="lucide:x" class="close-btn" :class="{ show: mouseMovedRecently }" - @click="fullscreen = false" + @click="closeFullscreen()" />
diff --git a/app/components/Player/Fullscreen/LyricsDisplay.vue b/app/components/Player/Fullscreen/LyricsDisplay.vue index 09c49ef..819b104 100644 --- a/app/components/Player/Fullscreen/LyricsDisplay.vue +++ b/app/components/Player/Fullscreen/LyricsDisplay.vue @@ -6,7 +6,7 @@ const { animationDuration, offset, showScrollBar } = defineProps<{ }>() const song = useSong() -const fullscreen = useFullscreen() +const { fullscreen } = useFullscreen() const { secondsPlayed } = usePlayer() const parsedLyrics = computed(() => { diff --git a/app/components/Player/index.vue b/app/components/Player/index.vue index 1b08c68..9b9206b 100644 --- a/app/components/Player/index.vue +++ b/app/components/Player/index.vue @@ -39,7 +39,7 @@ const durationFormatted = computed(() => ) const toast = useToast() -const fullscreen = useFullscreen() +const { open: openFullscreen } = useFullscreen() diff --git a/app/composables/useFullscreen.ts b/app/composables/useFullscreen.ts index cf3c848..0a4436d 100644 --- a/app/composables/useFullscreen.ts +++ b/app/composables/useFullscreen.ts @@ -1 +1,66 @@ -export const useFullscreen = () => useState("fullscreen", () => false) +type FullscreenState = ReturnType> + +type FullscreenControls = { + fullscreen: FullscreenState + open: () => Promise + close: () => Promise + toggle: () => Promise +} + +const syncFullscreenState = (fullscreen: FullscreenState) => { + fullscreen.value = Boolean(document.fullscreenElement) +} + +let fullscreenListenerInstalled = false + +export const useFullscreen = () => { + const fullscreen = useState("fullscreen", () => false) + + const open = async () => { + fullscreen.value = true + + if (!import.meta.client) return true + if (!document.documentElement.requestFullscreen) return true + + try { + await document.documentElement.requestFullscreen() + return true + } catch { + fullscreen.value = false + return false + } + } + + const close = async () => { + if (import.meta.client && document.fullscreenElement) { + try { + await document.exitFullscreen() + } catch { + // Fall through to keep the app state consistent. + } + } + + fullscreen.value = false + return true + } + + const toggle = async () => { + if (fullscreen.value) return close() + return open() + } + + if (import.meta.client && !fullscreenListenerInstalled) { + fullscreenListenerInstalled = true + document.addEventListener("fullscreenchange", () => { + syncFullscreenState(fullscreen) + }) + syncFullscreenState(fullscreen) + } + + return { + fullscreen, + open, + close, + toggle, + } as FullscreenControls +}