fix hydration

userquin/feat-add-inert-content-again
Divyansh Singh 2 years ago
parent 2a38b78974
commit b86f82eeac

@ -9,8 +9,8 @@ import VPNav from './components/VPNav.vue'
import VPSidebar from './components/VPSidebar.vue'
import VPSkipLink from './components/VPSkipLink.vue'
import { useData } from './composables/data'
import { useInert } from './composables/inert'
import { useCloseSidebarOnEscape, useSidebar } from './composables/sidebar'
import { inertState } from './composables/inert'
const {
isOpen: isSidebarOpen,
@ -25,6 +25,8 @@ useCloseSidebarOnEscape(isSidebarOpen, closeSidebar)
const { frontmatter } = useData()
const inert = useInert()
const slots = useSlots()
const heroImageSlotExists = computed(() => !!slots['home-hero-image'])
@ -34,9 +36,9 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template>
<div v-if="frontmatter.layout !== false" class="Layout" :class="frontmatter.pageClass" >
<slot name="layout-top" />
<VPSkipLink :inert="inertState.inertSkipLink" />
<VPSkipLink :inert="inert.skipLink" />
<VPBackdrop class="backdrop" :show="isSidebarOpen" @click="closeSidebar" />
<VPNav :inert="inertState.inertNav">
<VPNav :inert="inert.nav">
<template #nav-bar-title-before><slot name="nav-bar-title-before" /></template>
<template #nav-bar-title-after><slot name="nav-bar-title-after" /></template>
<template #nav-bar-content-before><slot name="nav-bar-content-before" /></template>
@ -44,14 +46,14 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template #nav-screen-content-before><slot name="nav-screen-content-before" /></template>
<template #nav-screen-content-after><slot name="nav-screen-content-after" /></template>
</VPNav>
<VPLocalNav :inert="inertState.inertLocalNav" :open="isSidebarOpen" @open-menu="openSidebar" />
<VPLocalNav :inert="inert.localNav" :open="isSidebarOpen" @open-menu="openSidebar" />
<VPSidebar :inert="inertState.inertSidebar" :open="isSidebarOpen">
<VPSidebar :inert="inert.sidebar" :open="isSidebarOpen">
<template #sidebar-nav-before><slot name="sidebar-nav-before" /></template>
<template #sidebar-nav-after><slot name="sidebar-nav-after" /></template>
</VPSidebar>
<VPContent :inert="inertState.inertContent">
<VPContent :inert="inert.content">
<template #page-top><slot name="page-top" /></template>
<template #page-bottom><slot name="page-bottom" /></template>
@ -77,7 +79,7 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template #aside-ads-after><slot name="aside-ads-after" /></template>
</VPContent>
<VPFooter :inert="inertState.inertFooter" />
<VPFooter :inert="inert.footer" />
<slot name="layout-bottom" />
</div>
<Content v-else />

@ -1,6 +1,7 @@
<script setup lang="ts">
import { ref, computed, watchEffect, onMounted } from 'vue'
import { computed } from 'vue'
import { useData } from '../composables/data'
import { clientComputed } from '../support/reactivity'
const { theme, page, frontmatter, lang } = useData()
@ -8,21 +9,13 @@ const date = computed(
() => new Date(frontmatter.value.lastUpdated ?? page.value.lastUpdated)
)
const isoDatetime = computed(() => date.value.toISOString())
const datetime = ref('')
// set time on mounted hook to avoid hydration mismatch due to
// potential differences in timezones of the server and clients
onMounted(() => {
watchEffect(() => {
datetime.value = new Intl.DateTimeFormat(
theme.value.lastUpdated?.formatOptions?.forceLocale ? lang.value : undefined,
theme.value.lastUpdated?.formatOptions ?? {
dateStyle: 'short',
timeStyle: 'short'
}
).format(date.value)
})
})
const datetime = clientComputed(() => {
return new Intl.DateTimeFormat(
theme.value.lastUpdated?.formatOptions?.forceLocale ? lang.value : undefined,
theme.value.lastUpdated?.formatOptions ?? { dateStyle: 'short', timeStyle: 'short' }
).format(date.value)
}, '')
</script>
<template>

@ -1,11 +1,11 @@
<script setup lang="ts">
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
import { onContentUpdated } from 'vitepress'
import { nextTick, ref } from 'vue'
import { useData } from '../composables/data'
import { resolveTitle, type MenuItem } from '../composables/outline'
import VPDocOutlineItem from './VPDocOutlineItem.vue'
import VPIconChevronRight from './icons/VPIconChevronRight.vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
const props = defineProps<{
headers: MenuItem[]

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { useWindowScroll } from '@vueuse/core'
import { ref, watchPostEffect } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { useData } from '../composables/data'
import { useLocalNav } from '../composables/local-nav'
import { useSidebar } from '../composables/sidebar'
@ -25,20 +25,25 @@ const { y } = useWindowScroll()
const { hasSidebar } = useSidebar()
const { hasLocalNav } = useLocalNav()
const { frontmatter } = useData()
const navbar = ref<HTMLElement>()
const classes = ref<Record<string, boolean>>({})
watchPostEffect(() => {
classes.value = {
const classes = computed(() => {
return {
'top': frontmatter.value.layout === 'home' && y.value === 0,
'has-sidebar': hasSidebar.value,
'has-local-nav': hasLocalNav.value,
top: frontmatter.value.layout === 'home' && y.value === 0,
}
})
onMounted(() => {
if (frontmatter.value.layout === 'home' && y.value !== 0) {
navbar.value?.classList.remove('top')
}
})
</script>
<template>
<div class="VPNavBar" :class="classes">
<div class="VPNavBar" :class="classes" ref="navbar">
<div class="wrapper">
<div class="container">
<div class="title">

@ -1,26 +1,19 @@
import { computed, reactive } from 'vue'
import { reactive } from 'vue'
import { clientComputed } from '../support/reactivity'
export const inertControls = reactive({
isSidebarOpen: false,
isScreenOpen: false,
isSidebarOpen: false,
isSidebarVisible: false
})
export const inertState = reactive({
inertSkipLink: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
),
inertNav: computed(() => inertControls.isSidebarOpen),
inertLocalNav: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
),
inertSidebar: computed(
() => !inertControls.isSidebarVisible || inertControls.isScreenOpen
),
inertContent: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
),
inertFooter: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
)
})
export function useInert() {
return clientComputed(() => ({
skipLink: inertControls.isSidebarOpen || inertControls.isScreenOpen,
nav: inertControls.isSidebarOpen,
localNav: inertControls.isSidebarOpen || inertControls.isScreenOpen,
sidebar: !inertControls.isSidebarVisible || inertControls.isScreenOpen,
content: inertControls.isSidebarOpen || inertControls.isScreenOpen,
footer: inertControls.isSidebarOpen || inertControls.isScreenOpen
}))
}

@ -33,7 +33,8 @@ export function useNav() {
} else {
inertControls.isScreenOpen = screenOpen
}
}
},
{ immediate: true }
)
const route = useRoute()

