diff --git a/frontend/src/components/SharePopover.vue b/frontend/src/components/SharePopover.vue index 54fbe11b..30eec172 100644 --- a/frontend/src/components/SharePopover.vue +++ b/frontend/src/components/SharePopover.vue @@ -72,7 +72,7 @@ const handleCopyLink = async (close) => { if (!presentationId.value) return close() - const link = `${window.location.origin}/slides/presentation/view/${presentationId.value}` + const link = `${window.location.origin}/slides/presentation/${presentationId.value}` copyToClipboard(link) } diff --git a/frontend/src/pages/Slideshow.vue b/frontend/src/pages/Slideshow.vue index 7051c8d3..f9da9d8d 100644 --- a/frontend/src/pages/Slideshow.vue +++ b/frontend/src/pages/Slideshow.vue @@ -99,7 +99,15 @@ const props = defineProps({ const transition = ref('none') const transform = ref('') const opacity = ref(1) -const clipPath = ref('') +const windowWidth = ref(window.innerWidth) +const windowHeight = ref(window.innerHeight) + +const clipPath = computed(() => { + if (!inSlideShowMode.value) return 'none' + const slideHeight = 540 * (windowWidth.value / 960) + const inset = Math.max(0, (windowHeight.value - slideHeight) / 2) + return `inset(${inset}px 0px ${inset}px 0px)` +}) const getElementKey = (element) => { return element.refId || element.id @@ -122,9 +130,8 @@ const isMagicMoveApplied = computed(() => { }) const slideStyles = computed(() => { - // scale slide to fit current screen size while maintaining 16:9 aspect ratio - const screenWidth = window.screen.width - const widthScale = screenWidth / 960 + // scale slide to fit screen width while maintaining 16:9 aspect ratio + const widthScale = windowWidth.value / 960 const baseStyles = { width: '960px', @@ -249,38 +256,26 @@ const slideLeave = (el, done) => { done() } -const resetCursorVisibility = () => { - if (slideCursor.value != 'none') return - let cursorTimer +let cursorTimer = null +const resetCursorVisibility = () => { slideCursor.value = 'auto' clearTimeout(cursorTimer) cursorTimer = setTimeout(() => { slideCursor.value = 'none' - }, 9000) + }, 4000) } const handleFullScreenChange = () => { if (document.fullscreenElement) { - slideContainerRef.value.addEventListener('mousemove', resetCursorVisibility) + slideContainerRef.value?.addEventListener('mousemove', resetCursorVisibility) inSlideShowMode.value = true } else { - slideContainerRef.value.removeEventListener('mousemove', resetCursorVisibility) + slideContainerRef.value?.removeEventListener('mousemove', resetCursorVisibility) endSlideShow() } } -const setClipPath = () => { - const screenHeight = window.screen.height - const scale = window.screen.width / 960 - const containerHeight = 540 * scale - - // divide remaining height by 2 to set inset on top and bottom - const inset = (screenHeight - containerHeight) / 2 - - clipPath.value = `inset(${inset}px 0px ${inset}px 0px)` -} - const slideContainerStyles = computed(() => { return { clipPath: clipPath.value, @@ -305,8 +300,6 @@ const initFullscreenMode = async () => { fullscreenMethod.call(container).catch((e) => { router.replace({ name: 'PresentationEditor' }) }) - - setClipPath() } } @@ -315,11 +308,17 @@ const loadPresentation = async () => { initPresentationDoc(props.presentationId) } +const updateWindowSize = () => { + windowWidth.value = window.innerWidth + windowHeight.value = window.innerHeight +} + onActivated(() => { resetFocus() loadPresentation() initFullscreenMode() document.addEventListener('fullscreenchange', handleFullScreenChange) + window.addEventListener('resize', updateWindowSize) // Initial prefetch of next slide setTimeout(() => { @@ -329,6 +328,7 @@ onActivated(() => { onDeactivated(() => { document.removeEventListener('fullscreenchange', handleFullScreenChange) + window.removeEventListener('resize', updateWindowSize) }) watch( diff --git a/frontend/src/router.ts b/frontend/src/router.ts index 38fee25e..9171528a 100644 --- a/frontend/src/router.ts +++ b/frontend/src/router.ts @@ -35,9 +35,7 @@ const routes = [ }, { path: '/presentation/view/:presentationId/:slug?', - name: 'PresentationView', - component: () => import('@/pages/PresentationEditor.vue'), - props: withPresentationProps, + redirect: (route: RouteLocationNormalized) => ({ name: 'PresentationEditor', params: route.params, query: route.query }), }, { path: '/slideshow/:presentationId/:slug?', @@ -81,7 +79,7 @@ router.beforeEach(async (to, from, next) => { const isLoggedIn = session.isLoggedIn - if (!['Slideshow', 'PresentationEditor', 'Home', 'PresentationView'].includes(to.name as string)) { + if (!['Slideshow', 'PresentationEditor', 'Home'].includes(to.name as string)) { return next() } @@ -89,18 +87,10 @@ router.beforeEach(async (to, from, next) => { return next({ name: 'PresentationEditor', params: to.params, query: to.query } ) } else if (to.name === 'Slideshow') { return next() - } else if (to.name === 'PresentationEditor' || to.name == 'PresentationView') { + } else if (to.name === 'PresentationEditor') { if (from.name != to.name || from.params.presentationId != to.params.presentationId) { editorAccess = await getEditorAccess(to.params.presentationId as string) } - if (to.name === 'PresentationView' && editorAccess === 'edit') { - return next({ - name: 'PresentationEditor', - params: to.params, - query: to.query, - replace: true, - }) - } if (['edit', 'view'].includes(editorAccess)) { return next() }