fix: header scroll and click

This commit is contained in:
YunYouJun 2023-09-08 02:04:58 +08:00
parent a610c373a1
commit 538445aee2
24 changed files with 259 additions and 149 deletions

View File

@ -1,5 +1,6 @@
---
title: 长目录测试
categories: Test
---
::: zh-CN

View File

@ -3,7 +3,7 @@ import type { ThemeConfig } from 'valaxy-theme-yun'
import { addonAlgolia } from 'valaxy-addon-algolia'
import { addonTwikoo } from 'valaxy-addon-twikoo'
// import { addonTwikoo } from 'valaxy-addon-twikoo'
import { addonWaline } from 'valaxy-addon-waline'
import { addonComponents } from 'valaxy-addon-components'
@ -108,8 +108,8 @@ export default defineValaxyConfig<ThemeConfig>({
comment: true,
}),
addonLightGallery(),
addonTwikoo({
envId: 'https://twikoo.vercel.app',
}),
// addonTwikoo({
// envId: 'https://twikoo.vercel.app',
// }),
],
})

View File

@ -3,3 +3,20 @@
Docs for valaxy.
Use theme [valaxy-theme-press](./packages/valaxy-theme-press).
## Dev
```bash
# build valaxy
pnpm run build
# start docs server
pnpm run docs
```
Migrate to VitePress.
```bash
# start vitepress docs
pnpm run docs:dev
```

View File

@ -1,46 +0,0 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const props = defineProps<{
startTime: string
}>()
const { t } = useI18n()
const passDay = ref(0)
const passHour = ref(0)
const passMinute = ref(0)
const passSecond = ref(0)
/**
* get live time
*/
function siteLiveTime() {
const start = new Date(props.startTime)
const now = new Date()
const timeDiff = (now.getTime() - start.getTime())
const msPerMinute = 60 * 1000
const msPerHour = 60 * msPerMinute
const msPerDay = 24 * msPerHour
passDay.value = Math.floor(timeDiff / msPerDay)
passHour.value = Math.floor((timeDiff % msPerDay) / 60 / 60 / 1000)
passMinute.value = Math.floor((timeDiff % msPerHour) / 60 / 1000)
passSecond.value = Math.floor((timeDiff % msPerMinute) / 1000)
}
onMounted(() => {
setInterval(siteLiveTime, 1000)
})
</script>
<template>
<div class="vc-site-live-time">
<slot name="live-time-before" />
<span mx-1>{{ t('time.day', passDay) }}</span>
<span mx-1>{{ t('time.hour', passHour) }}</span>
<span mx-1>{{ t('time.minute', passMinute) }}</span>
<span mx-1>{{ t('time.second', passSecond) }}</span>
<slot name="live-time-after" />
</div>
</template>

View File

