feat: add again inert content on narrow for narrow screens

userquin/feat-add-inert-content-again
userquin 2 years ago
parent d1ff29431f
commit 0ae4ef0a2f

@ -17,6 +17,7 @@ import { usePrefetch } from './composables/preFetch'
import { dataSymbol, initData, siteDataRef, useData } from './data'
import { RouterSymbol, createRouter, scrollTo, type Router } from './router'
import { inBrowser, pathToFile } from './utils'
import { provideInert } from './inert'
function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme {
if (theme.extends) {
@ -73,6 +74,8 @@ export async function createApp() {
const data = initData(router.route)
app.provide(dataSymbol, data)
provideInert(app)
// install global components
app.component('Content', Content)
app.component('ClientOnly', ClientOnly)

@ -0,0 +1,60 @@
import {
type App,
computed,
inject,
reactive,
type UnwrapNestedRefs
} from 'vue'
const inertSymbol = Symbol()
const inertStateSymbol = Symbol()
export interface Inert {
isSidebarOpen: boolean
isScreenOpen: boolean
isSidebarEnabled: boolean
onAfterRouteChanged: () => void
}
export interface InertState {
inertSkipLink: boolean
inertNav: boolean
inertLocalNav: boolean
inertSidebar: boolean
inertContent: boolean
inertFooter: boolean
}
export function useInert() {
return inject<UnwrapNestedRefs<Inert>>(inertSymbol)
}
export function useInertState() {
return inject<UnwrapNestedRefs<InertState>>(inertStateSymbol)
}
export function provideInert(app: App) {
const inert = reactive({
isSidebarOpen: false,
isScreenOpen: false,
isSidebarEnabled: false,
onAfterRouteChanged() {
inert.isSidebarOpen = false
inert.isScreenOpen = false
}
})
const inertState = reactive({
inertSkipLink: computed(() => inert.isSidebarOpen || inert.isScreenOpen),
inertNav: computed(() => inert.isSidebarOpen),
inertLocalNav: computed(() => inert.isSidebarOpen || inert.isScreenOpen),
inertSidebar: computed(
() =>
!inert.isSidebarEnabled && (!inert.isSidebarOpen || inert.isScreenOpen)
),
inertContent: computed(() => inert.isSidebarOpen || inert.isScreenOpen),
inertFooter: computed(() => inert.isSidebarOpen || inert.isScreenOpen)
})
app.provide(inertSymbol, inert)
app.provide(inertStateSymbol, inertState)
}

@ -3,6 +3,7 @@
// generic types
export type { VitePressData } from './app/data'
export type { Inert, InertState } from './app/inert'
export type { Route, Router } from './app/router'
// theme types
@ -13,6 +14,7 @@ export type { HeadConfig, Header, PageData, SiteData } from '../../types/shared'
// composables
export { useData, dataSymbol } from './app/data'
export { useInert, useInertState } from './app/inert'
export { useRoute, useRouter } from './app/router'
// utilities

@ -1,5 +1,5 @@
<script setup lang="ts">
import { useRoute } from 'vitepress'
import { useInertState, useRoute } from 'vitepress'
import { computed, provide, useSlots, watch } from 'vue'
import VPBackdrop from './components/VPBackdrop.vue'
import VPContent from './components/VPContent.vue'
@ -17,6 +17,7 @@ const {
close: closeSidebar
} = useSidebar()
const inert = useInertState()
const route = useRoute()
watch(() => route.path, closeSidebar)
@ -33,9 +34,9 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template>
<div v-if="frontmatter.layout !== false" class="Layout" :class="frontmatter.pageClass" >
<slot name="layout-top" />
<VPSkipLink />
<VPSkipLink :inert="inert?.inertSkipLink" />
<VPBackdrop class="backdrop" :show="isSidebarOpen" @click="closeSidebar" />
<VPNav>
<VPNav :inert="inert?.inertNav">
<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>
@ -43,14 +44,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 :open="isSidebarOpen" @open-menu="openSidebar" />
<VPLocalNav :inert="inert?.inertLocalNav" :open="isSidebarOpen" @open-menu="openSidebar" />
<VPSidebar :open="isSidebarOpen">
<VPSidebar :inert="inert?.inertSidebar" :open="isSidebarOpen">
<template #sidebar-nav-before><slot name="sidebar-nav-before" /></template>
<template #sidebar-nav-after><slot name="sidebar-nav-after" /></template>
</VPSidebar>
<VPContent>
<VPContent :inert="inert?.inertContent">
<template #page-top><slot name="page-top" /></template>
<template #page-bottom><slot name="page-bottom" /></template>
@ -76,7 +77,7 @@ provide('hero-image-slot-exists', heroImageSlotExists)
<template #aside-ads-after><slot name="aside-ads-after" /></template>
</VPContent>
<VPFooter />
<VPFooter :inert="inert?.inertFooter" />
<slot name="layout-bottom" />
</div>
<Content v-else />

@ -1,37 +1,50 @@
<script setup lang="ts">
import { onClickOutside, onKeyStroke } from '@vueuse/core'
import { onKeyStroke } from '@vueuse/core'
import { onContentUpdated } from 'vitepress'
import { nextTick, ref } from 'vue'
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[]
navHeight: number
}>()
const { theme } = useData()
const open = ref(false)
const vh = ref(0)
const main = ref<HTMLDivElement>()
const items = ref<HTMLDivElement>()
onClickOutside(main, () => {
open.value = false
const open = ref(false)
const { theme } = useData()
const { activate, deactivate } = useFocusTrap(items, {
immediate: true,
allowOutsideClick: true,
clickOutsideDeactivates: true,
escapeDeactivates: true,
delayInitialFocus: false,
onDeactivate: () => {
open.value = false
},
})
const vh = ref(0)
onKeyStroke('Escape', () => {
open.value = false
deactivate()
})
onContentUpdated(() => {
open.value = false
})
onContentUpdated(deactivate)
function toggle() {
open.value = !open.value
if (open.value) {
deactivate()
} else {
open.value = true
nextTick(() => activate())
}
vh.value = window.innerHeight + Math.min(window.scrollY - props.navHeight, 0)
}
@ -41,14 +54,12 @@ function onItemClick(e: Event) {
if (items.value) {
items.value.style.transition = 'none'
}
nextTick(() => {
open.value = false
})
nextTick(() => deactivate())
}
}
function scrollToTop() {
open.value = false
deactivate()
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
}
</script>
@ -155,11 +166,12 @@ function scrollToTop() {
.header {
background-color: var(--vp-c-bg-soft);
padding: 2px 16px;
}
.top-link {
display: block;
padding: 0 16px;
padding: 0;
line-height: 48px;
font-size: 14px;
font-weight: 500;

@ -27,14 +27,16 @@ function focusOnTargetAnchor({ target }: Event) {
</script>
<template>
<span ref="backToTop" tabindex="-1" />
<a
href="#VPContent"
class="VPSkipLink visually-hidden"
@click="focusOnTargetAnchor"
>
Skip to content
</a>
<div>
<span ref="backToTop" tabindex="-1" />
<a
href="#VPContent"
class="VPSkipLink visually-hidden"
@click="focusOnTargetAnchor"
>
Skip to content
</a>
</div>
</template>
<style scoped>

@ -1,16 +1,17 @@
import { ref, watch } from 'vue'
import { useRoute } from 'vitepress'
import { computed, watch } from 'vue'
import { useInert, useRoute } from 'vitepress'
export function useNav() {
const isScreenOpen = ref(false)
const inert = useInert()!
const isScreenOpen = computed(() => inert.isScreenOpen)
function openScreen() {
isScreenOpen.value = true
inert.isScreenOpen = true
window.addEventListener('resize', closeScreenOnTabletWindow)
}
function closeScreen() {
isScreenOpen.value = false
inert.isScreenOpen = false
window.removeEventListener('resize', closeScreenOnTabletWindow)
}
@ -19,7 +20,7 @@ export function useNav() {
}
/**
* Close screen when the user resizes the window wider than tablet size.
* Close the screen when the user resizes the window wider than tablet size.
*/
function closeScreenOnTabletWindow() {
window.outerWidth >= 768 && closeScreen()

@ -18,6 +18,7 @@ import {
getSidebarGroups
} from '../support/sidebar'
import { useData } from './data'
import { useInert } from 'vitepress'
export interface SidebarControl {
collapsed: Ref<boolean>
@ -33,7 +34,8 @@ export function useSidebar() {
const { frontmatter, page, theme } = useData()
const is960 = useMediaQuery('(min-width: 960px)')
const isOpen = ref(false)
const inert = useInert()!
const isOpen = computed(() => inert.isSidebarOpen)
const _sidebar = computed(() => {
const sidebarConfig = theme.value.sidebar
@ -77,11 +79,11 @@ export function useSidebar() {
})
function open() {
isOpen.value = true
inert.isSidebarOpen = true
}
function close() {
isOpen.value = false
inert.isSidebarOpen = false
}
function toggle() {

@ -157,7 +157,11 @@ export async function createVitePressPlugin(
},
optimizeDeps: {
// force include vue to avoid duplicated copies when linked + optimized
include: ['vue', 'vitepress > @vue/devtools-api'],
include: [
'vue',
'vitepress > @vue/devtools-api',
'vitepress > @vueuse/integrations/useFocusTrap'
],
exclude: ['@docsearch/js', 'vitepress']
},
server: {

@ -168,7 +168,6 @@ export async function localSearchPlugin(
config: () => ({
optimizeDeps: {
include: [
'vitepress > @vueuse/integrations/useFocusTrap',
'vitepress > mark.js/src/vanilla.js',
'vitepress > minisearch'
]

Loading…
Cancel
Save