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

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

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

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useWindowScroll } from '@vueuse/core' import { useWindowScroll } from '@vueuse/core'
import { ref, watchPostEffect } from 'vue' import { computed, onMounted, ref } from 'vue'
import { useData } from '../composables/data' import { useData } from '../composables/data'
import { useLocalNav } from '../composables/local-nav' import { useLocalNav } from '../composables/local-nav'
import { useSidebar } from '../composables/sidebar' import { useSidebar } from '../composables/sidebar'
@ -25,20 +25,25 @@ const { y } = useWindowScroll()
const { hasSidebar } = useSidebar() const { hasSidebar } = useSidebar()
const { hasLocalNav } = useLocalNav() const { hasLocalNav } = useLocalNav()
const { frontmatter } = useData() const { frontmatter } = useData()
const navbar = ref<HTMLElement>()
const classes = ref<Record<string, boolean>>({}) const classes = computed(() => {
return {
watchPostEffect(() => { 'top': frontmatter.value.layout === 'home' && y.value === 0,
classes.value = {
'has-sidebar': hasSidebar.value, 'has-sidebar': hasSidebar.value,
'has-local-nav': hasLocalNav.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> </script>
<template> <template>
<div class="VPNavBar" :class="classes"> <div class="VPNavBar" :class="classes" ref="navbar">
<div class="wrapper"> <div class="wrapper">
<div class="container"> <div class="container">
<div class="title"> <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({ export const inertControls = reactive({
isSidebarOpen: false,
isScreenOpen: false, isScreenOpen: false,
isSidebarOpen: false,
isSidebarVisible: false isSidebarVisible: false
}) })
export const inertState = reactive({ export function useInert() {
inertSkipLink: computed( return clientComputed(() => ({
() => inertControls.isSidebarOpen || inertControls.isScreenOpen skipLink: inertControls.isSidebarOpen || inertControls.isScreenOpen,
), nav: inertControls.isSidebarOpen,
inertNav: computed(() => inertControls.isSidebarOpen), localNav: inertControls.isSidebarOpen || inertControls.isScreenOpen,
inertLocalNav: computed( sidebar: !inertControls.isSidebarVisible || inertControls.isScreenOpen,
() => inertControls.isSidebarOpen || inertControls.isScreenOpen content: inertControls.isSidebarOpen || inertControls.isScreenOpen,
), footer: inertControls.isSidebarOpen || inertControls.isScreenOpen
inertSidebar: computed( }))
() => !inertControls.isSidebarVisible || inertControls.isScreenOpen }
),
inertContent: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
),
inertFooter: computed(
() => inertControls.isSidebarOpen || inertControls.isScreenOpen
)
})

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

@ -75,13 +75,14 @@ export function useSidebar() {
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value) const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)
watch( watch(
() => [hasSidebar.value, is960.value, isOpen.value], () => [isSidebarEnabled.value, isOpen.value],
([sb, mq, o]) => { ([sidebarEnabled, o]) => {
if (o) { if (o) {
inertControls.isSidebarVisible = inertControls.isSidebarOpen = true inertControls.isSidebarOpen = true
inertControls.isSidebarVisible = true
} else { } else {
inertControls.isSidebarOpen = false inertControls.isSidebarOpen = false
inertControls.isSidebarVisible = sb && mq inertControls.isSidebarVisible = sidebarEnabled
} }
}, },
{ immediate: true } { 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 VPTeamPageSection } from './components/VPTeamPageSection.vue'
export { default as VPTeamMembers } from './components/VPTeamMembers.vue' export { default as VPTeamMembers } from './components/VPTeamMembers.vue'
export { inertControls, inertState } from './composables/inert'
export { useSidebar } from './composables/sidebar' export { useSidebar } from './composables/sidebar'
export { useLocalNav } from './composables/local-nav' export { useLocalNav } from './composables/local-nav'

Loading…
Cancel
Save