@ -1,8 +1,10 @@
<script lang="ts" setup>
import { computed, nextTick } from 'vue'
import type { PageData, Post } from 'valaxy'
import { usePostTitle, useSiteConfig } from 'valaxy'
import { onContentUpdated, usePostTitle, useSiteConfig } from 'valaxy'
import type { StyleValue } from 'vue'
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { scrollTo } from '../utils'
import { usePostProperty } from '../composables'
const props = defineProps<{
@ -16,6 +18,59 @@ const { styles, icon, color } = usePostProperty(props.frontmatter.type)
const title = usePostTitle(computed(() => props.frontmatter))
const aside = computed(() => props.frontmatter.aside !== false)
const route = useRoute()
const router = useRouter()
nextTick(() => {
if (route.hash) {
setTimeout(() => {
scrollTo(document.body, route.hash, true)
}, 0)
}
})
onContentUpdated(() => {
// to extract
// click title scroll
window.addEventListener(
'click',
async (e) => {
const link = (e.target as Element).closest('a')
if (link) {
const { protocol, hostname, pathname, hash, target } = link
const currentUrl = window.location
const extMatch = pathname.match(/\.\w+$/)
// only intercept inbound links
if (
!e.ctrlKey
&& !e.shiftKey
&& !e.altKey
&& !e.metaKey
&& target !== '_blank'
&& protocol === currentUrl.protocol
&& hostname === currentUrl.hostname
&& !(extMatch && extMatch[0] !== '.html')
) {
if (pathname === currentUrl.pathname) {
e.preventDefault()
// scroll between hash anchors in the same page
if (hash && hash !== currentUrl.hash) {
await router.push({ hash })
history.replaceState({ ...history.state }, '')
// still emit the event so we can listen to it in themes
window.dispatchEvent(new Event('hashchange'))
// use smooth scroll when clicking on header anchor links
scrollTo(link, hash, link.classList.contains('header-anchor'))
}
}
}
}
},
{ capture: true },
)
})
</script>
<template>
@ -36,14 +91,14 @@ const aside = computed(() => props.frontmatter.aside !== false)
<div p="x-4 b-8" class="sm:px-6 lg:px-12 xl:px-16" w="full">
<slot name="main-content">
<Transition appear>
<ValaxyMd :frontmatter="frontmatter">
<YunMdTimeWarning :frontmatter="frontmatter" />
<!-- <Transition appear> -->
<ValaxyMd :frontmatter="frontmatter">
<YunMdTimeWarning :frontmatter="frontmatter" />
<slot name="main-content-md" />
<slot />
</ValaxyMd>
</Transition>
<slot name="main-content-md" />
<slot />
</ValaxyMd>
<!-- </Transition> -->
</slot>
<slot name="main-content-after" />

View File

@ -1,5 +1,5 @@
import { defineAppSetup } from 'valaxy'
export default defineAppSetup((_ctx) => {
// can do for setup
})

View File

@ -9,3 +9,35 @@ export function onImgError(e: Event, defaultImg = anonymousImage) {
targetEl.setAttribute('data-src', targetEl.src)
targetEl.src = defaultImg
}
export function scrollTo(el: HTMLElement, hash: string, smooth = false) {
let target: Element | null = null
try {
target = el.classList.contains('header-anchor')
? el
: ((decodeURIComponent(hash) && document.querySelector(decodeURIComponent(hash))) || null)
}
catch (e) {
console.warn(e)
}
if (target) {
const targetPadding = -64
const targetTop
= window.scrollY
+ (target as HTMLElement).getBoundingClientRect().top
+ targetPadding
// only smooth scroll if distance is smaller than screen height.
if (!smooth || Math.abs(targetTop - window.scrollY) > window.innerHeight) {
window.scrollTo(0, targetTop)
}
else {
window.scrollTo({
// left: 0,
top: targetTop,
behavior: 'smooth',
})
}
}
}

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onBeforeMount, provide, ref } from 'vue'
import { computed, onBeforeMount } from 'vue'
import { useHead, useSeoMeta } from '@vueuse/head'
// @ts-expect-error virtual module
@ -72,9 +72,6 @@ useSeoMeta({
ogUrl: siteUrl,
})
const onContentUpdated = ref()
provide('onContentUpdated', onContentUpdated)
// for SEO
useSchemaOrg([
// https://unhead-schema-org.harlanzw.com//guide/guides/identity.html

View File

@ -1,7 +1,6 @@
<script lang="ts" setup>
import { useDecrypt, useFrontmatter } from 'valaxy'
import type { Ref } from 'vue'
import { defineComponent, h, inject, onMounted, ref } from 'vue'
import { runContentUpdated, useDecrypt, useFrontmatter } from 'valaxy'
import { defineComponent, h, onMounted, ref } from 'vue'
const props = defineProps<{
encryptedContent: string
@ -12,8 +11,6 @@ const decryptedContent = ref('')
const hasError = ref(false)
const onContentUpdated = inject('onContentUpdated') as Ref<() => void>
const { decrypt } = useDecrypt()
async function decryptContent() {
const ciphertext = props.encryptedContent
@ -24,7 +21,7 @@ async function decryptContent() {
decryptedContent.value = result || ''
setTimeout(() => {
onContentUpdated.value?.()
runContentUpdated()
}, 16)
}
catch (e) {
@ -37,7 +34,7 @@ function encryptAgain() {
password.value = ''
setTimeout(() => {
onContentUpdated.value?.()
runContentUpdated()
}, 16)
}

View File

@ -1,8 +1,7 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import { inject, onMounted, ref } from 'vue'
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAplayer, useCodePen, useCopyCode, useMediumZoom, wrapTable } from 'valaxy'
import { onContentUpdated, runContentUpdated, useAplayer, useCodePen, useCopyCode, useMediumZoom, wrapTable } from 'valaxy'
import type { Post } from 'valaxy'
const props = defineProps<{
@ -10,18 +9,15 @@ const props = defineProps<{
excerpt?: string
}>()
const onContentUpdated = inject('onContentUpdated') as Ref<() => void>
const { t } = useI18n()
const contentRef = ref()
function updateDom() {
onContentUpdated(() => {
wrapTable(contentRef.value)
onContentUpdated.value?.()
}
})
onMounted(() => {
updateDom()
runContentUpdated()
})
// widgets

View File

@ -0,0 +1,13 @@
import { ref } from 'vue'
export function useAside() {
// const { hasSidebar } = useSidebar()
// const is960 = useMediaQuery('(min-width: 960px)')
// const is1280 = useMediaQuery('(min-width: 1280px)')
const isAsideEnabled = ref(true)
return {
isAsideEnabled,
}
}

View File

@ -1,6 +1,7 @@
import type { Ref } from 'vue'
import { onMounted, onUnmounted, onUpdated } from 'vue'
import { throttleAndDebounce } from '../../utils'
import { useAside } from '../aside'
// magic number to avoid repeated retrieval
const PAGE_OFFSET = 56
@ -10,6 +11,7 @@ export function useActiveAnchor(
container: Ref<HTMLElement>,
marker: Ref<HTMLElement>,
) {
const { isAsideEnabled } = useAside()
const onScroll = throttleAndDebounce(setActiveLink, 100)
let prevActiveLink: HTMLAnchorElement | null = null
@ -29,7 +31,7 @@ export function useActiveAnchor(
})
function setActiveLink() {
if (!container.value)
if (!isAsideEnabled.value)
return
const links = [].slice.call(
@ -60,8 +62,8 @@ export function useActiveAnchor(
}
// isTop
if (anchors.length && scrollY === 0)
activateLink('#')
// if (anchors.length && scrollY === 0)
// activateLink('#')
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i]
@ -87,21 +89,23 @@ export function useActiveAnchor(
const bottom = activeLink.getBoundingClientRect().bottom
if (top < topOffset || bottom > window.innerHeight - topOffset)
activeLink.scrollIntoView({ behavior: 'smooth', block: 'center' })
activeLink.scrollIntoView()
}
function activateLink(hash: string | null) {
if (prevActiveLink)
prevActiveLink.classList.remove('active')
if (hash !== null) {
if (hash == null) {
prevActiveLink = null
}
else {
prevActiveLink = container.value.querySelector(
`a[href="${decodeURIComponent(hash)}"]`,
) as HTMLAnchorElement
)
}
const activeLink = prevActiveLink
checkActiveLinkInViewport()
if (activeLink) {

View File

@ -1,6 +1,6 @@
import type { Ref } from 'vue'
import { computed, inject, ref } from 'vue'
import type { DefaultThemeConfig, Header } from 'valaxy/types'
import { computed, shallowRef } from 'vue'
import type { DefaultTheme, Header } from 'valaxy/types'
import { onContentUpdated } from '../../utils'
import { useFrontmatter, useThemeConfig } from '../..'
export type MenuItem = Omit<Header, 'slug' | 'children'> & {
@ -9,7 +9,7 @@ export type MenuItem = Omit<Header, 'slug' | 'children'> & {
export function resolveHeaders(
headers: MenuItem[],
levelsRange: Exclude<DefaultThemeConfig['outline'], false> = [2, 4],
levelsRange: Exclude<DefaultTheme.Config['outline'], false> = [2, 4],
) {
const levels: [number, number]
= typeof levelsRange === 'number'
@ -69,22 +69,25 @@ function addToParent(
export function useOutline() {
const frontmatter = useFrontmatter()
const themeConfig = useThemeConfig()
const headers = ref<MenuItem[]>([])
const pageOutline = computed<DefaultThemeConfig['outline']>(
const headers = shallowRef<MenuItem[]>([])
const pageOutline = computed<DefaultTheme.Config['outline']>(
() => frontmatter.value.outline ?? themeConfig.value.outline,
)
const onContentUpdated = inject('onContentUpdated') as Ref<() => void>
onContentUpdated.value = () => {
onContentUpdated(() => {
if (pageOutline.value === false)
return
headers.value = getHeaders(pageOutline.value)
}
})
const handleClick = ({ target: el }: Event) => {
const id = `#${(el as HTMLAnchorElement).href!.split('#')[1]}`
const heading = document.querySelector(
const id = (el as HTMLAnchorElement).href!.split('#')[1]
const heading = document.getElementById(
decodeURIComponent(id),
) as HTMLAnchorElement
heading?.focus()
heading?.focus({
preventScroll: true,
})
}
return {
@ -101,24 +104,40 @@ export function useOutline() {
/**
* get headers from document directly
* @param pageOutline
* @returns
*/
export function getHeaders(pageOutline: DefaultThemeConfig['outline']) {
if (pageOutline === false)
return []
const updatedHeaders: MenuItem[] = []
document
.querySelectorAll<HTMLHeadingElement>('h2, h3, h4, h5, h6')
.forEach((el) => {
if (el.textContent && el.id) {
updatedHeaders.push({
level: Number(el.tagName[1]),
title: el.innerText.replace(/\s+#\s*$/, ''),
link: `#${el.id}`,
lang: el.lang,
})
export function getHeaders(range: Exclude<DefaultTheme.Config['outline'], false>) {
const headers = Array.from(document.querySelectorAll('.markdown-body :where(h1,h2,h3,h4,h5,h6)'))
.filter(el => el.id && el.hasChildNodes())
.map((el) => {
const level = Number(el.tagName[1])
return {
title: serializeHeader(el),
link: `#${el.id}`,
level,
// @ts-expect-error lang
lang: el.lang,
}
})
return resolveHeaders(updatedHeaders, pageOutline)
return resolveHeaders(headers, range)
}
function serializeHeader(h: Element): string {
let ret = ''
for (const node of Array.from(h.childNodes)) {
if (node.nodeType === 1) {
if (
(node as Element).classList.contains('VABadge')
|| (node as Element).classList.contains('header-anchor')
)
continue
ret += node.textContent
}
else if (node.nodeType === 3) {
ret += node.textContent
}
}
return ret.trim()
}

View File

@ -10,7 +10,7 @@ import { computed, inject, readonly, shallowRef } from 'vue'
// fix build caused by pnpm
// This is likely not portable. A type annotation is necessary.
// https://github.com/microsoft/TypeScript/issues/42873
import type { DefaultThemeConfig, ValaxyConfig } from 'valaxy/types'
import type { DefaultTheme, ValaxyConfig } from 'valaxy/types'
/**
* parse valaxy config
@ -57,7 +57,7 @@ export function initContext() {
* @public
* @returns
*/
export function useValaxyConfig<ThemeConfig = DefaultThemeConfig>() {
export function useValaxyConfig<ThemeConfig = DefaultTheme.Config>() {
const config = inject<ComputedRef<ValaxyConfig<ThemeConfig>>>(valaxyConfigSymbol)
if (!config)
throw new Error('[Valaxy] site config not properly injected in app')
@ -69,7 +69,7 @@ export function useValaxyConfig<ThemeConfig = DefaultThemeConfig>() {
* @public
* @returns
*/
export function useConfig<ThemeConfig = DefaultThemeConfig>() {
export function useConfig<ThemeConfig = DefaultTheme.Config>() {
return useValaxyConfig<ThemeConfig>()
}
@ -78,7 +78,7 @@ export function useConfig<ThemeConfig = DefaultThemeConfig>() {
* @public
* @returns
*/
export function useSiteConfig<ThemeConfig = DefaultThemeConfig>() {
export function useSiteConfig<ThemeConfig = DefaultTheme.Config>() {
const config = useValaxyConfig<ThemeConfig>()
return computed(() => config!.value.siteConfig)
}
@ -90,7 +90,7 @@ export function useSiteConfig<ThemeConfig = DefaultThemeConfig>() {
* @internal
* @returns
*/
export function useThemeConfig<ThemeConfig = DefaultThemeConfig>() {
export function useThemeConfig<ThemeConfig = DefaultTheme.Config>() {
const config = useValaxyConfig<ThemeConfig>()
return computed(() => config!.value.themeConfig)
}

View File

@ -0,0 +1,18 @@
import { onUnmounted } from 'vue'
// eslint-disable-next-line import/no-mutable-exports
export let contentUpdatedCallbacks: (() => any)[] = []
/**
* Register callback that is called every time the markdown content is updated
* in the DOM.
*/
export function onContentUpdated(fn: () => any) {
contentUpdatedCallbacks.push(fn)
onUnmounted(() => {
contentUpdatedCallbacks = contentUpdatedCallbacks.filter(f => f !== fn)
})
}
export const runCbs = () => contentUpdatedCallbacks.forEach(fn => fn())
export const runContentUpdated = runCbs

View File

@ -3,3 +3,4 @@ export * from './helper'
export * from './time'
export * from './wrap'
export * from './types'
export * from './content'

View File

@ -1,4 +1,4 @@
import type { DefaultThemeConfig, ValaxyAddon } from '../../types'
import type { DefaultTheme, ValaxyAddon } from '../../types'
import type { ResolvedValaxyOptions } from '../options'
import type { ValaxyNodeConfig } from '../types'
@ -11,8 +11,8 @@ export const defineAddon = defineValaxyAddon
export type ValaxyConfigExtendKey = 'vite' | 'vue' | 'unocss' | 'unocssPresets' | 'markdown' | 'extendMd' | 'addons'
export type ValaxyPickConfig = Pick<ValaxyNodeConfig, ValaxyConfigExtendKey>
export type ValaxyTheme<ThemeConfig = DefaultThemeConfig> = ValaxyPickConfig & { themeConfig?: ThemeConfig }
export function defineValaxyTheme<ThemeConfig = DefaultThemeConfig>(
export type ValaxyTheme<ThemeConfig = DefaultTheme.Config> = ValaxyPickConfig & { themeConfig?: ThemeConfig }
export function defineValaxyTheme<ThemeConfig = DefaultTheme.Config>(
theme: ValaxyTheme<ThemeConfig> | ((options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyTheme<ThemeConfig>),
) {
return theme

View File

@ -6,7 +6,7 @@ import fg from 'fast-glob'
import { ensureSuffix, uniq } from '@antfu/utils'
import defu from 'defu'
import { cyan, yellow } from 'kolorist'
import type { DefaultThemeConfig, RuntimeConfig } from '../types'
import type { DefaultTheme, RuntimeConfig } from '../types'
import { logger } from './logger'
import { resolveImportPath, slash } from './utils'
import { mergeValaxyConfig, resolveAddonConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot } from './utils/config'
@ -26,7 +26,7 @@ export interface ValaxyEntryOptions {
userRoot: string
}
export interface ResolvedValaxyOptions<ThemeConfig = DefaultThemeConfig> {
export interface ResolvedValaxyOptions<ThemeConfig = DefaultTheme.Config> {
mode: 'dev' | 'build'
/**
* package.json root

View File

@ -4,17 +4,17 @@ import type { VitePluginConfig as UnoCSSConfig } from 'unocss/vite'
import type Pages from 'vite-plugin-pages'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { presetAttributify, presetIcons, presetTypography, presetUno } from 'unocss'
import type { DefaultThemeConfig, PartialDeep, ValaxyAddon, ValaxyConfig } from '../types'
import type { DefaultTheme, PartialDeep, ValaxyAddon, ValaxyConfig } from '../types'
import type { ResolvedValaxyOptions } from './options'
import type { MarkdownOptions } from './markdown/types'
export type ValaxyNodeConfig<ThemeConfig = DefaultThemeConfig> = ValaxyConfig<ThemeConfig> & ValaxyExtendConfig
export type UserValaxyNodeConfig<ThemeConfig = DefaultThemeConfig> = PartialDeep<ValaxyNodeConfig<ThemeConfig>>
export type ValaxyNodeConfig<ThemeConfig = DefaultTheme.Config> = ValaxyConfig<ThemeConfig> & ValaxyExtendConfig
export type UserValaxyNodeConfig<ThemeConfig = DefaultTheme.Config> = PartialDeep<ValaxyNodeConfig<ThemeConfig>>
/**
* fn with options for theme config
*/
export type ValaxyConfigFn<ThemeConfig = DefaultThemeConfig> = (options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyConfigExport<ThemeConfig = DefaultThemeConfig> = ValaxyNodeConfig<ThemeConfig> | ValaxyConfigFn<ThemeConfig>
export type ValaxyConfigFn<ThemeConfig = DefaultTheme.Config> = (options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyConfigExport<ThemeConfig = DefaultTheme.Config> = ValaxyNodeConfig<ThemeConfig> | ValaxyConfigFn<ThemeConfig>
export interface ValaxyExtendConfig {
/**
@ -62,8 +62,8 @@ export interface ValaxyExtendConfig {
export type ValaxyAddonLike = ValaxyAddon | false | null | undefined
export type ValaxyAddons = (ValaxyAddon | string)[] | Record<string, ValaxyAddonLike>
export type ValaxyAddonFn<ThemeConfig = DefaultThemeConfig> = (addonOptions: ValaxyAddonResolver, valaxyOptions: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyAddonExport<ThemeConfig = DefaultThemeConfig> = ValaxyNodeConfig<ThemeConfig> | ValaxyAddonFn<ThemeConfig>
export type ValaxyAddonFn<ThemeConfig = DefaultTheme.Config> = (addonOptions: ValaxyAddonResolver, valaxyOptions: ResolvedValaxyOptions<ThemeConfig>) => ValaxyNodeConfig | Promise<ValaxyNodeConfig>
export type ValaxyAddonExport<ThemeConfig = DefaultTheme.Config> = ValaxyNodeConfig<ThemeConfig> | ValaxyAddonFn<ThemeConfig>
export interface ValaxyAddonResolver {
name: string

View File

@ -84,7 +84,7 @@
"gray-matter": "^4.0.3",
"html-to-text": "^9.0.5",
"is-installed-globally": "^0.4.0",
"jiti": "^1.19.3",
"jiti": "^1.20.0",
"katex": "^0.16.8",
"kolorist": "^1.8.0",
"lru-cache": "^10.0.1",

View File

@ -2,15 +2,7 @@ import type { ZoomOptions } from 'medium-zoom'
import type { FuseOptions } from '@vueuse/integrations/useFuse'
import type { ValaxyAddon } from '../types'
import type { FuseListItem } from './node'
export type DefaultThemeConfig = {
/**
* Custom header levels of outline in the aside component.
*
* @default 2
*/
outline?: number | [number, number] | 'deep' | false
} & Record<string, any>
import type { DefaultTheme } from './default-theme'
export interface SocialLink {
/**
@ -301,7 +293,7 @@ export interface RuntimeConfig {
addons: Record<string, ValaxyAddon>
}
export interface ValaxyConfig<ThemeConfig = DefaultThemeConfig> {
export interface ValaxyConfig<ThemeConfig = DefaultTheme.Config> {
siteConfig: SiteConfig
/**
* The name of theme
@ -343,4 +335,4 @@ export type UserSiteConfig = PartialDeep<SiteConfig>
* Valaxy User Config
* @description Valaxy
*/
export type UserValaxyConfig<ThemeConfig = DefaultThemeConfig> = PartialDeep<ValaxyConfig<ThemeConfig>>
export type UserValaxyConfig<ThemeConfig = DefaultTheme.Config> = PartialDeep<ValaxyConfig<ThemeConfig>>

View File

@ -0,0 +1,11 @@
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace DefaultTheme {
export interface Config {
/**
* Custom header levels of outline in the aside component.
*
* @default 2
*/
outline?: number | [number, number] | 'deep' | false
}
}

View File

@ -6,3 +6,6 @@ export * from './posts'
// used in node, but without node deps
export * from './node'
// theme
export * from './default-theme'

View File

@ -275,8 +275,8 @@ importers:
specifier: ^0.4.0
version: 0.4.0
jiti:
specifier: ^1.19.3
version: 1.19.3
specifier: ^1.20.0
version: 1.20.0
katex:
specifier: ^0.16.8
version: 0.16.8
@ -6547,8 +6547,8 @@ packages:
supports-color: 7.2.0
dev: true
/jiti@1.19.3:
resolution: {integrity: sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==}
/jiti@1.20.0:
resolution: {integrity: sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==}
hasBin: true
dev: false
@ -8956,7 +8956,7 @@ packages:
dependencies:
'@antfu/utils': 0.7.6
defu: 6.1.2
jiti: 1.19.3
jiti: 1.20.0
mlly: 1.4.0
dev: false