mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
refactor: use deconstruct syntax to handle component props (#744)
This commit is contained in:
parent
0e38265f96
commit
d4ad65a1ea
@ -4,13 +4,13 @@ import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { label, total } = defineProps<{
|
||||
label: string
|
||||
total: number
|
||||
}>()
|
||||
|
||||
const active = ref(false)
|
||||
const list = computed(() => Array.from({ length: props.total }, (_, i) => i))
|
||||
const list = computed(() => Array.from({ length: total }, (_, i) => i))
|
||||
const position = ref({ x: 0, y: 0 })
|
||||
|
||||
const popover = useTemplateRef<HTMLDivElement>('popover')
|
||||
|
||||
@ -3,7 +3,7 @@ import { useInterval } from '@vueuse/core'
|
||||
import { onMounted, toRef, watch } from 'vue'
|
||||
import { useAudioPlayer } from '../composables/audio.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { src, autoplay, type, volume, startTime, endTime } = defineProps<{
|
||||
src: string
|
||||
autoplay?: boolean
|
||||
type?: string
|
||||
@ -13,20 +13,19 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const { paused, play, pause, seek, setVolume } = useAudioPlayer(
|
||||
toRef(() => props.src),
|
||||
toRef(() => src),
|
||||
{
|
||||
type: toRef(() => props.type || ''),
|
||||
autoplay: props.autoplay,
|
||||
type: toRef(() => type || ''),
|
||||
autoplay,
|
||||
oncanplay: () => {
|
||||
if (props.startTime) {
|
||||
seek(props.startTime)
|
||||
}
|
||||
if (startTime)
|
||||
seek(startTime)
|
||||
},
|
||||
ontimeupdate: (time) => {
|
||||
if (props.endTime && time >= props.endTime) {
|
||||
if (endTime && time >= endTime) {
|
||||
pause()
|
||||
if (props.startTime) {
|
||||
seek(props.startTime)
|
||||
if (startTime) {
|
||||
seek(startTime)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -56,7 +55,7 @@ function toggle() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(() => props.volume, (volume) => {
|
||||
watch(() => volume, (volume) => {
|
||||
if (typeof volume !== 'undefined') {
|
||||
setVolume(volume)
|
||||
}
|
||||
|
||||
@ -12,16 +12,12 @@ interface MessageData {
|
||||
}
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const { feature, past = 2, future = 1, meta = '' } = defineProps<{
|
||||
feature: string
|
||||
past?: number
|
||||
future?: number
|
||||
meta?: string
|
||||
}>(), {
|
||||
past: 2,
|
||||
future: 1,
|
||||
meta: '',
|
||||
})
|
||||
}>()
|
||||
|
||||
const url = 'https://caniuse.pengzhanbo.cn/'
|
||||
|
||||
@ -29,7 +25,7 @@ const height = ref('330px')
|
||||
|
||||
const isDark = useDarkMode()
|
||||
const source = computed(() => {
|
||||
const source = `${url}${props.feature}#past=${props.past}&future=${props.future}&meta=${props.meta}&theme=${isDark.value ? 'dark' : 'light'}`
|
||||
const source = `${url}${feature}#past=${past}&future=${future}&meta=${meta}&theme=${isDark.value ? 'dark' : 'light'}`
|
||||
|
||||
return source
|
||||
})
|
||||
@ -40,8 +36,8 @@ useEventListener('message', (event) => {
|
||||
if (
|
||||
type === 'ciu_embed'
|
||||
&& payload
|
||||
&& payload.feature === props.feature
|
||||
&& payload.meta === props.meta
|
||||
&& payload.feature === feature
|
||||
&& payload.meta === meta
|
||||
) {
|
||||
height.value = `${Math.ceil(payload.height)}px`
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { useDarkMode } from '@vuepress/helper/client'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { user, slash, title, preview, editable, tab, theme, width, height } = defineProps<{
|
||||
user: string
|
||||
slash: string
|
||||
title?: string
|
||||
@ -19,16 +19,16 @@ const CODEPEN_LINK = 'https://codepen.io/'
|
||||
const isDark = useDarkMode()
|
||||
|
||||
const link = computed(() => {
|
||||
const middle = props.preview ? '/embed/preview/' : '/embed/'
|
||||
const middle = preview ? '/embed/preview/' : '/embed/'
|
||||
const params = new URLSearchParams()
|
||||
|
||||
props.editable && params.set('editable', 'true')
|
||||
props.tab && params.set('default-tab', props.tab)
|
||||
editable && params.set('editable', 'true')
|
||||
tab && params.set('default-tab', tab)
|
||||
|
||||
const theme = props.theme ?? (isDark.value ? 'dark' : 'light')
|
||||
theme && params.set('theme-id', theme)
|
||||
const themeMode = theme ?? (isDark.value ? 'dark' : 'light')
|
||||
themeMode && params.set('theme-id', themeMode)
|
||||
|
||||
return `${CODEPEN_LINK}${props.user}${middle}${props.slash}?${params.toString()}`
|
||||
return `${CODEPEN_LINK}${user}${middle}${slash}?${params.toString()}`
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { Ref } from 'vue'
|
||||
import { inject, ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { type, filename, level, diff, expanded, focus, filepath } = defineProps<{
|
||||
type: 'file' | 'folder'
|
||||
filename: string
|
||||
level: number
|
||||
@ -18,17 +18,17 @@ const onNodeClick = inject<
|
||||
(filename: string, type: 'file' | 'folder') => void
|
||||
>('on-file-tree-node-click', () => {})
|
||||
|
||||
const active = ref(props.expanded)
|
||||
const active = ref(expanded)
|
||||
|
||||
function nodeClick() {
|
||||
if (props.filename === '…' || props.filename === '...')
|
||||
if (filename === '…' || filename === '...')
|
||||
return
|
||||
|
||||
onNodeClick(props.filepath || props.filename, props.type)
|
||||
onNodeClick(filepath || filename, type)
|
||||
}
|
||||
|
||||
function toggle(ev: MouseEvent) {
|
||||
if (props.type === 'folder') {
|
||||
if (type === 'folder') {
|
||||
const el = ev.target as HTMLElement
|
||||
if (!el.matches('.comment, .comment *')) {
|
||||
active.value = !active.value
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { useDarkMode } from '@vuepress/helper/client'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { source, title, tab, theme, width, height } = defineProps<{
|
||||
source: string
|
||||
title?: string
|
||||
tab: string
|
||||
@ -14,8 +14,8 @@ const props = defineProps<{
|
||||
const isDark = useDarkMode()
|
||||
|
||||
const link = computed(() => {
|
||||
const theme = props.theme === 'dark' ? '/dark/' : isDark.value ? '/dark/' : ''
|
||||
return `https://jsfiddle.net/${props.source}/embedded/${props.tab}${theme}`
|
||||
const themeMode = theme === 'dark' ? '/dark/' : isDark.value ? '/dark/' : ''
|
||||
return `https://jsfiddle.net/${source}/embedded/${tab}${themeMode}`
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<ReplitTokenMeta>()
|
||||
const { source, theme, width, height: h, title } = defineProps<ReplitTokenMeta>()
|
||||
|
||||
// magic height
|
||||
const height = ref('47px')
|
||||
@ -19,18 +19,18 @@ const REPLIT_LINK = 'https://replit.com/'
|
||||
const isDark = useDarkMode()
|
||||
|
||||
const link = computed(() => {
|
||||
const url = new URL(`/${props.source}`, REPLIT_LINK)
|
||||
const url = new URL(`/${source}`, REPLIT_LINK)
|
||||
url.searchParams.set('embed', 'true')
|
||||
|
||||
const theme = props.theme || (isDark.value ? 'dark' : 'light')
|
||||
url.searchParams.set('theme', theme)
|
||||
const themeMode = theme || (isDark.value ? 'dark' : 'light')
|
||||
url.searchParams.set('theme', themeMode)
|
||||
|
||||
return url.toString()
|
||||
})
|
||||
|
||||
function onload() {
|
||||
loaded.value = true
|
||||
height.value = props.height || '450px'
|
||||
height.value = h || '450px'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -5,27 +5,27 @@ import { onMounted, ref, shallowRef, watch } from 'vue'
|
||||
interface TabProps extends Record<string, unknown> {
|
||||
id: string
|
||||
}
|
||||
const props = withDefaults(defineProps<{
|
||||
const { id, tabId = '', active = 0, data } = defineProps<{
|
||||
id: string
|
||||
tabId?: string
|
||||
active?: number
|
||||
data: TabProps[]
|
||||
}>(), { active: 0, tabId: '' })
|
||||
}>()
|
||||
|
||||
const TAB_STORE_NAME = 'VUEPRESS_TAB_STORE'
|
||||
|
||||
const tabStore = useStorage<Record<string, string>>(TAB_STORE_NAME, {})
|
||||
|
||||
// Index of current active item
|
||||
const activeIndex = ref(props.active)
|
||||
const activeIndex = ref(active)
|
||||
|
||||
// Refs of the tab buttons
|
||||
const tabRefs = shallowRef<HTMLUListElement[]>([])
|
||||
|
||||
// Update store
|
||||
function updateStore(): void {
|
||||
if (props.tabId)
|
||||
tabStore.value[props.tabId] = props.data[activeIndex.value].id
|
||||
if (tabId)
|
||||
tabStore.value[tabId] = data[activeIndex.value]?.id
|
||||
}
|
||||
|
||||
// Activate next tab
|
||||
@ -59,26 +59,26 @@ function keyboardHandler(event: KeyboardEvent, index: number): void {
|
||||
}
|
||||
|
||||
function getInitialIndex(): number {
|
||||
if (props.tabId) {
|
||||
const valueIndex = props.data.findIndex(
|
||||
({ id }) => tabStore.value[props.tabId] === id,
|
||||
if (tabId) {
|
||||
const valueIndex = data.findIndex(
|
||||
({ id }) => tabStore.value[tabId] === id,
|
||||
)
|
||||
|
||||
if (valueIndex !== -1)
|
||||
return valueIndex
|
||||
}
|
||||
|
||||
return props.active
|
||||
return active
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
activeIndex.value = getInitialIndex()
|
||||
|
||||
watch(
|
||||
() => tabStore.value[props.tabId],
|
||||
() => tabStore.value[tabId],
|
||||
(newValue, oldValue) => {
|
||||
if (props.tabId && newValue !== oldValue) {
|
||||
const index = props.data.findIndex(({ id }) => id === newValue)
|
||||
if (tabId && newValue !== oldValue) {
|
||||
const index = data.findIndex(({ id }) => id === newValue)
|
||||
|
||||
if (index !== -1)
|
||||
activeIndex.value = index
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, provide, ref, useTemplateRef, watch } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const { title, height = '320px', entryFile } = defineProps<{
|
||||
title?: string
|
||||
height?: string
|
||||
entryFile?: string
|
||||
}>(), { height: '320px' })
|
||||
}>()
|
||||
|
||||
const activeNode = ref(props.entryFile || '')
|
||||
const activeNode = ref(entryFile || '')
|
||||
const isEmpty = ref(true)
|
||||
const codePanel = useTemplateRef<HTMLDivElement>('codePanel')
|
||||
|
||||
@ -44,7 +44,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="vp-code-tree">
|
||||
<div class="code-tree-panel" :style="{ 'max-height': props.height }">
|
||||
<div class="code-tree-panel" :style="{ 'max-height': height }">
|
||||
<div v-if="title" class="code-tree-title" :title="title">
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
@ -52,7 +52,7 @@ onMounted(() => {
|
||||
<slot name="file-tree" />
|
||||
</div>
|
||||
</div>
|
||||
<div ref="codePanel" class="code-panel" :style="{ height: props.height }">
|
||||
<div ref="codePanel" class="code-panel" :style="{ height }">
|
||||
<slot />
|
||||
<div v-if="isEmpty" class="code-tree-empty">
|
||||
<span class="vpi-code-tree-empty" />
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
import { provide, ref } from 'vue'
|
||||
import { INJECT_COLLAPSE_KEY } from '../options.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { accordion, index } = defineProps<{
|
||||
accordion?: boolean
|
||||
index?: number
|
||||
}>()
|
||||
|
||||
const currentIndex = ref<number | undefined>(props.index)
|
||||
const currentIndex = ref<number | undefined>(index)
|
||||
|
||||
provide(INJECT_COLLAPSE_KEY, {
|
||||
accordion: props.accordion ?? false,
|
||||
accordion: accordion ?? false,
|
||||
index: currentIndex,
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -6,7 +6,7 @@ import { INJECT_COLLAPSE_KEY } from '../options.js'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { expand, index } = defineProps<{
|
||||
expand?: boolean
|
||||
index: number
|
||||
}>()
|
||||
@ -20,36 +20,36 @@ if (__VUEPRESS_DEV__ && !collapse) {
|
||||
throw new Error('<VPCollapseItem /> must be used inside <VPCollapse />')
|
||||
}
|
||||
|
||||
const expand = ref(
|
||||
const expanded = ref(
|
||||
collapse?.accordion && typeof collapse.index.value !== 'undefined'
|
||||
? props.index === collapse.index.value
|
||||
: props.expand,
|
||||
? index === collapse.index.value
|
||||
: expand,
|
||||
)
|
||||
|
||||
if (collapse?.accordion) {
|
||||
watch(collapse?.index, () => {
|
||||
expand.value = collapse?.index.value === props.index
|
||||
expanded.value = collapse?.index.value === index
|
||||
})
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (collapse?.accordion) {
|
||||
if (collapse.index.value === props.index && expand.value) {
|
||||
expand.value = false
|
||||
if (collapse.index.value === index && expanded.value) {
|
||||
expanded.value = false
|
||||
}
|
||||
else {
|
||||
collapse!.index.value = props.index!
|
||||
expand.value = true
|
||||
collapse!.index.value = index!
|
||||
expanded.value = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
expand.value = !expand.value
|
||||
expanded.value = !expanded.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-collapse-item" :class="{ expand }">
|
||||
<div class="vp-collapse-item" :class="{ expanded }">
|
||||
<div class="vp-collapse-header" @click="toggle">
|
||||
<span class="vpi-chevron-right" />
|
||||
<p class="vp-collapse-title">
|
||||
@ -57,7 +57,7 @@ function toggle() {
|
||||
</p>
|
||||
</div>
|
||||
<FadeInExpandTransition>
|
||||
<div v-show="expand" class="vp-collapse-content">
|
||||
<div v-show="expanded" class="vp-collapse-content">
|
||||
<div class="vp-collapse-content-inner">
|
||||
<slot />
|
||||
</div>
|
||||
@ -95,7 +95,7 @@ function toggle() {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.vp-collapse-item.expand .vpi-chevron-right {
|
||||
.vp-collapse-item.expanded .vpi-chevron-right {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@ import { useExpand } from '../composables/demo.js'
|
||||
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
import '../styles/demo.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { type, title, desc, expanded } = defineProps<{
|
||||
type?: 'vue' | 'markdown'
|
||||
title?: string
|
||||
desc?: string
|
||||
expanded?: boolean
|
||||
}>()
|
||||
|
||||
const [showCode, toggleCode] = useExpand(props.expanded)
|
||||
const [showCode, toggleCode] = useExpand(expanded)
|
||||
|
||||
const draw = useTemplateRef<HTMLIFrameElement>('draw')
|
||||
const vueDraw = useTemplateRef<HTMLIFrameElement>('draw-vue')
|
||||
@ -30,7 +30,7 @@ function resizeAndPositionVueDraw() {
|
||||
vueDraw.value.style.left = `${rect.x + scrollLeft}px`
|
||||
}
|
||||
|
||||
if (props.type === 'vue' && !__VUEPRESS_SSR__) {
|
||||
if (type === 'vue' && !__VUEPRESS_SSR__) {
|
||||
watch([draw, vueDraw], () => {
|
||||
resizeAndPositionVueDraw()
|
||||
if (draw.value && vueDraw.value) {
|
||||
|
||||
@ -8,29 +8,29 @@ import '@vuepress/helper/transition/fade-in.css'
|
||||
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
import '../styles/demo.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { title, desc, expanded, config } = defineProps<{
|
||||
title?: string
|
||||
desc?: string
|
||||
expanded?: boolean
|
||||
config?: DemoConfig
|
||||
}>()
|
||||
|
||||
const [showCode, toggleCode] = useExpand(props.expanded)
|
||||
const [showCode, toggleCode] = useExpand(expanded)
|
||||
|
||||
const { resources, showResources, toggleResources } = useResources(
|
||||
useTemplateRef<HTMLDivElement>('resourcesEl'),
|
||||
() => props.config,
|
||||
() => config,
|
||||
)
|
||||
|
||||
const { id, height } = useNormalDemo(
|
||||
useTemplateRef<HTMLIFrameElement>('draw'),
|
||||
() => props.title,
|
||||
() => props.config,
|
||||
() => title,
|
||||
() => config,
|
||||
)
|
||||
|
||||
const data = useFence(
|
||||
useTemplateRef<HTMLDivElement>('fence'),
|
||||
() => props.config,
|
||||
() => config,
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { decodeData } from '@vuepress/helper/client'
|
||||
import { useClipboard, useToggle } from '@vueuse/core'
|
||||
import { computed, useTemplateRef } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { title, align = 'left', copy, maxContent, fullWidth, markdown } = defineProps<{
|
||||
/** 表格标题 */
|
||||
title?: string
|
||||
/** 对其方式 */
|
||||
@ -19,7 +19,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const tableEl = useTemplateRef('table')
|
||||
const rawContent = computed(() => props.markdown ? decodeData(props.markdown) : '')
|
||||
const rawContent = computed(() => markdown ? decodeData(markdown) : '')
|
||||
|
||||
const [isHTMLCopied, toggleHTMLCopy] = useToggle()
|
||||
const [isMDCopied, toggleMDCopy] = useToggle()
|
||||
@ -35,7 +35,7 @@ function onCopy(type: 'html' | 'md') {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-table" :class="{ [align || 'left']: true, full: fullWidth }">
|
||||
<div class="vp-table" :class="{ [align]: true, full: fullWidth }">
|
||||
<div class="table-container">
|
||||
<div class="table-content">
|
||||
<div v-if="copy" class="table-toolbar">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed, provide } from 'vue'
|
||||
import { INJECT_TIMELINE_KEY } from '../options.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { horizontal, card, placement, line } = defineProps<{
|
||||
horizontal?: boolean
|
||||
card?: boolean
|
||||
placement?: 'left' | 'right' | 'between'
|
||||
@ -10,10 +10,10 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
provide(INJECT_TIMELINE_KEY, computed(() => ({
|
||||
line: props.line || 'solid',
|
||||
card: props.card ?? false,
|
||||
horizontal: props.horizontal ?? false,
|
||||
placement: props.placement || 'left',
|
||||
line: line || 'solid',
|
||||
card: card ?? false,
|
||||
horizontal: horizontal ?? false,
|
||||
placement: placement || 'left',
|
||||
})))
|
||||
</script>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { useMediaQuery } from '@vueuse/core'
|
||||
import { computed, inject } from 'vue'
|
||||
import { INJECT_TIMELINE_KEY } from '../options.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { time, type, card, line, icon, color, placement } = defineProps<{
|
||||
time?: string
|
||||
type?: 'info' | 'tip' | 'success' | 'warning' | 'danger' | 'caution' | 'important' | (string & {})
|
||||
card?: boolean
|
||||
@ -25,17 +25,17 @@ const defaultOptions = inject<ComputedRef<{
|
||||
|
||||
const timeline = computed(() => {
|
||||
const between = defaultOptions?.value.placement === 'between' && !is639.value
|
||||
const placement = defaultOptions?.value.placement === 'between' ? 'left' : defaultOptions?.value.placement
|
||||
const defaultPlacement = defaultOptions?.value.placement === 'between' ? 'left' : defaultOptions?.value.placement
|
||||
return {
|
||||
time: props.time,
|
||||
type: props.type || 'info',
|
||||
line: props.line || defaultOptions?.value.line || 'solid',
|
||||
icon: props.icon,
|
||||
color: props.color,
|
||||
time,
|
||||
type: type || 'info',
|
||||
line: line || defaultOptions?.value.line || 'solid',
|
||||
icon,
|
||||
color,
|
||||
horizontal: defaultOptions?.value.horizontal ?? false,
|
||||
between: between ? props.placement || 'left' : false,
|
||||
placement: between ? '' : (placement || 'left'),
|
||||
card: props.card ?? defaultOptions?.value.card ?? false,
|
||||
between: between ? placement || 'left' : false,
|
||||
placement: between ? '' : (defaultPlacement || 'left'),
|
||||
card: card ?? defaultOptions?.value.card ?? false,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -32,7 +32,7 @@ import BackIcon from './icons/BackIcon.vue'
|
||||
import ClearIcon from './icons/ClearIcon.vue'
|
||||
import SearchIcon from './icons/SearchIcon.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { locales, options } = defineProps<{
|
||||
locales: SearchBoxLocales
|
||||
options: SearchOptions
|
||||
}>()
|
||||
@ -42,7 +42,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const routeLocale = useRouteLocale()
|
||||
const locale = useLocale(toRef(props.locales))
|
||||
const locale = useLocale(toRef(() => locales))
|
||||
|
||||
const el = shallowRef<HTMLElement>()
|
||||
const resultsEl = shallowRef<HTMLElement>()
|
||||
@ -71,15 +71,15 @@ const searchIndex = computedAsync(async () =>
|
||||
prefix: true,
|
||||
boost: { title: 4, text: 2, titles: 1 },
|
||||
},
|
||||
...props.options.miniSearch?.searchOptions,
|
||||
...props.options.miniSearch?.options,
|
||||
...options.miniSearch?.searchOptions,
|
||||
...options.miniSearch?.options,
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
const disableQueryPersistence = computed(() =>
|
||||
props.options?.disableQueryPersistence === true,
|
||||
options?.disableQueryPersistence === true,
|
||||
)
|
||||
const filterText = disableQueryPersistence.value
|
||||
? ref('')
|
||||
|
||||
@ -3,11 +3,11 @@ import type { SearchBoxLocales } from '../../shared/index.js'
|
||||
import { toRef } from 'vue'
|
||||
import { useLocale } from '../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { locales } = defineProps<{
|
||||
locales: SearchBoxLocales
|
||||
}>()
|
||||
|
||||
const locale = useLocale(toRef(props.locales))
|
||||
const locale = useLocale(toRef(() => locales))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -6,14 +6,14 @@ import { withBase } from 'vuepress/client'
|
||||
import { isLinkHttp } from 'vuepress/shared'
|
||||
import { useData } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<ThemeHomeBanner>()
|
||||
const { banner, bannerMask, hero } = defineProps<ThemeHomeBanner>()
|
||||
|
||||
const DEFAULT_BANNER = 'https://api.pengzhanbo.cn/wallpaper/bing'
|
||||
|
||||
const { isDark, frontmatter: matter } = useData<'home'>()
|
||||
|
||||
const mask = computed(() => {
|
||||
const mask = props.bannerMask ?? matter.value.bannerMask
|
||||
const mask = bannerMask ?? matter.value.bannerMask
|
||||
if (typeof mask !== 'object')
|
||||
return mask || 0
|
||||
|
||||
@ -21,17 +21,17 @@ const mask = computed(() => {
|
||||
})
|
||||
|
||||
const bannerStyle = computed(() => {
|
||||
const banner = props.banner ?? matter.value.banner
|
||||
const link = banner ? isLinkHttp(banner) ? banner : withBase(banner) : DEFAULT_BANNER
|
||||
const _banner = banner ?? matter.value.banner
|
||||
const link = _banner ? isLinkHttp(_banner) ? _banner : withBase(_banner) : DEFAULT_BANNER
|
||||
return {
|
||||
'background-image': `url(${link})`,
|
||||
}
|
||||
})
|
||||
|
||||
const name = computed(() => props.hero?.name ?? matter.value.hero?.name ?? 'Plume')
|
||||
const tagline = computed(() => props.hero?.tagline ?? matter.value.hero?.tagline ?? 'A VuePress Theme')
|
||||
const text = computed(() => props.hero?.text ?? matter.value.hero?.text)
|
||||
const actions = computed(() => props.hero?.actions ?? matter.value.hero?.actions ?? [])
|
||||
const name = computed(() => hero?.name ?? matter.value.hero?.name ?? 'Plume')
|
||||
const tagline = computed(() => hero?.tagline ?? matter.value.hero?.tagline ?? 'A VuePress Theme')
|
||||
const text = computed(() => hero?.text ?? matter.value.hero?.text)
|
||||
const actions = computed(() => hero?.actions ?? matter.value.hero?.actions ?? [])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -5,38 +5,38 @@ import { withBase } from 'vuepress/client'
|
||||
import { isLinkHttp } from 'vuepress/shared'
|
||||
import { useDarkMode } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<ThemeHomeConfigBase & {
|
||||
const { backgroundAttachment, backgroundImage, containerClass, full } = defineProps<ThemeHomeConfigBase & {
|
||||
containerClass?: any
|
||||
}>()
|
||||
|
||||
const isDark = useDarkMode()
|
||||
|
||||
const styles = computed(() => {
|
||||
if (!props.backgroundImage)
|
||||
if (!backgroundImage)
|
||||
return null
|
||||
|
||||
const image = typeof props.backgroundImage === 'string' ? props.backgroundImage : (props.backgroundImage[isDark.value ? 'dark' : 'light'] ?? props.backgroundImage.light)
|
||||
const image = typeof backgroundImage === 'string' ? backgroundImage : (backgroundImage[isDark.value ? 'dark' : 'light'] ?? backgroundImage.light)
|
||||
|
||||
if (!image)
|
||||
return null
|
||||
|
||||
const link = isLinkHttp(image) ? props.backgroundImage : withBase(image)
|
||||
const link = isLinkHttp(image) ? backgroundImage : withBase(image)
|
||||
return {
|
||||
'background-image': `url(${link})`,
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center',
|
||||
'background-repeat': 'no-repeat',
|
||||
'background-attachment': props.backgroundAttachment || '',
|
||||
'background-attachment': backgroundAttachment || '',
|
||||
}
|
||||
})
|
||||
|
||||
const containerClass = computed(() => normalizeClass(props.containerClass || ''))
|
||||
const containerClasses = computed(() => normalizeClass(containerClass || ''))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-home-box" :class="{ full: props.full }" :style="styles">
|
||||
<div class="vp-home-box" :class="{ full }" :style="styles">
|
||||
<slot name="before" />
|
||||
<div class="container" :class="containerClass">
|
||||
<div class="container" :class="containerClasses">
|
||||
<slot />
|
||||
</div>
|
||||
<slot name="after" />
|
||||
|
||||
@ -6,15 +6,15 @@ import VPLink from '@theme/VPLink.vue'
|
||||
import { isLinkAbsolute, isLinkHttp } from '@vuepress/helper/client'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<ThemeHomeFeature>()
|
||||
const { icon, link, linkText, rel, target, title, details } = defineProps<ThemeHomeFeature>()
|
||||
|
||||
const ICONIFY_NAME = /^[\w-]+:[\w-]+$/
|
||||
|
||||
const isIconify = computed(() => {
|
||||
if (typeof props.icon !== 'string' || isLinkAbsolute(props.icon) || isLinkHttp(props.icon)) {
|
||||
if (typeof icon !== 'string' || isLinkAbsolute(icon) || isLinkHttp(icon)) {
|
||||
return false
|
||||
}
|
||||
return ICONIFY_NAME.test(props.icon)
|
||||
return ICONIFY_NAME.test(icon)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -4,10 +4,10 @@ import VPHomeBox from '@theme/Home/VPHomeBox.vue'
|
||||
import VPHomeFeature from '@theme/Home/VPHomeFeature.vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<ThemeHomeFeatures>()
|
||||
const { features, title, description, type, backgroundImage, backgroundAttachment, full, index } = defineProps<ThemeHomeFeatures>()
|
||||
|
||||
const grid = computed(() => {
|
||||
const length = props.features?.length
|
||||
const length = features?.length
|
||||
|
||||
if (!length)
|
||||
return undefined
|
||||
@ -32,11 +32,13 @@ const grid = computed(() => {
|
||||
<VPHomeBox
|
||||
v-if="features"
|
||||
class="vp-home-features"
|
||||
:type="type"
|
||||
:background-image="backgroundImage"
|
||||
:background-attachment="backgroundAttachment"
|
||||
:full="full"
|
||||
:index="index"
|
||||
v-bind="{
|
||||
type,
|
||||
backgroundAttachment,
|
||||
backgroundImage,
|
||||
full,
|
||||
index,
|
||||
}"
|
||||
>
|
||||
<h2 v-if="title" class="title" v-html="title" />
|
||||
<p v-if="description" class="description" v-html="description" />
|
||||
@ -48,15 +50,7 @@ const grid = computed(() => {
|
||||
class="item"
|
||||
:class="[grid]"
|
||||
>
|
||||
<VPHomeFeature
|
||||
:icon="feature.icon"
|
||||
:title="feature.title"
|
||||
:details="feature.details"
|
||||
:link="feature.link"
|
||||
:link-text="feature.linkText"
|
||||
:rel="feature.rel"
|
||||
:target="feature.target"
|
||||
/>
|
||||
<VPHomeFeature v-bind="feature" />
|
||||
</div>
|
||||
</div>
|
||||
</VPHomeBox>
|
||||
|
||||
@ -3,7 +3,8 @@ import type { ThemeHomeHero } from '../../../shared/index.js'
|
||||
import { effectComponents, effects } from '@internal/home-hero-effects'
|
||||
import ImageBg from '@theme/background/ImageBg.vue'
|
||||
import VPButton from '@theme/VPButton.vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { hasGlobalComponent } from '@vuepress/helper/client'
|
||||
import { computed, markRaw, nextTick, onMounted, onUnmounted, resolveComponent, watch } from 'vue'
|
||||
import { isPlainObject } from 'vuepress/shared'
|
||||
import { useData } from '../../composables/index.js'
|
||||
import { inBrowser } from '../../utils/index.js'
|
||||
@ -15,10 +16,11 @@ const hero = computed(() => props.hero ?? frontmatter.value.hero ?? {})
|
||||
const actions = computed(() => hero.value.actions ?? [])
|
||||
|
||||
const effect = computed(() => {
|
||||
const effect = props.effect || props.background
|
||||
if (!effect || !effects.includes(effect))
|
||||
return null
|
||||
return effect as typeof effects[number]
|
||||
if (props.effect)
|
||||
return props.effect
|
||||
if (props.background && effects.includes(props.background))
|
||||
return props.background
|
||||
return null
|
||||
})
|
||||
|
||||
const effectConfig = computed(() => {
|
||||
@ -37,6 +39,17 @@ const effectConfig = computed(() => {
|
||||
return props.effectConfig
|
||||
})
|
||||
|
||||
const realEffectComponent = computed(() => {
|
||||
if (!effect.value)
|
||||
return null
|
||||
if (effectComponents[effect.value])
|
||||
return markRaw(effectComponents[effect.value])
|
||||
if (hasGlobalComponent(effect.value))
|
||||
return resolveComponent(effect.value)
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
function noTransition() {
|
||||
document.documentElement.classList.add('no-transition')
|
||||
setTimeout(() => {
|
||||
@ -85,7 +98,7 @@ onUnmounted(() => {
|
||||
[effect ?? '']: !!effect,
|
||||
}"
|
||||
>
|
||||
<component :is="effectComponents[effect]" v-if="effect" v-bind="effectConfig" />
|
||||
<component :is="realEffectComponent" v-if="realEffectComponent" v-bind="effectConfig" />
|
||||
<ImageBg v-else v-bind="props" />
|
||||
|
||||
<div class="hero-container">
|
||||
|
||||
@ -5,7 +5,7 @@ import VPImage from '@theme/VPImage.vue'
|
||||
import { computed } from 'vue'
|
||||
import { useData } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<ThemeHomeProfile>()
|
||||
const { name, description, avatar, circle, type, backgroundImage, backgroundAttachment, full, index } = defineProps<ThemeHomeProfile>()
|
||||
|
||||
const { theme } = useData()
|
||||
|
||||
@ -13,10 +13,10 @@ const rawProfile = computed(() => theme.value.profile)
|
||||
|
||||
const profile = computed(() => {
|
||||
return {
|
||||
name: props.name || rawProfile.value?.name,
|
||||
description: props.description || rawProfile.value?.description,
|
||||
avatar: props.avatar || rawProfile.value?.avatar || rawProfile.value?.url,
|
||||
circle: props.circle || rawProfile.value?.circle,
|
||||
name: name || rawProfile.value?.name,
|
||||
description: description || rawProfile.value?.description,
|
||||
avatar: avatar || rawProfile.value?.avatar || rawProfile.value?.url,
|
||||
circle: circle || rawProfile.value?.circle,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -24,11 +24,7 @@ const profile = computed(() => {
|
||||
<template>
|
||||
<VPHomeBox
|
||||
class="vp-home-profile"
|
||||
:type="type"
|
||||
:background-image="backgroundImage"
|
||||
:background-attachment="backgroundAttachment"
|
||||
:full="full"
|
||||
:index="index"
|
||||
v-bind="{ type, backgroundAttachment, backgroundImage, full, index }"
|
||||
>
|
||||
<VPImage v-if="profile.avatar" :image="profile.avatar" :class="{ circle: profile.circle }" />
|
||||
|
||||
|
||||
@ -4,11 +4,9 @@ import VPHomeBox from '@theme/Home/VPHomeBox.vue'
|
||||
import VPImage from '@theme/VPImage.vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<ThemeHomeTextImage>()
|
||||
const { width, title, description, list, image, type, backgroundImage, backgroundAttachment, full, index } = defineProps<ThemeHomeTextImage>()
|
||||
|
||||
const maxWidth = computed(() => {
|
||||
const width = props.width
|
||||
|
||||
if (typeof width === 'number')
|
||||
return `${width}px`
|
||||
|
||||
@ -19,12 +17,8 @@ const maxWidth = computed(() => {
|
||||
<template>
|
||||
<VPHomeBox
|
||||
class="vp-home-text-image"
|
||||
:type="type"
|
||||
:background-image="backgroundImage"
|
||||
:background-attachment="backgroundAttachment"
|
||||
:full="full"
|
||||
:container-class="{ reverse: type === 'text-image' }"
|
||||
:index="index"
|
||||
v-bind="{ type, backgroundAttachment, backgroundImage, full, index }"
|
||||
>
|
||||
<div class="content-image">
|
||||
<VPImage :image="image" :style="{ maxWidth }" />
|
||||
@ -39,7 +33,7 @@ const maxWidth = computed(() => {
|
||||
<p v-if="description" class="description" v-html="description" />
|
||||
|
||||
<ul v-if="list && list.length" class="list">
|
||||
<li v-for="(item, index) in list" :key="index">
|
||||
<li v-for="(item, i) in list" :key="i">
|
||||
<template v-if="typeof item === 'object'">
|
||||
<h3 v-if="item.title" v-html="item.title" />
|
||||
<p v-if="item.description" v-html="item.description" />
|
||||
|
||||
@ -11,7 +11,7 @@ import { useWindowScroll } from '@vueuse/core'
|
||||
import { ref, watchPostEffect } from 'vue'
|
||||
import { useData, useSidebar } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { isScreenOpen } = defineProps<{
|
||||
isScreenOpen: boolean
|
||||
}>()
|
||||
defineEmits<(e: 'toggleScreen') => void>()
|
||||
@ -27,7 +27,7 @@ watchPostEffect(() => {
|
||||
'has-sidebar': hasSidebar.value,
|
||||
'home': frontmatter.value.pageLayout === 'home',
|
||||
'top': y.value === 0,
|
||||
'screen-open': props.isScreenOpen,
|
||||
'screen-open': isScreenOpen,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
defineProps<{
|
||||
const { active } = defineProps<{
|
||||
active: boolean
|
||||
}>()
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import { resolveRouteFullPath } from 'vuepress/client'
|
||||
import { useData } from '../../composables/index.js'
|
||||
import { isActive } from '../../utils/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { item } = defineProps<{
|
||||
item: ResolvedNavItemWithChildren
|
||||
}>()
|
||||
|
||||
@ -20,14 +20,14 @@ function isChildActive(navItem: ResolvedNavItem): boolean {
|
||||
return isActive(
|
||||
page.value.path,
|
||||
resolveRouteFullPath(navItem.link),
|
||||
!!props.item.activeMatch,
|
||||
!!item.activeMatch,
|
||||
)
|
||||
}
|
||||
else {
|
||||
return navItem.items.some(isChildActive)
|
||||
}
|
||||
}
|
||||
const childrenActive = computed(() => isChildActive(props.item))
|
||||
const childrenActive = computed(() => isChildActive(item))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -7,7 +7,7 @@ import { resolveRouteFullPath } from 'vuepress/client'
|
||||
import { useData } from '../../composables/index.js'
|
||||
import { isActive } from '../../utils/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { item } = defineProps<{
|
||||
item: ResolvedNavItemWithLink
|
||||
}>()
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import { inBrowser } from '../../utils/index.js'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in.css'
|
||||
|
||||
defineProps<{
|
||||
const { open } = defineProps<{
|
||||
open: boolean
|
||||
}>()
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { text, icon, badge, items } = defineProps<{
|
||||
text: string
|
||||
icon?: ThemeIcon
|
||||
badge?: string | ThemeBadge
|
||||
@ -19,7 +19,7 @@ const props = defineProps<{
|
||||
const isOpen = ref(false)
|
||||
|
||||
const groupId = computed(
|
||||
() => `nav-screen-menu-group-${props.text.replace(' ', '-').toLowerCase()}`,
|
||||
() => `nav-screen-menu-group-${text.replace(' ', '-').toLowerCase()}`,
|
||||
)
|
||||
|
||||
function toggle() {
|
||||
|
||||
@ -5,7 +5,7 @@ import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { inject } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
const { item } = defineProps<{
|
||||
item: ResolvedNavItemWithLink
|
||||
}>()
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { NavItemWithLink, ThemeIcon } from '../../../shared/index.js'
|
||||
import VPNavScreenMenuGroupLink from '@theme/Nav/VPNavScreenMenuGroupLink.vue'
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
|
||||
defineProps<{
|
||||
const { icon, text, items } = defineProps<{
|
||||
icon?: ThemeIcon
|
||||
text?: string
|
||||
items: NavItemWithLink[]
|
||||
|
||||
@ -5,7 +5,7 @@ import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { inject } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
const { item } = defineProps<{
|
||||
item: ResolvedNavItemWithLink
|
||||
}>()
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@ import type { CategoryItem, CategoryItemWithPost } from '../../composables/index
|
||||
import VPCategoriesGroup from '@theme/Posts/VPCategoriesGroup.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
|
||||
withDefaults(defineProps<{
|
||||
const { items, depth = 0 } = defineProps<{
|
||||
items: (CategoryItem | CategoryItemWithPost)[]
|
||||
depth?: number
|
||||
}>(), {
|
||||
depth: 0,
|
||||
})
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -5,12 +5,11 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vuepress/client'
|
||||
import { useData } from '../../composables/index.js'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const { item, depth = 0 } = defineProps<{
|
||||
item: CategoryItem
|
||||
depth?: number
|
||||
}>(), {
|
||||
depth: 0,
|
||||
})
|
||||
}>()
|
||||
|
||||
const { collection } = useData<'page', 'post'>()
|
||||
const route = useRoute()
|
||||
const el = ref<HTMLDivElement | null>(null)
|
||||
@ -28,16 +27,16 @@ const expandDepth = computed(() => {
|
||||
})
|
||||
|
||||
watch(
|
||||
() => [route.query, props.item, expandDepth.value],
|
||||
() => [route.query, item, expandDepth.value],
|
||||
() => {
|
||||
const id = route.query.id as string
|
||||
if (!id) {
|
||||
expand.value = props.depth <= expandDepth.value
|
||||
expand.value = depth <= expandDepth.value
|
||||
}
|
||||
else {
|
||||
expand.value = hasExpand(props.item, id)
|
||||
expand.value = hasExpand(item, id)
|
||||
}
|
||||
isExpand.value = id ? props.item.id === id : false
|
||||
isExpand.value = id ? item.id === id : false
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useData } from '../../composables/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { page, isFirstPage, isLastPage, pageRange } = defineProps<{
|
||||
page: number
|
||||
totalPage: number
|
||||
isFirstPage: boolean
|
||||
|
||||
@ -6,7 +6,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { withBase } from 'vuepress/client'
|
||||
import { useData, useInternalLink, useTagColors } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { post, index } = defineProps<{
|
||||
post: ThemePostsItem
|
||||
index: number
|
||||
}>()
|
||||
@ -14,9 +14,9 @@ const props = defineProps<{
|
||||
const isMobile = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
isMobile.value = _isMobile(navigator.userAgent)
|
||||
isMobile.value = _isMobile()
|
||||
window.addEventListener('resize', () => {
|
||||
isMobile.value = _isMobile(navigator.userAgent)
|
||||
isMobile.value = _isMobile()
|
||||
})
|
||||
})
|
||||
|
||||
@ -24,15 +24,15 @@ const { collection } = useData<'page', 'post'>()
|
||||
const colors = useTagColors()
|
||||
const { categories: categoriesLink, tags: tagsLink } = useInternalLink()
|
||||
|
||||
const createTime = computed(() => props.post.createTime?.split(/\s|T/)[0].replace(/\//g, '-'))
|
||||
const categoryList = computed(() => props.post.categoryList ?? [])
|
||||
const createTime = computed(() => post.createTime?.split(/\s|T/)[0].replace(/\//g, '-'))
|
||||
const categoryList = computed(() => post.categoryList ?? [])
|
||||
|
||||
const sticky = computed(() => {
|
||||
if (typeof props.post.sticky === 'boolean') {
|
||||
return props.post.sticky
|
||||
if (typeof post.sticky === 'boolean') {
|
||||
return post.sticky
|
||||
}
|
||||
else if (typeof props.post.sticky === 'number') {
|
||||
return props.post.sticky >= 0
|
||||
else if (typeof post.sticky === 'number') {
|
||||
return post.sticky >= 0
|
||||
}
|
||||
return false
|
||||
})
|
||||
@ -40,7 +40,7 @@ const sticky = computed(() => {
|
||||
const tags = computed(() => {
|
||||
const tagTheme = collection.value?.tagsTheme ?? 'colored'
|
||||
|
||||
return (props.post.tags ?? [])
|
||||
return (post.tags ?? [])
|
||||
.slice(0, 4)
|
||||
.map(tag => ({
|
||||
name: tag,
|
||||
@ -49,18 +49,18 @@ const tags = computed(() => {
|
||||
})
|
||||
|
||||
const cover = computed<PostsCoverStyle | null>(() => {
|
||||
if (!props.post.cover)
|
||||
if (!post.cover)
|
||||
return null
|
||||
const opt = collection.value?.postCover ?? 'right'
|
||||
const options = typeof opt === 'string' ? { layout: opt } : opt
|
||||
return { layout: 'right', ratio: '4:3', ...options, ...props.post.coverStyle }
|
||||
return { layout: 'right', ratio: '4:3', ...options, ...post.coverStyle }
|
||||
})
|
||||
|
||||
const coverLayout = computed(() => {
|
||||
if (isMobile.value)
|
||||
return 'top'
|
||||
const layout = cover.value?.layout ?? 'right'
|
||||
const odd = (props.index + 1) % 2 === 1
|
||||
const odd = (index + 1) % 2 === 1
|
||||
if (layout === 'odd-left')
|
||||
return odd ? 'left' : 'right'
|
||||
if (layout === 'odd-right')
|
||||
@ -69,7 +69,7 @@ const coverLayout = computed(() => {
|
||||
})
|
||||
|
||||
const coverCompact = computed(() => {
|
||||
if (props.post.excerpt || coverLayout.value === 'top')
|
||||
if (post.excerpt || coverLayout.value === 'top')
|
||||
return false
|
||||
return cover.value?.compact ?? false
|
||||
})
|
||||
|
||||
@ -5,7 +5,7 @@ import VPTransitionDrop from '@theme/VPTransitionDrop.vue'
|
||||
import { computed } from 'vue'
|
||||
import { usePostListControl } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { homePosts } = defineProps<{
|
||||
homePosts?: boolean
|
||||
}>()
|
||||
|
||||
@ -18,7 +18,7 @@ const {
|
||||
isFirstPage,
|
||||
isPaginationEnabled,
|
||||
changePage,
|
||||
} = usePostListControl(computed(() => !!props.homePosts))
|
||||
} = usePostListControl(computed(() => !!homePosts))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -10,7 +10,7 @@ import VPTransitionFadeSlideY from '@theme/VPTransitionFadeSlideY.vue'
|
||||
import { onBeforeUnmount, watch } from 'vue'
|
||||
import { forceUpdateCollection, useData } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { homePosts, collection } = defineProps<{
|
||||
homePosts?: boolean
|
||||
type?: string
|
||||
onlyOnce?: boolean
|
||||
@ -20,8 +20,8 @@ const props = defineProps<{
|
||||
const { theme, page } = useData()
|
||||
|
||||
watch(
|
||||
() => [props.homePosts, props.collection],
|
||||
() => forceUpdateCollection(props.homePosts ? (props.collection || true) : undefined),
|
||||
() => [homePosts, collection],
|
||||
() => forceUpdateCollection(homePosts ? (collection || true) : undefined),
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import VPLink from '@theme/VPLink.vue'
|
||||
import { useRoute } from 'vuepress/client'
|
||||
import { usePostsExtract } from '../../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { isLocal } = defineProps<{
|
||||
isLocal?: boolean
|
||||
}>()
|
||||
|
||||
@ -13,7 +13,7 @@ const { hasPostsExtract, tags, archives, categories } = usePostsExtract()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="hasPostsExtract" class="vp-posts-nav" :class="{ local: props.isLocal }">
|
||||
<div v-if="hasPostsExtract" class="vp-posts-nav" :class="{ local: isLocal }">
|
||||
<VPLink
|
||||
v-if="tags.link"
|
||||
class="nav-link"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
|
||||
defineProps<{
|
||||
const { postList } = defineProps<{
|
||||
postList: {
|
||||
title: string
|
||||
path: string
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import '@vuepress/helper/transition/fade-in.css'
|
||||
|
||||
defineProps<{
|
||||
const { show } = defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@ -9,7 +9,7 @@ import { useRoute } from 'vuepress/client'
|
||||
import { useData, usePostsPageData, useSidebar } from '../composables/index.js'
|
||||
import { inBrowser } from '../utils/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { isNotFound } = defineProps<{
|
||||
isNotFound?: boolean
|
||||
}>()
|
||||
|
||||
@ -43,7 +43,7 @@ watch(
|
||||
<template>
|
||||
<div
|
||||
id="VPContent" vp-content class="vp-content" :class="{
|
||||
'has-sidebar': hasSidebar && !props.isNotFound,
|
||||
'has-sidebar': hasSidebar && !isNotFound,
|
||||
'is-home': frontmatter.pageLayout === 'home',
|
||||
}"
|
||||
>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { useData } from '../composables/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { title, anchor } = defineProps<{
|
||||
title?: string
|
||||
anchor: string
|
||||
}>()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { MenuItem } from '../composables/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { headers, root } = defineProps<{
|
||||
headers: MenuItem[]
|
||||
root?: boolean
|
||||
}>()
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { useData, useEncryptCompare } from '../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { global, info } = defineProps<{
|
||||
global?: boolean
|
||||
info?: string
|
||||
}>()
|
||||
@ -18,7 +18,7 @@ async function onSubmit() {
|
||||
if (unlocking.value)
|
||||
return
|
||||
|
||||
const compare = props.global ? compareGlobal : comparePage
|
||||
const compare = global ? compareGlobal : comparePage
|
||||
unlocking.value = true
|
||||
const result = await compare(password.value)
|
||||
unlocking.value = false
|
||||
|
||||
@ -6,7 +6,7 @@ import VPMenu from '@theme/VPMenu.vue'
|
||||
import { ref } from 'vue'
|
||||
import { useFlyout } from '../composables/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { prefixIcon, icon, button, label, items, badge } = defineProps<{
|
||||
prefixIcon?: ThemeIcon
|
||||
icon?: any
|
||||
button?: string
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { FriendGroup } from '../../shared/index.js'
|
||||
import VPFriendsItem from '@theme/VPFriendsItem.vue'
|
||||
|
||||
defineProps<{
|
||||
const { group } = defineProps<{
|
||||
group: FriendGroup
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@ -6,7 +6,7 @@ import { computed } from 'vue'
|
||||
import { useDarkMode } from '../composables/index.js'
|
||||
import VPSocialLinks from './VPSocialLinks.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { friend } = defineProps<{
|
||||
friend: FriendsItem
|
||||
}>()
|
||||
|
||||
@ -21,9 +21,9 @@ function getStyle(name: string, color?: string | { light: string, dark: string }
|
||||
|
||||
const friendStyle = computed(() => {
|
||||
return {
|
||||
...getStyle('--vp-friends-text-color', props.friend.color),
|
||||
...getStyle('--vp-friends-bg-color', props.friend.backgroundColor),
|
||||
...getStyle('--vp-friends-name-color', props.friend.nameColor),
|
||||
...getStyle('--vp-friends-text-color', friend.color),
|
||||
...getStyle('--vp-friends-bg-color', friend.backgroundColor),
|
||||
...getStyle('--vp-friends-name-color', friend.nameColor),
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -6,7 +6,7 @@ import VPIconImage from '@theme/VPIconImage.vue'
|
||||
import { computed } from 'vue'
|
||||
import { isLinkHttp } from 'vuepress/shared'
|
||||
|
||||
const props = defineProps<{
|
||||
const { provider, name, size, color, extra } = defineProps<{
|
||||
provider?: 'iconify' | 'iconfont' | 'fontawesome'
|
||||
name: string | { svg: string }
|
||||
size?: string | number
|
||||
@ -18,20 +18,20 @@ declare const __MD_POWER_ICON_PROVIDER__: 'iconify' | 'iconfont' | 'fontawesome'
|
||||
declare const __MD_POWER_ICON_PREFIX__: string
|
||||
|
||||
const type = computed(() => {
|
||||
const provider = props.provider || __MD_POWER_ICON_PROVIDER__
|
||||
// name -> https://example.com/icon.svg
|
||||
// name -> /icon.svg
|
||||
if (typeof props.name === 'string' && (isLinkHttp(props.name) || props.name[0] === '/')) {
|
||||
if (typeof name === 'string' && (isLinkHttp(name) || name[0] === '/')) {
|
||||
return 'link'
|
||||
}
|
||||
|
||||
// name -> { svg: '<svg></svg>' }
|
||||
if (typeof props.name === 'object' && !!props.name.svg) {
|
||||
if (typeof name === 'object' && !!name.svg) {
|
||||
return 'svg'
|
||||
}
|
||||
|
||||
if (provider === 'iconfont' || provider === 'fontawesome') {
|
||||
return provider
|
||||
const _provider = provider || __MD_POWER_ICON_PROVIDER__
|
||||
if (_provider === 'iconfont' || _provider === 'fontawesome') {
|
||||
return _provider
|
||||
}
|
||||
|
||||
return 'iconify'
|
||||
@ -43,8 +43,7 @@ function parseSize(size: string | number): string {
|
||||
return String(size)
|
||||
}
|
||||
|
||||
const size = computed(() => {
|
||||
const size = props.size
|
||||
const rect = computed(() => {
|
||||
if (!size)
|
||||
return undefined
|
||||
|
||||
@ -56,9 +55,9 @@ const size = computed(() => {
|
||||
return { width, height: height || width }
|
||||
})
|
||||
const binding = computed(() => ({
|
||||
name: props.name as string,
|
||||
color: props.color,
|
||||
size: size.value,
|
||||
name: name as string,
|
||||
color,
|
||||
size: rect.value,
|
||||
prefix: __MD_POWER_ICON_PREFIX__ as any,
|
||||
}))
|
||||
</script>
|
||||
@ -66,7 +65,7 @@ const binding = computed(() => ({
|
||||
<template>
|
||||
<VPIconImage
|
||||
v-if="type === 'link' || type === 'svg'"
|
||||
:type="type" :name="name" :color="color" :size="size"
|
||||
:type="type" :name="name" :color="color" :size="rect"
|
||||
/>
|
||||
<VPIconfont
|
||||
v-else-if="type === 'iconfont'"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { FontAwesomePrefix } from 'vuepress-plugin-md-power/client'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { name, size, color, prefix, extra } = defineProps<{
|
||||
name: string
|
||||
size?: { width?: string, height?: string }
|
||||
color?: string
|
||||
@ -25,20 +25,19 @@ const configs: Record<string, FontAwesomePrefix[]> = {
|
||||
}
|
||||
|
||||
const iconName = computed(() => {
|
||||
const icon = props.name.includes(':') ? props.name : `${props.prefix || 'fas'}:${props.name}`
|
||||
const [type, name] = icon.split(':')
|
||||
let prefix = 'solid'
|
||||
const icon = name.includes(':') ? name : `${prefix || 'fas'}:${name}`
|
||||
const [type, iconName] = icon.split(':')
|
||||
let _prefix = 'solid'
|
||||
for (const [key, alias] of Object.entries(configs)) {
|
||||
if (alias.includes(type as FontAwesomePrefix)) {
|
||||
prefix = key
|
||||
_prefix = key
|
||||
break
|
||||
}
|
||||
}
|
||||
return `${prefix.split(' ').map(v => `fa-${v.trim()}`).join(' ')} fa-${name}`
|
||||
return `${_prefix.split(' ').map(v => `fa-${v.trim()}`).join(' ')} fa-${iconName}`
|
||||
})
|
||||
|
||||
const extraClasses = computed(() => {
|
||||
const extra = props.extra
|
||||
if (!extra)
|
||||
return []
|
||||
return extra.split(' ').map(v => v.trim().startsWith('fa-') ? v : `fa-${v}`)
|
||||
|
||||
@ -3,7 +3,7 @@ import { computed } from 'vue'
|
||||
import { withBase } from 'vuepress/client'
|
||||
import { isLinkHttp } from 'vuepress/shared'
|
||||
|
||||
const props = defineProps<{
|
||||
const { type, name, color, size } = defineProps<{
|
||||
type: 'link' | 'svg'
|
||||
name: string | { svg: string }
|
||||
color?: string
|
||||
@ -11,14 +11,14 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const svg = computed(() => {
|
||||
if (props.type === 'svg' && typeof props.name === 'object' && 'svg' in props.name) {
|
||||
return props.name.svg
|
||||
if (type === 'svg' && typeof name === 'object' && 'svg' in name) {
|
||||
return name.svg
|
||||
}
|
||||
return ''
|
||||
})
|
||||
const link = computed(() => {
|
||||
if (props.type === 'link') {
|
||||
const link = props.name as string
|
||||
if (type === 'link') {
|
||||
const link = name as string
|
||||
return isLinkHttp(link) ? link : withBase(link)
|
||||
}
|
||||
return ''
|
||||
|
||||
@ -1,20 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { name, size, color, prefix } = defineProps<{
|
||||
name: string
|
||||
size?: { width?: string, height?: string }
|
||||
color?: string
|
||||
prefix?: string
|
||||
}>()
|
||||
|
||||
const prefix = computed(() => props.prefix || 'iconfont icon-')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<i
|
||||
class="vp-icon"
|
||||
:class="`${prefix}${name}`"
|
||||
:class="`${prefix || 'iconfont icon-'}${name}`"
|
||||
:style="{ color, 'font-size': size?.height || '1em' }"
|
||||
data-provider="iconfont"
|
||||
aria-hidden
|
||||
|
||||
@ -9,7 +9,7 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<{
|
||||
const { name, size, color, prefix, extra } = defineProps<{
|
||||
name: string
|
||||
size?: { width?: string, height?: string }
|
||||
color?: string
|
||||
@ -23,10 +23,9 @@ const loaded = ref(false)
|
||||
const iconsData = useIconsData()
|
||||
|
||||
const iconName = computed(() => {
|
||||
const name = props.name
|
||||
if (name.includes(':'))
|
||||
return name
|
||||
return props.prefix ? `${props.prefix}:${name}` : name
|
||||
return prefix ? `${prefix}:${name}` : name
|
||||
})
|
||||
|
||||
const localIconName = computed(() => iconsData.value[iconName.value])
|
||||
@ -37,13 +36,13 @@ async function loadRemoteIcon() {
|
||||
|
||||
if (!localIconName.value) {
|
||||
loaded.value = false
|
||||
icon.value = await loadIcon(props.name)
|
||||
icon.value = await loadIcon(name)
|
||||
}
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
if (!__VUEPRESS_SSR__)
|
||||
watch(() => props.name, loadRemoteIcon, { immediate: true })
|
||||
watch(() => name, loadRemoteIcon, { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -4,13 +4,12 @@ import { computed } from 'vue'
|
||||
import { withBase } from 'vuepress/client'
|
||||
import { numToUnit } from '../utils/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { image, alt } = defineProps<{
|
||||
image: ThemeImage
|
||||
alt?: string
|
||||
}>()
|
||||
|
||||
const styles = computed(() => {
|
||||
const image = props.image
|
||||
if (!image || typeof image === 'string')
|
||||
return ''
|
||||
if (!image.width || !image.height)
|
||||
|
||||
@ -4,7 +4,7 @@ import { useWindowScroll } from '@vueuse/core'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useData, useHeaders, usePostsPageData, useSidebar } from '../composables/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { open, showOutline } = defineProps<{
|
||||
open: boolean
|
||||
showOutline: boolean
|
||||
}>()
|
||||
@ -39,7 +39,7 @@ const classes = computed(() => {
|
||||
'fixed': empty.value,
|
||||
'reached-top': y.value >= navHeight.value,
|
||||
'is-posts': isPosts.value && !isPostsLayout.value,
|
||||
'with-outline': !props.showOutline,
|
||||
'with-outline': !showOutline,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { useData } from '../composables/index.js'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in-scale-up.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { headers, navHeight } = defineProps<{
|
||||
headers: MenuItem[]
|
||||
navHeight: number
|
||||
}>()
|
||||
@ -18,7 +18,7 @@ const vh = ref(0)
|
||||
const items = ref<HTMLDivElement>()
|
||||
const btn = ref<HTMLButtonElement>()
|
||||
|
||||
watch(() => props.headers, () => {
|
||||
watch(() => headers, () => {
|
||||
open.value = false
|
||||
})
|
||||
|
||||
@ -28,7 +28,7 @@ onClickOutside(items, () => {
|
||||
|
||||
function toggle() {
|
||||
open.value = !open.value
|
||||
vh.value = window.innerHeight + Math.min(window.scrollY - props.navHeight, 0)
|
||||
vh.value = window.innerHeight + Math.min(window.scrollY - navHeight, 0)
|
||||
}
|
||||
|
||||
function onItemClick(e: Event) {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import VPMenuGroup from '@theme/VPMenuGroup.vue'
|
||||
import VPMenuLink from '@theme/VPMenuLink.vue'
|
||||
|
||||
defineProps<{
|
||||
const { items } = defineProps<{
|
||||
items?: any[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPMenuLink from '@theme/VPMenuLink.vue'
|
||||
|
||||
defineProps<{
|
||||
const { text, icon, items } = defineProps<{
|
||||
text?: string
|
||||
icon?: string | { svg: string }
|
||||
items: any[]
|
||||
|
||||
@ -6,7 +6,7 @@ import { resolveRouteFullPath } from 'vuepress/client'
|
||||
import { useData } from '../composables/index.js'
|
||||
import { isActive } from '../utils/index.js'
|
||||
|
||||
defineProps<{
|
||||
const { item } = defineProps<{
|
||||
item: any
|
||||
}>()
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { useRoutePath } from 'vuepress/client'
|
||||
import { useData, useSidebar } from '../composables/index.js'
|
||||
import { inBrowser } from '../utils/index.js'
|
||||
|
||||
const props = defineProps<{
|
||||
const { open } = defineProps<{
|
||||
open: boolean
|
||||
}>()
|
||||
|
||||
@ -20,9 +20,9 @@ const navEl = ref<HTMLElement | null>(null)
|
||||
const isLocked = useScrollLock(inBrowser ? document.body : null)
|
||||
|
||||
watch(
|
||||
[() => props.open, navEl],
|
||||
[() => open, navEl],
|
||||
() => {
|
||||
if (props.open) {
|
||||
if (open) {
|
||||
isLocked.value = true
|
||||
navEl.value?.focus()
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import type { ResolvedSidebarItem } from '../../shared/index.js'
|
||||
import VPSidebarItem from '@theme/VPSidebarItem.vue'
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
const { items } = defineProps<{
|
||||
items: ResolvedSidebarItem[]
|
||||
}>()
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import { useSidebarControl } from '../composables/index.js'
|
||||
|
||||
import '@vuepress/helper/transition/fade-in-height-expand.css'
|
||||
|
||||
const props = defineProps<{
|
||||
const { item, depth } = defineProps<{
|
||||
item: ResolvedSidebarItem
|
||||
depth: number
|
||||
}>()
|
||||
@ -22,7 +22,7 @@ const {
|
||||
hasActiveLink,
|
||||
hasChildren,
|
||||
toggle,
|
||||
} = useSidebarControl(computed(() => props.item))
|
||||
} = useSidebarControl(computed(() => item))
|
||||
|
||||
const sectionTag = computed(() => (hasChildren.value ? 'section' : `div`))
|
||||
|
||||
@ -31,17 +31,17 @@ const linkTag = computed(() => (isLink.value ? 'a' : 'div'))
|
||||
const textTag = computed(() => {
|
||||
return !hasChildren.value
|
||||
? 'p'
|
||||
: props.depth + 2 === 7
|
||||
: depth + 2 === 7
|
||||
? 'p'
|
||||
: `h${props.depth + 2}`
|
||||
: `h${depth + 2}`
|
||||
})
|
||||
|
||||
const itemRole = computed(() => (isLink.value ? undefined : 'button'))
|
||||
|
||||
const isSeparator = computed(() => props.item.link?.startsWith('---'))
|
||||
const isSeparator = computed(() => item.link?.startsWith('---'))
|
||||
|
||||
const classes = computed(() => [
|
||||
[`level-${props.depth}`],
|
||||
[`level-${depth}`],
|
||||
{ collapsible: collapsible.value },
|
||||
{ collapsed: collapsed.value },
|
||||
{ 'is-link': isLink.value },
|
||||
@ -53,13 +53,13 @@ function onItemInteraction(e: MouseEvent | Event) {
|
||||
if ('key' in e && e.key !== 'Enter')
|
||||
return
|
||||
|
||||
if (!props.item.link) {
|
||||
if (!item.link) {
|
||||
toggle()
|
||||
}
|
||||
}
|
||||
|
||||
function onCaretClick() {
|
||||
if (props.item.link) {
|
||||
if (item.link) {
|
||||
toggle()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,16 @@
|
||||
import type { SocialLinkIcon } from '../../shared/index.js'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { icon, link, ariaLabel } = defineProps<{
|
||||
icon: SocialLinkIcon
|
||||
link: string
|
||||
ariaLabel?: string
|
||||
}>()
|
||||
|
||||
const svg = computed(() => {
|
||||
if (typeof props.icon === 'object')
|
||||
return props.icon.svg
|
||||
return `<span class="vpi-social-${props.icon}" />`
|
||||
if (typeof icon === 'object')
|
||||
return icon.svg
|
||||
return `<span class="vpi-social-${icon}" />`
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { SocialLink as SocialLinkType } from '../../shared/index.js'
|
||||
import VPSocialLink from '@theme/VPSocialLink.vue'
|
||||
|
||||
defineProps<{
|
||||
const { links } = defineProps<{
|
||||
links: SocialLinkType[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@ -7,10 +7,7 @@ interface Props {
|
||||
duration?: number
|
||||
appear?: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
delay: 0,
|
||||
duration: 0.25,
|
||||
})
|
||||
const { delay = 0, duration = 0.25, appear } = defineProps<Props>()
|
||||
|
||||
const { theme } = useData()
|
||||
|
||||
@ -36,7 +33,7 @@ function setStyle(item: Element) {
|
||||
_transition = value && !value.includes('all') ? `${value || ''}, ` : ' '
|
||||
}
|
||||
|
||||
el.style.transition = `${_transition}transform ${props.duration}s ease-in-out ${props.delay}s, opacity ${props.duration}s ease-in-out ${props.delay}s`
|
||||
el.style.transition = `${_transition}transform ${duration}s ease-in-out ${delay}s, opacity ${duration}s ease-in-out ${delay}s`
|
||||
}
|
||||
|
||||
function unsetStyle(item: Element) {
|
||||
|
||||
@ -2,17 +2,14 @@
|
||||
import type { ThemeBadge } from '../../../shared/index.js'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<ThemeBadge>(), {
|
||||
type: 'tip',
|
||||
borderColor: 'transparent',
|
||||
})
|
||||
const { type = 'tip', text, color, bgColor, borderColor = 'transparent' } = defineProps<ThemeBadge>()
|
||||
|
||||
const customStyle = computed(() => {
|
||||
if (props.color || props.bgColor) {
|
||||
if (color || bgColor) {
|
||||
return {
|
||||
color: props.color,
|
||||
backgroundColor: props.bgColor,
|
||||
borderColor: props.borderColor,
|
||||
color,
|
||||
backgroundColor: bgColor,
|
||||
borderColor,
|
||||
}
|
||||
}
|
||||
return {}
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { title, icon = '' } = defineProps<{
|
||||
title?: string
|
||||
icon?: string | { svg: string }
|
||||
}>()
|
||||
|
||||
const icon = computed<string | { svg: string } | undefined>(() => {
|
||||
if (props.icon?.[0] === '{') {
|
||||
const iconName = computed<string | { svg: string }>(() => {
|
||||
if (typeof icon === 'string' && icon?.[0] === '{') {
|
||||
try {
|
||||
return JSON.parse(icon) as { svg: string }
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
return props.icon
|
||||
return icon
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -22,7 +22,7 @@ const icon = computed<string | { svg: string } | undefined>(() => {
|
||||
<article class="vp-card-wrapper">
|
||||
<slot name="title">
|
||||
<p v-if="title || icon" class="title">
|
||||
<VPIcon v-if="icon" :name="icon" />
|
||||
<VPIcon v-if="icon" :name="iconName" />
|
||||
<span v-if="title" class="text" v-html="title" />
|
||||
</p>
|
||||
</slot>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { useMediaQuery } from '@vueuse/core'
|
||||
import { onMounted, ref, toValue, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
const { cols } = defineProps<{
|
||||
cols?: string | number | { sm?: number, md?: number, lg?: number }
|
||||
}>()
|
||||
|
||||
@ -12,13 +12,13 @@ const repeat = ref(1)
|
||||
|
||||
function resolveCols() {
|
||||
const reset = { sm: 1, md: 2, lg: 2 }
|
||||
if (!props.cols)
|
||||
if (!cols)
|
||||
return reset
|
||||
if (typeof props.cols === 'number' || typeof props.cols === 'string') {
|
||||
const cols = Number(props.cols)
|
||||
return { sm: cols, md: cols, lg: cols }
|
||||
if (typeof cols === 'number' || typeof cols === 'string') {
|
||||
const res = Number(cols)
|
||||
return { sm: res, md: res, lg: res }
|
||||
}
|
||||
return { ...reset, ...toValue(props.cols) }
|
||||
return { ...reset, ...toValue(cols) }
|
||||
}
|
||||
|
||||
function getRepeat() {
|
||||
@ -30,7 +30,7 @@ function getRepeat() {
|
||||
return cols.sm
|
||||
}
|
||||
|
||||
watch(() => [md.value, lg.value, props.cols], () => {
|
||||
watch([md, lg, () => cols], () => {
|
||||
repeat.value = getRepeat()
|
||||
})
|
||||
|
||||
|
||||
@ -3,13 +3,10 @@ import type { VNode } from 'vue'
|
||||
import { useDebounceFn, useMediaQuery, useResizeObserver } from '@vueuse/core'
|
||||
import { cloneVNode, computed, markRaw, mergeProps, nextTick, onMounted, ref, shallowRef, useId, watch } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const { cols = { sm: 2, md: 2, lg: 3 }, gap = 16 } = defineProps<{
|
||||
cols?: number | { sm?: number, md?: number, lg?: number }
|
||||
gap?: number
|
||||
}>(), {
|
||||
cols: () => ({ sm: 2, md: 2, lg: 3 }),
|
||||
gap: 16,
|
||||
})
|
||||
}>()
|
||||
|
||||
const slots = defineSlots<{ default: () => VNode[] | null }>()
|
||||
const uuid = useId()
|
||||
@ -29,16 +26,16 @@ const rawList = computed(() => {
|
||||
|
||||
function resolveColumnsLength() {
|
||||
let length = 1
|
||||
if (typeof props.cols === 'number') {
|
||||
length = props.cols
|
||||
if (typeof cols === 'number') {
|
||||
length = cols
|
||||
}
|
||||
else if (typeof props.cols === 'object') {
|
||||
else if (typeof cols === 'object') {
|
||||
if (isLg.value)
|
||||
length = props.cols.lg || 3
|
||||
length = cols.lg || 3
|
||||
else if (isMd.value)
|
||||
length = props.cols.md || 2
|
||||
length = cols.md || 2
|
||||
else
|
||||
length = props.cols.sm || 2
|
||||
length = cols.sm || 2
|
||||
}
|
||||
|
||||
columnsLength.value = Number(length)
|
||||
@ -62,7 +59,7 @@ async function drawColumns() {
|
||||
const index = heights.indexOf(Math.min(...heights))
|
||||
|
||||
columns[index].push(item)
|
||||
heights[index] += height + props.gap
|
||||
heights[index] += height + gap
|
||||
}
|
||||
columnsList.value = columns
|
||||
}
|
||||
@ -71,7 +68,7 @@ onMounted(() => {
|
||||
if (__VUEPRESS_SSR__)
|
||||
return
|
||||
|
||||
watch(() => [isMd.value, isLg.value, props.cols], resolveColumnsLength, { immediate: true })
|
||||
watch([isMd, isLg, () => cols], resolveColumnsLength, { immediate: true })
|
||||
|
||||
drawColumns()
|
||||
const debounceDraw = useDebounceFn(drawColumns)
|
||||
@ -81,9 +78,9 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="masonry" class="vp-card-masonry" :class="[`cols-${columnsLength}`]" :style="{ 'grid-gap': `${props.gap}px`, '--card-masonry-cols': columnsLength }" data-allow-mismatch>
|
||||
<div ref="masonry" class="vp-card-masonry" :class="[`cols-${columnsLength}`]" :style="{ 'grid-gap': `${gap}px`, '--card-masonry-cols': columnsLength }" data-allow-mismatch>
|
||||
<ClientOnly>
|
||||
<div v-for="(column, index) in columnsList" :key="`${uuid}-${index}`" class="card-masonry-item" :style="{ gap: `${props.gap}px` }">
|
||||
<div v-for="(column, index) in columnsList" :key="`${uuid}-${index}`" class="card-masonry-item" :style="{ gap: `${gap}px` }">
|
||||
<component :is="item" v-for="item in column" :key="item.props!.class" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { usePageLang, withBase } from 'vuepress/client'
|
||||
|
||||
const props = defineProps<{
|
||||
const { image, title, description, href, author, date, width, center } = defineProps<{
|
||||
image: string
|
||||
title?: string
|
||||
description?: string
|
||||
@ -15,42 +15,40 @@ const props = defineProps<{
|
||||
|
||||
const lang = usePageLang()
|
||||
|
||||
const date = computed(() => {
|
||||
if (!props.date)
|
||||
const dateStr = computed(() => {
|
||||
if (!date)
|
||||
return ''
|
||||
const date = props.date instanceof Date ? props.date : new Date(props.date)
|
||||
const instance = date instanceof Date ? date : new Date(date)
|
||||
const intl = new Intl.DateTimeFormat(
|
||||
lang.value,
|
||||
{ year: 'numeric', month: 'short', day: 'numeric' },
|
||||
)
|
||||
|
||||
return intl.format(date)
|
||||
return intl.format(instance)
|
||||
})
|
||||
|
||||
const styles = computed(() => {
|
||||
const width = props.width
|
||||
? String(Number(props.width)) === String(props.width)
|
||||
? `${props.width}px`
|
||||
: props.width
|
||||
: undefined
|
||||
|
||||
return { width }
|
||||
})
|
||||
const styles = computed(() => ({
|
||||
width: width
|
||||
? String(Number(width)) === String(width)
|
||||
? `${width}px`
|
||||
: width
|
||||
: undefined,
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-image-card" :style="styles" :class="{ center }">
|
||||
<div class="image-container">
|
||||
<img :src="withBase(image)" :alt="title" loading="lazy">
|
||||
<div v-if="title || author || date || description" class="image-info">
|
||||
<div v-if="title || author || dateStr || description" class="image-info">
|
||||
<h3 v-if="title" class="title">
|
||||
<a v-if="href" :href="href" target="_blank" rel="noopener noreferrer" class="no-icon">{{ title }}</a>
|
||||
<span v-else>{{ title }}</span>
|
||||
</h3>
|
||||
<p v-if="author || date" class="copyright">
|
||||
<span v-if="author">{{ author }}</span>
|
||||
<span v-if="author && date"> | </span>
|
||||
<span v-if="date">{{ date }}</span>
|
||||
<span v-if="author && dateStr"> | </span>
|
||||
<span v-if="dateStr">{{ dateStr }}</span>
|
||||
</p>
|
||||
<p v-if="description" class="description">
|
||||
{{ description }}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import VPIcon from '@theme/VPIcon.vue'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
|
||||
defineProps<{
|
||||
const { href, title, icon, description, target, rel } = defineProps<{
|
||||
href: string
|
||||
title?: string
|
||||
icon?: string | { svg: string }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user