@ -75,13 +75,14 @@ export function useSidebar() {
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)
watch(
() => [hasSidebar.value, is960.value, isOpen.value],
([sb, mq, o]) => {
() => [isSidebarEnabled.value, isOpen.value],
([sidebarEnabled, o]) => {
if (o) {
inertControls.isSidebarVisible = inertControls.isSidebarOpen = true
inertControls.isSidebarOpen = true
inertControls.isSidebarVisible = true
} else {
inertControls.isSidebarOpen = false
inertControls.isSidebarVisible = sb && mq
inertControls.isSidebarVisible = sidebarEnabled
}
},
{ immediate: true }

@ -0,0 +1,24 @@
import {
onMounted,
shallowReadonly,
shallowRef,
toValue,
watchEffect,
type ShallowRef
} from 'vue'
export function clientComputed<T extends {}>(
fn: () => T,
defaultValue: any = {},
options?: { flush?: 'pre' | 'post' | 'sync' }
): Readonly<ShallowRef<T>> {
const data = shallowRef<T>(toValue(defaultValue))
onMounted(() => {
watchEffect(() => {
data.value = toValue(fn)
}, options)
})
return shallowReadonly(data)
}

@ -23,7 +23,6 @@ export { default as VPTeamPageTitle } from './components/VPTeamPageTitle.vue'
export { default as VPTeamPageSection } from './components/VPTeamPageSection.vue'
export { default as VPTeamMembers } from './components/VPTeamMembers.vue'
export { inertControls, inertState } from './composables/inert'
export { useSidebar } from './composables/sidebar'
export { useLocalNav } from './composables/local-nav'

Loading…
Cancel
Save