frontend: remove fullpage.js, rewrite equivalent
Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
parent
cbb36e7fb9
commit
87e3b40a54
7 changed files with 353 additions and 185 deletions
|
|
@ -1,8 +1,9 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { EyeOff, Info } from 'lucide-vue-next'
|
||||
import { ChevronLeft, ChevronRight, EyeOff, Info } from 'lucide-vue-next'
|
||||
import { cn } from '@/lib/utils.js'
|
||||
|
||||
defineProps(['post'])
|
||||
const props = defineProps(['post', 'class'])
|
||||
const section = ref(null)
|
||||
|
||||
let postDataVisible = ref(true)
|
||||
|
|
@ -11,98 +12,182 @@ const postDataTitle = ref(null)
|
|||
const postDataDescription = ref(null)
|
||||
const postActionBtn = ref(null)
|
||||
|
||||
defineEmits(['scrollableelemententer', 'scrollableelementleave'])
|
||||
|
||||
function onVisible() {
|
||||
document.addEventListener('keydown', onFullpageKeyDown)
|
||||
}
|
||||
|
||||
function onInvisible() {
|
||||
document.removeEventListener('keydown', onFullpageKeyDown)
|
||||
}
|
||||
|
||||
defineExpose({ onVisible, onInvisible })
|
||||
|
||||
function onFullpageKeyDown(event) {
|
||||
if (event.key === 'ArrowLeft') scrollSlideDir(-1)
|
||||
else if (event.key === 'ArrowRight') scrollSlideDir(1)
|
||||
else return
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
function postDataToggle() {
|
||||
if (postDataVisible.value) {
|
||||
for (const data of postData.value) {
|
||||
data.classList.remove('backdrop-blur-sm')
|
||||
data.classList.remove('bg-gray-400/10')
|
||||
data.classList.add('bg-gray-400/0')
|
||||
}
|
||||
for (const title of postDataTitle.value) {
|
||||
title.classList.add('opacity-0')
|
||||
}
|
||||
for (const desc of postDataDescription.value) {
|
||||
desc.classList.add('opacity-0')
|
||||
desc.classList.remove('scrollable-element')
|
||||
}
|
||||
for (const btn of postActionBtn.value) {
|
||||
btn.classList.remove('top-0')
|
||||
btn.classList.remove('right-0')
|
||||
btn.classList.add('left-0')
|
||||
btn.classList.add('bottom-0')
|
||||
}
|
||||
postData.value.classList.remove('backdrop-blur-sm')
|
||||
postData.value.classList.remove('bg-gray-400/10')
|
||||
postData.value.classList.add('bg-gray-400/0')
|
||||
postDataTitle.value.classList.add('opacity-0')
|
||||
postDataDescription.value.classList.add('opacity-0')
|
||||
postDataDescription.value.classList.remove('scrollable-element')
|
||||
postActionBtn.value.classList.remove('top-0')
|
||||
postActionBtn.value.classList.remove('right-0')
|
||||
postActionBtn.value.classList.add('left-0')
|
||||
postActionBtn.value.classList.add('bottom-0')
|
||||
postDataVisible.value = false
|
||||
setTimeout(() => {
|
||||
postDataTitle.value.classList.add('hidden')
|
||||
postDataDescription.value.classList.add('hidden')
|
||||
}, 500)
|
||||
} else {
|
||||
for (const data of postData.value) {
|
||||
data.classList.add('backdrop-blur-sm')
|
||||
data.classList.add('bg-gray-400/10')
|
||||
data.classList.remove('bg-gray-400/0')
|
||||
}
|
||||
for (const title of postDataTitle.value) {
|
||||
title.classList.remove('opacity-0')
|
||||
}
|
||||
for (const desc of postDataDescription.value) {
|
||||
desc.classList.remove('opacity-0')
|
||||
desc.classList.add('scrollable-element')
|
||||
}
|
||||
for (const btn of postActionBtn.value) {
|
||||
btn.classList.add('top-0')
|
||||
btn.classList.add('right-0')
|
||||
btn.classList.remove('left-0')
|
||||
btn.classList.remove('bottom-0')
|
||||
}
|
||||
postDataTitle.value.classList.remove('hidden')
|
||||
postDataDescription.value.classList.remove('hidden')
|
||||
postData.value.classList.add('backdrop-blur-sm')
|
||||
postData.value.classList.add('bg-gray-400/10')
|
||||
postData.value.classList.remove('bg-gray-400/0')
|
||||
postDataTitle.value.classList.remove('opacity-0')
|
||||
postDataDescription.value.classList.remove('opacity-0')
|
||||
postDataDescription.value.classList.add('scrollable-element')
|
||||
postActionBtn.value.classList.add('top-0')
|
||||
postActionBtn.value.classList.add('right-0')
|
||||
postActionBtn.value.classList.remove('left-0')
|
||||
postActionBtn.value.classList.remove('bottom-0')
|
||||
postDataVisible.value = true
|
||||
}
|
||||
}
|
||||
|
||||
let slidesContainer = ref(null)
|
||||
let fpCurrentSlide = 0
|
||||
|
||||
function scrollSlideDir(direction) {
|
||||
scrollSlideToIndex(
|
||||
(((fpCurrentSlide + direction) % slidesContainer.value.children.length) +
|
||||
slidesContainer.value.children.length) %
|
||||
slidesContainer.value.children.length
|
||||
)
|
||||
}
|
||||
|
||||
function stopChildrenVideo(element) {
|
||||
for (const child of element.children) {
|
||||
if (child.nodeName === 'VIDEO') {
|
||||
child.pause()
|
||||
child.currentTime = 0
|
||||
return
|
||||
} else {
|
||||
stopChildrenVideo(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function playChildrenVideo(element) {
|
||||
for (const child of element.children) {
|
||||
if (child.nodeName === 'VIDEO') {
|
||||
child.play()
|
||||
return
|
||||
} else {
|
||||
playChildrenVideo(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scrollSlideToIndex(index) {
|
||||
const fromSlide = slidesContainer.value.children[fpCurrentSlide]
|
||||
stopChildrenVideo(fromSlide)
|
||||
slidesContainer.value.scroll({
|
||||
top: 0,
|
||||
left: window.innerWidth * index,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
fpCurrentSlide = index
|
||||
const toSlide = slidesContainer.value.children[index]
|
||||
playChildrenVideo(toSlide)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="section relative overflow-hidden" ref="section" :data-anchor="'post-' + post.id">
|
||||
<div class="slide relative overflow-hidden" v-for="asset in post.assets" :key="asset.id">
|
||||
<img
|
||||
class="absolute top-0 left-0 w-full h-full object-cover -z-10"
|
||||
:data-src="asset.presignedUrl"
|
||||
v-if="asset.contentType.startsWith('image/')"
|
||||
/>
|
||||
<video
|
||||
class="absolute top-0 left-0 w-full h-full object-cover -z-10"
|
||||
loop
|
||||
muted="true"
|
||||
playsinline
|
||||
data-autoplay
|
||||
v-else
|
||||
>
|
||||
<source :src="asset.presignedUrl" :type="asset.contentType" />
|
||||
</video>
|
||||
<div
|
||||
:class="cn('w-screen h-dvh relative overscroll-y-contain', props.class)"
|
||||
ref="section"
|
||||
:data-anchor="'post-' + post.id"
|
||||
>
|
||||
<div
|
||||
class="absolute top-1/2 left-0 mx-4 cursor-pointer z-30"
|
||||
v-if="post.assets.length > 1"
|
||||
@click="scrollSlideDir(-1)"
|
||||
>
|
||||
<ChevronLeft size="64" />
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 left-0 min-w-full max-w-full w-full lg:min-w-[20%] lg:max-w-[40%] lg:w-auto z-40 flex"
|
||||
>
|
||||
<div
|
||||
class="grid grid-cols-3 grid-rows-5 absolute w-full h-full top-0 left-0 pointer-events-none"
|
||||
ref="postData"
|
||||
class="m-6 p-2 bg-gray-400/10 h-full w-full backdrop-blur-sm rounded-lg pointer-events-auto transition-colors duration-500"
|
||||
>
|
||||
<div
|
||||
ref="postData"
|
||||
class="col-start-1 col-span-3 lg:col-span-1 row-start-4 row-span-2 self-end place-self-stretch m-6 p-2 bg-gray-400/10 backdrop-blur-sm rounded-lg pointer-events-auto transition-colors duration-500"
|
||||
class="absolute top-0 right-0 m-2 p-2 backdrop-blur-sm rounded-sm bg-black/10 hover:bg-black/20 cursor-pointer transition-colors duration-200 opacity-100"
|
||||
ref="postActionBtn"
|
||||
@click="postDataToggle"
|
||||
>
|
||||
<div
|
||||
class="absolute top-0 right-0 m-2 p-2 backdrop-blur-sm rounded-sm bg-black/10 hover:bg-black/20 cursor-pointer transition-colors duration-200 opacity-100"
|
||||
ref="postActionBtn"
|
||||
@click="postDataToggle"
|
||||
>
|
||||
<EyeOff v-if="postDataVisible" :size="20" />
|
||||
<Info :size="20" v-else />
|
||||
</div>
|
||||
<h2
|
||||
ref="postDataTitle"
|
||||
class="mx-2 scroll-m-20 pb-2 text-3xl font-semibold tracking-tight transition-opacity duration-500 mt-1"
|
||||
>
|
||||
{{ post.city }}, {{ post.country }}
|
||||
</h2>
|
||||
<div
|
||||
ref="postDataDescription"
|
||||
class="m-2 scrollable-element max-h-48 overflow-y-scroll transition-opacity duration-500"
|
||||
v-html="post.formatedDescription"
|
||||
></div>
|
||||
<EyeOff v-if="postDataVisible" :size="20" />
|
||||
<Info :size="20" v-else />
|
||||
</div>
|
||||
<h2
|
||||
ref="postDataTitle"
|
||||
class="mx-2 scroll-m-20 pb-2 text-3xl font-semibold tracking-tight transition-opacity duration-500 mt-1"
|
||||
>
|
||||
{{ post.city }}, {{ post.country }}
|
||||
</h2>
|
||||
<div
|
||||
ref="postDataDescription"
|
||||
class="m-2 max-h-48 overflow-y-scroll transition-opacity duration-500 overscroll-y-contain"
|
||||
v-html="post.formatedDescription"
|
||||
@mouseenter="$emit('scrollableelemententer')"
|
||||
@touchstart="$emit('scrollableelemententer')"
|
||||
@mouseleave="$emit('scrollableelementleave')"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="slidesContainer" class="h-dvh flex flex-nowrap overflow-hidden">
|
||||
<div
|
||||
class="w-screen h-dvh relative overflow-hidden overscroll-y-contain flex-grow-0 flex-shrink-0"
|
||||
v-for="asset in post.assets"
|
||||
:key="asset.id"
|
||||
>
|
||||
<img
|
||||
class="absolute top-0 left-0 w-full h-dvh object-cover -z-10"
|
||||
:src="asset.presignedUrl"
|
||||
v-if="asset.contentType.startsWith('image/')"
|
||||
/>
|
||||
<video
|
||||
class="absolute top-0 left-0 w-full h-dvh object-cover -z-10"
|
||||
loop
|
||||
muted="true"
|
||||
playsinline
|
||||
v-else
|
||||
>
|
||||
<source :src="asset.presignedUrl" :type="asset.contentType" />
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-1/2 right-0 mx-4 cursor-pointer z-30"
|
||||
v-if="post.assets.length > 1"
|
||||
@click="scrollSlideDir(1)"
|
||||
>
|
||||
<ChevronRight size="64" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
<script setup>
|
||||
const props = defineProps(['class'])
|
||||
|
||||
import { usePostsStore } from '@/stores/posts.js'
|
||||
import Countdown from '@/components/Countdown.vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { ChevronDown } from 'lucide-vue-next'
|
||||
|
||||
const enableCountdown = ref(false)
|
||||
const countdownDate = ref(new Date('2024-07-28 07:00:00'))
|
||||
|
|
@ -18,14 +21,16 @@ const postsStore = usePostsStore()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="section" ref="section" data-anchor="welcome-section">
|
||||
<div :class="props.class" ref="section" data-anchor="welcome-section">
|
||||
<div class="flex flex-col w-full h-full items-center justify-center text-center">
|
||||
<h3 class="scroll-m-20 text-2xl font-semibold tracking-tight mx-4 my-4">
|
||||
3 semaines pour traverser 7 pays d'Europe en train
|
||||
</h3>
|
||||
<div v-if="postsStore.posts.length > 0">
|
||||
<p class="mx-4">suivez mon voyage en naviguant vers le bas</p>
|
||||
<div class="arrow" />
|
||||
<p v-if="postsStore.posts.length > 0" class="mx-4">
|
||||
suivez mon voyage en naviguant vers le bas
|
||||
</p>
|
||||
<div v-if="postsStore.posts.length > 0" class="arrow mt-6">
|
||||
<ChevronDown size="96" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="mx-4">le contenu n'est pas encore disponible, revenez plus tard</p>
|
||||
|
|
@ -40,29 +45,20 @@ const postsStore = usePostsStore()
|
|||
|
||||
<style scoped>
|
||||
.arrow {
|
||||
margin-top: 40px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
width: 3vh;
|
||||
height: 3vh;
|
||||
border-bottom: 5px solid white;
|
||||
border-right: 5px solid white;
|
||||
transform: rotate(45deg);
|
||||
animation: arrowAnimation 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes arrowAnimation {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: rotate(45deg) translate(-20px, -20px);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: rotate(45deg) translate(20px, 20px);
|
||||
transform: translate(0, 40px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import './assets/main.css'
|
|||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import 'vue-fullpage.js/dist/style.css'
|
||||
import VueFullPage from 'vue-fullpage.js'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
|
@ -14,7 +12,6 @@ import OpenLayersMap from 'vue3-openlayers'
|
|||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(VueFullPage)
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(OpenLayersMap)
|
||||
|
|
|
|||
|
|
@ -1,78 +1,176 @@
|
|||
<script setup>
|
||||
import PostComponent from '@/components/PostComponent.vue'
|
||||
import { usePostsStore } from '@/stores/posts.js'
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import WelcomeComponent from '@/components/WelcomeComponent.vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const postsStore = usePostsStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const fullpage = ref(null)
|
||||
const fullpageOptions = ref({
|
||||
licenseKey: 'gplv3-license',
|
||||
menu: '#menu',
|
||||
scrollBar: true,
|
||||
normalScrollElements: '.scrollable-element',
|
||||
scrollOverflow: false,
|
||||
onLeave: onLeave,
|
||||
credits: { enabled: false }
|
||||
})
|
||||
const menu = ref(null)
|
||||
const menuItems = ref([])
|
||||
let fullPageInit = false
|
||||
const fullpageEnable = ref(false)
|
||||
const fullpageKey = ref(Math.floor(Math.random() * 1000))
|
||||
|
||||
/*
|
||||
There is a huge mess in this code because I couldn't find a way to make fullpage.js work well when
|
||||
changing views.
|
||||
At this point I've tried so many things that in the end I don't know which attempt worked best, so
|
||||
I'm leaving this as is because reloading the page is the only way I could make the app work for the
|
||||
users. How come after every ***** hack I've tried to completely destroy and rebuild the fullpage
|
||||
instance it still finds a way to be alive and break when changing views????
|
||||
*/
|
||||
const fullpage = ref(null)
|
||||
let fpMouseInScrollableElement = false
|
||||
let fpIsScrolling = false
|
||||
let fpCurrentlyInView = 0
|
||||
let fpTouchScroll = null
|
||||
let fpTouchScrollX = 0
|
||||
let fpTouchScrollY = 0
|
||||
let fpResizeTimeout = false
|
||||
|
||||
async function initFullpage() {
|
||||
if (fullPageInit) return
|
||||
|
||||
fullpageKey.value += 5
|
||||
fullpageEnable.value = true
|
||||
onMounted(async () => {
|
||||
await postsStore.fetchPosts()
|
||||
await nextTick()
|
||||
try {
|
||||
fullpage.value.init()
|
||||
} catch (e) {
|
||||
console.log(
|
||||
'failed to reload fullpage.js because it sucks with vue, reloading page as last resort'
|
||||
)
|
||||
window.location.reload()
|
||||
return
|
||||
}
|
||||
fullPageInit = true
|
||||
fullpageScrollToAnchor(window.location.hash.substring(1))
|
||||
})
|
||||
|
||||
window.addEventListener('popstate', (event) => {
|
||||
fullpageScrollToAnchor(window.location.hash.substring(1))
|
||||
})
|
||||
|
||||
window.addEventListener('resize', (event) => {
|
||||
clearTimeout(fpResizeTimeout)
|
||||
fpResizeTimeout = setTimeout(fullpageScrollToAnchor(window.location.hash.substring(1)), 500)
|
||||
})
|
||||
|
||||
function onFullpageWheel(event) {
|
||||
if (fpMouseInScrollableElement) return
|
||||
if (fpIsScrolling) return
|
||||
|
||||
// prevent scroll
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
fullpageScrollDir(event.deltaY > 0 ? 1 : -1)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('post view mounted')
|
||||
postsStore.fetchPosts().then(() => {
|
||||
initFullpage()
|
||||
})
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'ArrowUp' || event.key === 'PageUp') fullpageScrollDir(-1)
|
||||
else if (event.key === 'ArrowDown' || event.key === ' ' || event.key === 'PageDown')
|
||||
fullpageScrollDir(1)
|
||||
else return
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
})
|
||||
|
||||
onBeforeUnmount(async () => {
|
||||
console.log('caught post view unmount')
|
||||
if (
|
||||
typeof window.fullpage_api !== 'undefined' &&
|
||||
typeof window.fullpage_api.destroy !== 'undefined'
|
||||
) {
|
||||
window.fullpage_api.destroy('all')
|
||||
// touch screen support
|
||||
function onFullpageTouchStart(event) {
|
||||
// more than one finger, not a scroll
|
||||
if (fpTouchScroll) {
|
||||
fpTouchScroll = null
|
||||
return
|
||||
}
|
||||
fullpageKey.value++
|
||||
fullpageEnable.value = false
|
||||
await nextTick()
|
||||
fullPageInit = false
|
||||
})
|
||||
|
||||
const touch = event.changedTouches.item(0)
|
||||
fpTouchScrollX = touch.clientX
|
||||
fpTouchScrollY = touch.clientY
|
||||
fpTouchScroll = touch
|
||||
}
|
||||
|
||||
function onFullpageTouchMove(event) {
|
||||
if (fpMouseInScrollableElement) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
function onFullpageTouchEnd(event) {
|
||||
if (fpMouseInScrollableElement) {
|
||||
fpMouseInScrollableElement = false
|
||||
return
|
||||
}
|
||||
if (fpIsScrolling) return
|
||||
|
||||
const touch = event.changedTouches.item(0)
|
||||
const endTouchX = touch.clientX
|
||||
const endTouchY = touch.clientY
|
||||
|
||||
const diffX = endTouchX - fpTouchScrollX
|
||||
const diffY = endTouchY - fpTouchScrollY
|
||||
|
||||
if (Math.abs(diffY) > Math.abs(diffX)) {
|
||||
// small diff, not worth scroll
|
||||
if (Math.abs(diffY) < 10) {
|
||||
fpTouchScroll = null
|
||||
return
|
||||
}
|
||||
if (diffY > 0) fullpageScrollDir(-1)
|
||||
else fullpageScrollDir(1)
|
||||
}
|
||||
|
||||
fpTouchScroll = null
|
||||
}
|
||||
|
||||
// actual scrolling
|
||||
function fullpageScrollDir(direction) {
|
||||
if (direction < 0 && fpCurrentlyInView <= 0) return
|
||||
if (direction > 0 && fpCurrentlyInView >= fullpage.value.children.length - 1) return
|
||||
|
||||
fullpageScrollToIndex(fpCurrentlyInView + direction)
|
||||
}
|
||||
|
||||
function fullpageScrollToAnchor(target) {
|
||||
for (let i = 0; i < fullpage.value.children.length; i++) {
|
||||
const slide = fullpage.value.children[i]
|
||||
if (slide.dataset.anchor === target) {
|
||||
fullpageScrollToIndex(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const postComponents = ref([])
|
||||
function fullpageScrollToIndex(target) {
|
||||
fpIsScrolling = true
|
||||
if (fpCurrentlyInView !== 0) {
|
||||
const from = postComponents.value[fpCurrentlyInView - 1]
|
||||
if (Object.hasOwn(from, 'onInvisible')) from.onInvisible()
|
||||
}
|
||||
if (target !== 0) {
|
||||
const to = postComponents.value[target - 1]
|
||||
if (Object.hasOwn(to, 'onVisible')) to.onVisible()
|
||||
}
|
||||
const to = fullpage.value.children[target]
|
||||
onLeave(null, to.dataset.anchor)
|
||||
fullpage.value.scroll({
|
||||
top: window.innerHeight * target,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
router.push({ name: route.name, hash: '#' + to.dataset.anchor })
|
||||
fpCurrentlyInView = target
|
||||
for (let i = 0; i < menu.value.children.length; i++) {
|
||||
const menuItem = menu.value.children[i]
|
||||
if (menuItem.dataset.menuanchor === to.dataset.anchor) {
|
||||
menuItem.classList.add('active')
|
||||
} else {
|
||||
menuItem.classList.remove('active')
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
fpIsScrolling = false
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function onFullpageScrollEnd() {
|
||||
fpIsScrolling = false
|
||||
}
|
||||
|
||||
function fullpageOnScrollableElementEnter() {
|
||||
fpMouseInScrollableElement = true
|
||||
}
|
||||
function fullpageOnScrollableElementLeave() {
|
||||
fpMouseInScrollableElement = false
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function onLeave(origin, destination, direction, trigger) {
|
||||
if (destination.anchor === 'welcome-section') {
|
||||
function onLeave(origin, destination) {
|
||||
if (destination === 'welcome-section') {
|
||||
menu.value.classList.add('opacity-0')
|
||||
menu.value.classList.remove('scrollable-element')
|
||||
} else {
|
||||
|
|
@ -82,7 +180,7 @@ function onLeave(origin, destination, direction, trigger) {
|
|||
// Disgusting way to make the menu automatically scroll when changing slide.
|
||||
// For some reason this doesn't work on Chrome, I love web dev
|
||||
for (const menuItem of menuItems.value) {
|
||||
if (menuItem.dataset.menuanchor === destination.anchor) {
|
||||
if (menuItem.dataset.menuanchor === destination) {
|
||||
menuItem.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
inline: 'center'
|
||||
|
|
@ -97,12 +195,15 @@ function onLeave(origin, destination, direction, trigger) {
|
|||
<template>
|
||||
<div
|
||||
id="menu-grid"
|
||||
class="fixed z-50 h-full w-full grid grid-cols-5 grid-rows-3 place-items-stretch pointer-events-none"
|
||||
class="fixed z-50 h-dvh w-full grid grid-cols-5 grid-rows-3 place-items-stretch pointer-events-none"
|
||||
>
|
||||
<ul
|
||||
id="menu"
|
||||
class="col-start-1 col-span-full row-start-1 max-h-52 h-fit mt-28 sm:mt-16 lg:m-0 lg:col-start-5 lg:col-span-1 lg:row-start-3 lg:row-span-1 pointer-events-auto overflow-y-scroll transition-opacity duration-1000 opacity-0"
|
||||
class="col-start-1 col-span-full row-start-1 max-h-32 lg:max-h-52 h-fit mt-28 sm:mt-16 lg:m-0 lg:col-start-5 lg:col-span-1 lg:row-start-3 lg:row-span-1 pointer-events-auto overflow-y-scroll overscroll-y-contain transition-opacity duration-1000 opacity-0"
|
||||
ref="menu"
|
||||
@mouseenter="fullpageOnScrollableElementEnter"
|
||||
@touchstart="fullpageOnScrollableElementEnter"
|
||||
@mouseleave="fullpageOnScrollableElementLeave"
|
||||
>
|
||||
<li
|
||||
:data-menuanchor="'post-' + post.id"
|
||||
|
|
@ -119,18 +220,25 @@ function onLeave(origin, destination, direction, trigger) {
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<full-page
|
||||
id="fullpage"
|
||||
<div
|
||||
class="fixed w-screen h-dvh overflow-y-scroll overscroll-y-contain"
|
||||
ref="fullpage"
|
||||
:options="fullpageOptions"
|
||||
@on-leave="onLeave"
|
||||
:skip-init="true"
|
||||
:key="fullpageKey"
|
||||
v-if="fullpageEnable"
|
||||
@wheel="onFullpageWheel"
|
||||
@touchstart="onFullpageTouchStart"
|
||||
@touchend="onFullpageTouchEnd"
|
||||
@scrollend="onFullpageScrollEnd"
|
||||
@touchmove="onFullpageTouchMove"
|
||||
>
|
||||
<WelcomeComponent />
|
||||
<PostComponent class="section" v-for="post in postsStore.posts" :key="post.id" :post="post" />
|
||||
</full-page>
|
||||
<WelcomeComponent class="w-screen h-dvh" />
|
||||
<PostComponent
|
||||
v-for="post in postsStore.posts"
|
||||
:key="post.id"
|
||||
:post="post"
|
||||
@scrollableelemententer="fullpageOnScrollableElementEnter"
|
||||
@scrollableelementleave="fullpageOnScrollableElementLeave"
|
||||
ref="postComponents"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue