mirror of https://github.com/YunYouJun/valaxy
fix: header scroll and click
This commit is contained in:
parent
a610c373a1
commit
538445aee2
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
title: 长目录测试
|
||||
categories: Test
|
||||
---
|
||||
|
||||
::: zh-CN
|
||||
|
|
|
@ -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',
|
||||
// }),
|
||||
],
|
||||
})
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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>
|
|
@ -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" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { defineAppSetup } from 'valaxy'
|
||||
|
||||
export default defineAppSetup((_ctx) => {
|
||||
// can do for setup
|
||||
|
||||
})
|
||||
|
|
|
@ -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',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -3,3 +3,4 @@ export * from './helper'
|
|||
export * from './time'
|
||||
export * from './wrap'
|
||||
export * from './types'
|
||||
export * from './content'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -6,3 +6,6 @@ export * from './posts'
|
|||
|
||||
// used in node, but without node deps
|
||||
export * from './node'
|
||||
|
||||
// theme
|
||||
export * from './default-theme'
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue