valaxy 0.26.12 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import type { Ref } from 'vue'
2
2
  import type { Router } from 'vue-router'
3
- import type { PageData } from '../../types'
3
+ import type { PageData, Post } from '../../types'
4
4
  import { computed } from 'vue'
5
5
 
6
6
  export interface ValaxyData<FM = PageData['frontmatter']> {
@@ -16,6 +16,6 @@ export function initData(router: Router): ValaxyData {
16
16
  page: computed(() => (router.currentRoute.value as unknown as {
17
17
  data: PageData
18
18
  }).data),
19
- frontmatter: computed(() => router.currentRoute.value.meta.frontmatter),
19
+ frontmatter: computed(() => router.currentRoute.value.meta.frontmatter!) as Ref<Post>,
20
20
  }
21
21
  }
@@ -1,6 +1,6 @@
1
1
  import type { UseDarkOptions } from '@vueuse/core'
2
2
  import { useDark, useToggle } from '@vueuse/core'
3
- import { computed } from 'vue'
3
+ import { computed, nextTick } from 'vue'
4
4
 
5
5
  export function useValaxyDark(options: {
6
6
  /**
@@ -31,8 +31,12 @@ export function useValaxyDark(options: {
31
31
  if (options.circleTransition)
32
32
  import('valaxy/client/styles/common/view-transition.css')
33
33
 
34
+ const enableTransitions = () =>
35
+ 'startViewTransition' in document
36
+ && window.matchMedia('(prefers-reduced-motion: no-preference)').matches
37
+
34
38
  function toggleDarkWithTransition(event: MouseEvent, options: { duration?: number, easing?: EffectTiming['easing'] } = {}) {
35
- if (!document.startViewTransition) {
39
+ if (!enableTransitions()) {
36
40
  toggleDark()
37
41
  return
38
42
  }
@@ -44,23 +48,26 @@ export function useValaxyDark(options: {
44
48
  Math.max(y, innerHeight - y),
45
49
  )
46
50
 
47
- const transition = document.startViewTransition(() => {
51
+ const clipPath = [
52
+ `circle(0px at ${x}px ${y}px)`,
53
+ `circle(${endRadius}px at ${x}px ${y}px)`,
54
+ ]
55
+
56
+ const transition = document.startViewTransition(async () => {
48
57
  toggleDark()
58
+ await nextTick()
49
59
  })
50
60
 
51
61
  transition.ready.then(() => {
52
- const clipPath = [
53
- `circle(0px at ${x}px ${y}px)`,
54
- `circle(${endRadius}px at ${x}px ${y}px)`,
55
- ]
56
62
  document.documentElement.animate(
57
63
  {
58
- clipPath: isDark.value ? clipPath.reverse() : clipPath,
64
+ clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
59
65
  },
60
66
  {
61
- duration: options.duration || 300,
62
- easing: options.easing || 'ease-in',
63
- pseudoElement: isDark.value ? '::view-transition-old(root)' : '::view-transition-new(root)',
67
+ duration: options.duration ?? 200,
68
+ easing: options.easing ?? 'ease-in',
69
+ fill: 'forwards',
70
+ pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`,
64
71
  },
65
72
  )
66
73
  })
@@ -1,4 +1,4 @@
1
- import type { Post } from 'valaxy'
1
+ import type { Post, SiteConfig } from 'valaxy'
2
2
  import type { ComputedRef } from 'vue'
3
3
  import { orderByMeta, useSiteConfig } from 'valaxy'
4
4
  import { computed } from 'vue'
@@ -37,6 +37,39 @@ export function usePageList() {
37
37
  })
38
38
  }
39
39
 
40
+ /**
41
+ * Pure function to filter and sort posts from page list
42
+ * Can be used in both composables and stores without inject() issues
43
+ */
44
+ export function filterAndSortPosts(
45
+ pages: Post[],
46
+ siteConfig: SiteConfig,
47
+ params: { type?: string } = {},
48
+ ): Post[] {
49
+ // Filter posts
50
+ const routes = pages
51
+ .filter(i =>
52
+ i.path?.startsWith('/posts')
53
+ && !i.path?.endsWith('.html')
54
+ && i.date
55
+ && (!params.type || i.type === params.type)
56
+ && (!i.hide || i.hide === 'index'), // hide `hide: all` posts
57
+ )
58
+
59
+ function sortBySiteConfigOrderBy(posts: Post[]) {
60
+ const orderBy = siteConfig.orderBy
61
+ return orderByMeta(posts, orderBy)
62
+ }
63
+
64
+ /**
65
+ * 置顶
66
+ */
67
+ const topPosts = sortBySiteConfigOrderBy(routes.filter(i => i.top)).sort((a, b) => b.top! - a.top!)
68
+ const otherPosts = sortBySiteConfigOrderBy(routes.filter(i => !i.top))
69
+
70
+ return topPosts.concat(otherPosts)
71
+ }
72
+
40
73
  /**
41
74
  * get post list in 'pages/posts' folder
42
75
  * todo: use vue provide/inject to global
@@ -47,26 +80,6 @@ export function usePostList(params: {
47
80
  const siteConfig = useSiteConfig()
48
81
  const pageList = usePageList()
49
82
  return computed(() => {
50
- const routes = pageList.value
51
- .filter(i =>
52
- i.path?.startsWith('/posts')
53
- && !i.path?.endsWith('.html')
54
- && i.date
55
- && (!params.type || i.type === params.type)
56
- && (!i.hide || i.hide === 'index'), // hide `hide: all` posts
57
- )
58
-
59
- function sortBySiteConfigOrderBy(posts: Post[]) {
60
- const orderBy = siteConfig.value.orderBy
61
- return orderByMeta(posts, orderBy)
62
- }
63
-
64
- /**
65
- * 置顶
66
- */
67
- const topPosts = sortBySiteConfigOrderBy(routes.filter(i => i.top)).sort((a, b) => b.top! - a.top!)
68
- const otherPosts = sortBySiteConfigOrderBy(routes.filter(i => !i.top))
69
-
70
- return topPosts.concat(otherPosts)
83
+ return filterAndSortPosts(pageList.value, siteConfig.value, params)
71
84
  })
72
85
  }
package/client/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { Header } from '@valaxyjs/utils'
2
1
  import type { Ref } from 'vue'
3
2
  import type { Post } from '../types'
4
3
 
5
4
  import './shims.d'
5
+ // Import vue-router RouteMeta augmentation
6
+ import '../types/vue-router.d'
6
7
 
7
8
  export * from '../dist/types/index.mjs'
8
9
  export * from './index'
@@ -12,13 +13,6 @@ declare module '@docsearch/js' {
12
13
  export default docsearch
13
14
  }
14
15
 
15
- declare module 'vue-router' {
16
- interface RouteMeta {
17
- headers: Header[]
18
- frontmatter: Post
19
- }
20
- }
21
-
22
16
  declare interface Window {
23
17
  // for devtools
24
18
  __VUE_DEVTOOLS_ROUTER__: import('vue-router').Router
package/client/main.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders'
2
1
  import { dataSymbol, initValaxyConfig, valaxyConfigSymbol } from 'valaxy'
3
2
  import { setupLayouts } from 'virtual:generated-layouts'
4
3
  import { ViteSSG } from 'vite-ssg'
5
-
6
4
  import { routes as autoRoutes } from 'vue-router/auto-routes'
5
+
7
6
  // import App from '/@valaxyjs/App.vue'
8
7
  import App from './App.vue'
9
8
 
@@ -70,8 +69,10 @@ export const createApp = ViteSSG(
70
69
  const data = initData(router)
71
70
  app.provide(dataSymbol, data)
72
71
 
73
- // Register the plugin before the router
74
- app.use(DataLoaderPlugin, { router })
72
+ // Note: DataLoaderPlugin is not compatible with vite-ssg because vite-ssg
73
+ // calls this callback BEFORE app.use(router), but DataLoaderPlugin requires
74
+ // the router to be installed first for useRouter()/useRoute() to work.
75
+ // The page data is loaded via route.meta.frontmatter instead.
75
76
 
76
77
  app.provide(valaxyConfigSymbol, valaxyConfig)
77
78
 
@@ -1,5 +1,6 @@
1
1
  import type { UserModule } from '../types'
2
2
 
3
+ import { normalizeRepositoryUrl } from '@valaxyjs/utils'
3
4
  import pkg from '../../package.json'
4
5
  import valaxyLogo from '../assets/images/valaxy-logo.png'
5
6
 
@@ -39,7 +40,7 @@ export async function addValaxyTabAndCommand() {
39
40
  icon: 'i-ri-github-fill',
40
41
  action: {
41
42
  type: 'url',
42
- src: pkg.repository.url,
43
+ src: normalizeRepositoryUrl(pkg.repository.url),
43
44
  },
44
45
  },
45
46
  {
@@ -1,7 +1,7 @@
1
1
  import type { PageDataPayload } from '../../types'
2
2
  import { acceptHMRUpdate, defineStore } from 'pinia'
3
3
  import { computed, ref } from 'vue'
4
- import { usePostList, useRouterStore } from '..'
4
+ import { filterAndSortPosts, usePageList, useRouterStore, useSiteConfig } from '..'
5
5
  import { setWindowValaxyProp } from '../utils/dev'
6
6
 
7
7
  /**
@@ -14,14 +14,19 @@ export const useSiteStore = defineStore('site', () => {
14
14
  const routerStore = useRouterStore()
15
15
  const router = routerStore.router
16
16
 
17
+ // Get siteConfig once during store initialization to avoid inject() issues during HMR
18
+ const siteConfig = useSiteConfig()
19
+ const pageList = usePageList()
20
+
17
21
  const reload = ref(1)
18
22
  // for dev hot reload
19
23
  const postList = computed(() => {
20
- const val = usePostList().value
21
- if (reload.value && val)
22
- return val
23
- else
24
- return val
24
+ // Touch reload.value to trigger reactivity on HMR
25
+ // eslint-disable-next-line ts/no-unused-expressions
26
+ reload.value
27
+
28
+ // Reuse the same filter and sort logic as usePostList
29
+ return filterAndSortPosts(pageList.value, siteConfig.value)
25
30
  })
26
31
 
27
32
  // const postList = usePostList()
@@ -5,17 +5,12 @@
5
5
  mix-blend-mode: normal;
6
6
  }
7
7
 
8
- /* 进入dark模式和退出dark模式时,两个图像的位置顺序正好相反 */
9
- .dark::view-transition-old(root) {
10
- z-index: 9999;
11
- }
8
+ ::view-transition-old(root),
12
9
  .dark::view-transition-new(root) {
13
10
  z-index: 1;
14
11
  }
15
12
 
16
- ::view-transition-old(root) {
17
- z-index: 1;
18
- }
19
- ::view-transition-new(root) {
13
+ ::view-transition-new(root),
14
+ .dark::view-transition-old(root) {
20
15
  z-index: 9999;
21
- }
16
+ }
@@ -6,7 +6,6 @@
6
6
  "valaxy": ["./index.d.ts"]
7
7
  },
8
8
  "types": [
9
- "unplugin-vue-router/client",
10
9
  "vite/client",
11
10
  "vite-plugin-vue-layouts/client",
12
11
  "@intlify/unplugin-vue-i18n/messages"
@@ -1,7 +1,7 @@
1
1
  import 'node:process';
2
2
  import 'yargs';
3
3
  import 'yargs/helpers';
4
- export { c as cli, d as registerDevCommand, r as run, a as startValaxyDev } from '../../shared/valaxy.DsB_W1aR.mjs';
4
+ export { c as cli, D as registerDevCommand, S as run, U as startValaxyDev } from '../../shared/valaxy.DpV6HHc6.mjs';
5
5
  import 'node:os';
6
6
  import 'node:path';
7
7
  import 'consola';
@@ -22,6 +22,7 @@ import 'ora';
22
22
  import 'cross-spawn';
23
23
  import 'mlly';
24
24
  import 'resolve-global';
25
+ import '@valaxyjs/utils';
25
26
  import 'node:fs/promises';
26
27
  import 'dayjs';
27
28
  import 'feed';
@@ -56,7 +57,7 @@ import 'unocss';
56
57
  import 'pascalcase';
57
58
  import 'lru-cache';
58
59
  import 'html-to-text';
59
- import 'unplugin-vue-router/vite';
60
+ import 'vue-router/vite';
60
61
  import '@clack/prompts';
61
62
  import 'node:net';
62
63
  import 'node:child_process';
@@ -1,19 +1,19 @@
1
1
  import { ViteSSGOptions } from 'vite-ssg';
2
2
  import * as vite from 'vite';
3
3
  import { UserConfig, InlineConfig, ViteDevServer, PluginOption, Plugin } from 'vite';
4
+ import { D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, S as SiteConfig, U as UserSiteConfig } from '../shared/valaxy._i636HSR.mjs';
4
5
  import Vue from '@vitejs/plugin-vue';
5
- import { Options as Options$2 } from 'beasties';
6
+ import { Options as Options$1 } from 'beasties';
6
7
  import { Hookable } from 'hookable';
7
8
  import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
8
9
  import { presetWind4, presetAttributify, presetIcons, presetTypography } from 'unocss';
9
10
  import { VitePluginConfig } from 'unocss/vite';
10
11
  import Components from 'unplugin-vue-components/vite';
11
12
  import Markdown from 'unplugin-vue-markdown/vite';
12
- import { EditableTreeNode } from 'unplugin-vue-router';
13
- import Router from 'unplugin-vue-router/vite';
14
13
  import Layouts from 'vite-plugin-vue-layouts';
15
- import { Options as Options$1 } from 'vitepress-plugin-group-icons';
16
- import { D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, S as SiteConfig, U as UserSiteConfig } from '../shared/valaxy.gqLhCu14.mjs';
14
+ import { groupIconVitePlugin } from 'vitepress-plugin-group-icons';
15
+ import { EditableTreeNode } from 'vue-router/unplugin';
16
+ import Router from 'vue-router/vite';
17
17
  import { MarkdownEnv } from 'unplugin-vue-markdown/types';
18
18
  import { KatexOptions } from 'katex';
19
19
  import MarkdownIt from 'markdown-it';
@@ -23,6 +23,7 @@ import { ThemeRegistration, BuiltinTheme, LanguageInput, ShikiTransformer, Highl
23
23
  export { cli, registerDevCommand, run, startValaxyDev } from './cli/index.mjs';
24
24
  import { Awaitable } from '@antfu/utils';
25
25
  import * as defu from 'defu';
26
+ import '@valaxyjs/utils';
26
27
  import '@vueuse/integrations/useFuse';
27
28
  import 'medium-zoom';
28
29
  import 'vanilla-lazyload';
@@ -557,6 +558,12 @@ interface ValaxyExtendConfig {
557
558
  * @default false
558
559
  */
559
560
  fullText: boolean;
561
+ /**
562
+ * @zh 从构建后的 HTML 中提取图片路径(用于解析 Vite 打包后的 hash 文件名)
563
+ * @en Extract image paths from built HTML files (to resolve Vite hashed filenames)
564
+ * @default true
565
+ */
566
+ extractImagePathsFromHTML: boolean;
560
567
  };
561
568
  };
562
569
  /**
@@ -626,7 +633,7 @@ interface ValaxyExtendConfig {
626
633
  /**
627
634
  * @see https://github.com/yuyinws/vitepress-plugin-group-icons
628
635
  */
629
- groupIcons?: Partial<Options$1>;
636
+ groupIcons?: Partial<NonNullable<Parameters<typeof groupIconVitePlugin>[0]>>;
630
637
  /**
631
638
  * unocss presets
632
639
  * @see https://unocss.dev/guide/presets
@@ -703,7 +710,7 @@ interface ValaxyExtendConfig {
703
710
  * beastiesOptions
704
711
  * @see https://github.com/danielroe/beasties
705
712
  */
706
- beastiesOptions?: Options$2;
713
+ beastiesOptions?: Options$1;
707
714
  }
708
715
  type ValaxyApp = ReturnType<typeof createValaxyNode>;
709
716
 
@@ -1,4 +1,4 @@
1
- export { C as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, N as createServer, L as createValaxyPlugin, D as customElements, j as defaultSiteConfig, w as defaultValaxyConfig, F as defaultViteConfig, h as defineAddon, y as defineConfig, k as defineSiteConfig, u as defineTheme, f as defineValaxyAddon, x as defineValaxyConfig, t as defineValaxyTheme, O as encryptContent, g as generateClientRedirects, Q as getGitTimestamp, e as getIndexHtml, M as getServerInfoText, R as isExternal, U as isInstalledGlobally, S as isPath, v as loadConfigFromFile, A as mergeValaxyConfig, m as mergeViteConfigs, p as postProcessForSSG, I as processValaxyOptions, d as registerDevCommand, i as resolveAddonsConfig, Y as resolveImportPath, W as resolveImportUrl, J as resolveOptions, n as resolveSiteConfig, l as resolveSiteConfigFromRoot, o as resolveThemeConfigFromRoot, K as resolveThemeValaxyConfig, q as resolveUserThemeConfig, B as resolveValaxyConfig, z as resolveValaxyConfigFromRoot, r as run, s as ssgBuild, a as startValaxyDev, X as toAtFS, T as transformObject, H as version } from '../shared/valaxy.DsB_W1aR.mjs';
1
+ export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as generateClientRedirects, r as getGitTimestamp, s as getIndexHtml, t as getServerInfoText, u as isExternal, v as isInstalledGlobally, w as isPath, x as loadConfigFromFile, y as mergeValaxyConfig, z as mergeViteConfigs, B as postProcessForSSG, C as processValaxyOptions, D as registerDevCommand, F as resolveAddonsConfig, H as resolveImportPath, I as resolveImportUrl, J as resolveOptions, K as resolveSiteConfig, L as resolveSiteConfigFromRoot, M as resolveThemeConfigFromRoot, N as resolveThemeValaxyConfig, O as resolveUserThemeConfig, Q as resolveValaxyConfig, R as resolveValaxyConfigFromRoot, S as run, T as ssgBuild, U as startValaxyDev, W as toAtFS, X as transformObject, Y as version } from '../shared/valaxy.DpV6HHc6.mjs';
2
2
  import 'node:path';
3
3
  import 'fs-extra';
4
4
  import 'consola/utils';
@@ -22,6 +22,7 @@ import 'ora';
22
22
  import 'cross-spawn';
23
23
  import 'mlly';
24
24
  import 'resolve-global';
25
+ import '@valaxyjs/utils';
25
26
  import 'node:fs/promises';
26
27
  import 'dayjs';
27
28
  import 'feed';
@@ -56,7 +57,7 @@ import 'unocss';
56
57
  import 'pascalcase';
57
58
  import 'lru-cache';
58
59
  import 'html-to-text';
59
- import 'unplugin-vue-router/vite';
60
+ import 'vue-router/vite';
60
61
  import '@clack/prompts';
61
62
  import 'node:net';
62
63
  import 'node:child_process';
@@ -21,6 +21,7 @@ import ora from 'ora';
21
21
  import { spawn } from 'cross-spawn';
22
22
  import { resolvePath } from 'mlly';
23
23
  import { resolveGlobal } from 'resolve-global';
24
+ import { normalizeRepositoryUrl } from '@valaxyjs/utils';
24
25
  import { readFile } from 'node:fs/promises';
25
26
  import dayjs from 'dayjs';
26
27
  import { Feed } from 'feed';
@@ -55,13 +56,13 @@ import { transformerDirectives, transformerVariantGroup, presetWind4, presetAttr
55
56
  import pascalCase from 'pascalcase';
56
57
  import { LRUCache } from 'lru-cache';
57
58
  import { convert } from 'html-to-text';
58
- import VueRouter from 'unplugin-vue-router/vite';
59
+ import VueRouter from 'vue-router/vite';
59
60
  import { intro, confirm, select, outro } from '@clack/prompts';
60
61
  import net from 'node:net';
61
62
  import { exec } from 'node:child_process';
62
63
  import * as readline from 'node:readline';
63
64
  import qrcode from 'qrcode';
64
- import { render } from 'ejs';
65
+ import ejs from 'ejs';
65
66
 
66
67
  const EXCERPT_SEPARATOR = "<!-- more -->";
67
68
  const PATHNAME_PROTOCOL_RE = /^pathname:\/\//;
@@ -323,10 +324,10 @@ const EXCLUDE = [
323
324
  "/@valaxyjs/locales",
324
325
  "/@valaxyjs/styles",
325
326
  /**
326
- * unplugin-vue-router
327
+ * vue-router data loaders
327
328
  * exclude to avoid vite optimize, will make Symbol('loaderEntries') valid
328
329
  */
329
- "unplugin-vue-router/data-loaders/basic"
330
+ "vue-router/experimental"
330
331
  ];
331
332
  function createConfigPlugin(options) {
332
333
  const addonDeps = options.addons.map((i) => Object.keys(i.pkg.dependencies || {})).flat();
@@ -1599,7 +1600,7 @@ async function setupMarkdownPlugins(md, options, base = "/") {
1599
1600
  return md;
1600
1601
  }
1601
1602
 
1602
- const version = "0.26.12";
1603
+ const version = "0.27.0";
1603
1604
 
1604
1605
  const GLOBAL_STATE = {
1605
1606
  valaxyApp: void 0,
@@ -2134,7 +2135,8 @@ const defaultValaxyConfig = {
2134
2135
  modules: {
2135
2136
  rss: {
2136
2137
  enable: true,
2137
- fullText: false
2138
+ fullText: false,
2139
+ extractImagePathsFromHTML: true
2138
2140
  }
2139
2141
  },
2140
2142
  features: {
@@ -2378,7 +2380,9 @@ async function parseAddons(addons, userRoot = process.cwd()) {
2378
2380
  spinner.succeed();
2379
2381
  const resolvedAddons = Object.values(resolvers).filter((item) => item.enable);
2380
2382
  resolvedAddons.forEach((addon, i) => {
2381
- console.log(` ${i === resolvedAddons.length - 1 ? "\u2514\u2500" : "\u251C\u2500"} ${colors.yellow(addon.name)} ${colors.blue(`v${addon.pkg?.version}`)}${addon.global ? colors.cyan(" (global)") : ""} ${colors.dim(addon.pkg.homepage || addon.pkg.repository?.url || addon.pkg.repository || "")}`);
2383
+ const repoUrl = addon.pkg.repository?.url || addon.pkg.repository;
2384
+ const displayUrl = typeof repoUrl === "string" ? normalizeRepositoryUrl(repoUrl) : repoUrl;
2385
+ console.log(` ${i === resolvedAddons.length - 1 ? "\u2514\u2500" : "\u251C\u2500"} ${colors.yellow(addon.name)} ${colors.blue(`v${addon.pkg?.version}`)}${addon.global ? colors.cyan(" (global)") : ""} ${colors.dim(addon.pkg.homepage || displayUrl || "")}`);
2382
2386
  });
2383
2387
  return resolvedAddons;
2384
2388
  }
@@ -2928,10 +2932,12 @@ function genProvideCode(name, data) {
2928
2932
  }
2929
2933
  const encryptedKeys = ["encryptedContent", "partiallyEncryptedContents", "encryptedPhotos"];
2930
2934
  function injectPageDataCode(pageData) {
2935
+ const staticPageData = transformObject(pageData);
2931
2936
  const vueContextImports = [
2932
- `import { provide } from 'vue'`,
2937
+ `import { provide, shallowRef } from 'vue'`,
2933
2938
  `import { useRoute, useRouter } from 'vue-router'`,
2934
- "const { data: pageData } = usePageData()",
2939
+ // Use static page data instead of data loader
2940
+ `const pageData = shallowRef(${staticPageData})`,
2935
2941
  "const router = useRouter()",
2936
2942
  "const route = useRoute()",
2937
2943
  // $frontmatter contain runtime added data, will be deleted (for example, $frontmatter.partiallyEncryptedContents)
@@ -2949,8 +2955,6 @@ function injectPageDataCode(pageData) {
2949
2955
  return vueContextImports;
2950
2956
  }
2951
2957
  function createTransformMarkdown(options) {
2952
- const loaderVuePath = path$1.resolve(options.clientRoot, "templates", "loader.vue");
2953
- const loaderVue = fs.readFileSync(loaderVuePath, "utf-8");
2954
2958
  return (code, id, pageData) => {
2955
2959
  const isDev = options.mode === "dev";
2956
2960
  if (!isDev) {
@@ -2965,9 +2969,6 @@ function createTransformMarkdown(options) {
2965
2969
  encryptedKeys.forEach((key) => {
2966
2970
  delete pageData.frontmatter[key];
2967
2971
  });
2968
- const pagePath = pageData.relativePath.slice("/pages".length - 1, -".md".length);
2969
- const customDataLoader = loaderVue.replace("/relativePath", pagePath.endsWith("index") ? pagePath.replace(/\/index$/, "") : pagePath).replace("// custom basic loader", `return ${transformObject(pageData)}`);
2970
- code = customDataLoader + code;
2971
2972
  const scriptSetupStart = code.indexOf("<script setup>");
2972
2973
  if (scriptSetupStart !== -1)
2973
2974
  code = code.slice(0, scriptSetupStart + "<script setup>".length) + imports.join("\n") + code.slice(scriptSetupStart + 14);
@@ -3293,11 +3294,13 @@ function presetStatistics({
3293
3294
  }
3294
3295
  }, options.readTime)
3295
3296
  });
3296
- if (route.meta.frontmatter) {
3297
- if (!route.meta.frontmatter.wordCount)
3298
- route.meta.frontmatter.wordCount = wordCount2;
3299
- if (!route.meta.frontmatter.readingTime)
3300
- route.meta.frontmatter.readingTime = readingTime;
3297
+ const { frontmatter } = route.meta;
3298
+ if (frontmatter && typeof frontmatter === "object" && !Array.isArray(frontmatter)) {
3299
+ const fm = frontmatter;
3300
+ if (!fm.wordCount)
3301
+ fm.wordCount = wordCount2;
3302
+ if (!fm.readingTime)
3303
+ fm.readingTime = readingTime;
3301
3304
  }
3302
3305
  }
3303
3306
  }
@@ -3323,7 +3326,7 @@ async function createRouterPlugin(valaxyApp) {
3323
3326
  return VueRouter({
3324
3327
  extensions: [".vue", ".md"],
3325
3328
  routesFolder: roots.map((root) => `${root}/pages`),
3326
- dts: resolve$1(options.tempDir, "typed-router.d.ts"),
3329
+ dts: resolve$1(options.tempDir, "route-map.d.ts"),
3327
3330
  ...valaxyConfig.router,
3328
3331
  /**
3329
3332
  * @experimental See https://github.com/posva/unplugin-vue-router/issues/43
@@ -3405,7 +3408,9 @@ async function createRouterPlugin(valaxyApp) {
3405
3408
  ...mdFm,
3406
3409
  // 主题有新的字段需要主动设置
3407
3410
  // @TODO 添加文档和配置项,或者反过来允许用户自行优化
3408
- tags: typeof mdFm.tags === "string" ? [mdFm.tags] : mdFm.tags
3411
+ tags: typeof mdFm.tags === "string" ? [mdFm.tags] : mdFm.tags,
3412
+ // set default updated to date if not present
3413
+ updated: mdFm.updated ?? mdFm.date
3409
3414
  };
3410
3415
  excludeKeys.forEach((key) => {
3411
3416
  delete routerFM[key];
@@ -3419,8 +3424,6 @@ async function createRouterPlugin(valaxyApp) {
3419
3424
  layout: data.layout
3420
3425
  });
3421
3426
  }
3422
- if (!route.meta.frontmatter?.updated)
3423
- route.meta.frontmatter.updated = mdFm.date;
3424
3427
  if (valaxyConfig.siteConfig.statistics.enable) {
3425
3428
  presetStatistics({
3426
3429
  options: valaxyConfig.siteConfig.statistics,
@@ -3815,6 +3818,34 @@ const markdown = MarkdownIt({
3815
3818
  breaks: true,
3816
3819
  linkify: true
3817
3820
  });
3821
+ async function extractImagePathsFromHTML(htmlPath, DOMAIN) {
3822
+ const imageMap = /* @__PURE__ */ new Map();
3823
+ try {
3824
+ if (!await fs.exists(htmlPath))
3825
+ return imageMap;
3826
+ const html = await fs.readFile(htmlPath, "utf-8");
3827
+ const imgRegex = /<img[^>]+src="([^"]+)"[^>]*>/g;
3828
+ let match;
3829
+ while ((match = imgRegex.exec(html)) !== null) {
3830
+ const src = match[1];
3831
+ const assetMatch = src.match(/\/assets\/(.+)\.([a-zA-Z0-9]+)\.([a-z0-9]+)$/);
3832
+ if (assetMatch) {
3833
+ const [, basename, , ext] = assetMatch;
3834
+ const originalName = `${basename}.${ext}`;
3835
+ imageMap.set(originalName, `${DOMAIN}${src}`);
3836
+ imageMap.set(`./${originalName}`, `${DOMAIN}${src}`);
3837
+ consola.debug(`[RSS] Mapped image: ${originalName} -> ${DOMAIN}${src}`);
3838
+ }
3839
+ }
3840
+ if (imageMap.size > 0) {
3841
+ const uniqueImageCount = imageMap.size / 2;
3842
+ consola.info(`[RSS] Extracted ${uniqueImageCount} image(s) from ${htmlPath}`);
3843
+ }
3844
+ } catch (error) {
3845
+ consola.debug(`Failed to extract image paths from ${htmlPath}:`, error);
3846
+ }
3847
+ return imageMap;
3848
+ }
3818
3849
  async function build(options) {
3819
3850
  const s = ora("RSS Generating ...").start();
3820
3851
  const { config } = options;
@@ -3899,12 +3930,39 @@ async function getPosts(params, options) {
3899
3930
  }
3900
3931
  const fullText = options.config.modules.rss.fullText;
3901
3932
  const rssContent = fullText ? content : excerpt || content.slice(0, 100);
3902
- const html = markdown.render(rssContent).replace('src="/', `src="${DOMAIN}/`);
3903
- if (data.image?.startsWith("/"))
3904
- data.image = DOMAIN + data.image;
3905
3933
  const relativePath = relative$1(join(options.userRoot, "pages"), path);
3906
3934
  const urlPath = relativePath.replace(/\\/g, "/").replace(/\.md$/, "");
3907
3935
  const link = `${DOMAIN}/${urlPath}`;
3936
+ const extractImages = options.config.modules.rss.extractImagePathsFromHTML;
3937
+ let imageMap = /* @__PURE__ */ new Map();
3938
+ if (extractImages) {
3939
+ let htmlPath = resolve(options.userRoot, "dist", `${urlPath}.html`);
3940
+ if (urlPath.endsWith("/index")) {
3941
+ const withoutIndex = urlPath.slice(0, -6);
3942
+ const alternativePath = resolve(options.userRoot, "dist", `${withoutIndex}.html`);
3943
+ if (await fs.exists(alternativePath)) {
3944
+ htmlPath = alternativePath;
3945
+ }
3946
+ }
3947
+ imageMap = await extractImagePathsFromHTML(htmlPath, DOMAIN);
3948
+ }
3949
+ let html = markdown.render(rssContent);
3950
+ html = html.replace(/src="([^"]+)"/g, (_fullMatch, src) => {
3951
+ if (imageMap.has(src)) {
3952
+ return `src="${imageMap.get(src)}"`;
3953
+ }
3954
+ if (src.startsWith("http://") || src.startsWith("https://")) {
3955
+ return _fullMatch;
3956
+ }
3957
+ if (src.startsWith("/")) {
3958
+ return `src="${DOMAIN}${src}"`;
3959
+ }
3960
+ const postDirUrl = `${DOMAIN}/${urlPath.split("/").slice(0, -1).join("/")}`;
3961
+ const cleanSrc = src.startsWith("./") ? src.slice(2) : src;
3962
+ return `src="${postDirUrl}/${cleanSrc}"`;
3963
+ });
3964
+ if (data.image?.startsWith("/"))
3965
+ data.image = DOMAIN + data.image;
3908
3966
  const tip = `<br/><p>${lang === "zh-CN" ? `\u8BBF\u95EE <a href="${link}" target="_blank">${link}</a> ${fullText ? "\u67E5\u770B\u539F\u6587" : "\u9605\u8BFB\u5168\u6587"}\u3002` : `Visit <a href="${link}" target="_blank">${link}</a> to ${fullText ? "view original article" : "read more"}.`}</p>`;
3909
3967
  const item = {
3910
3968
  ...data,
@@ -4530,7 +4588,7 @@ async function genLayoutTemplate({
4530
4588
  if (!template)
4531
4589
  template = defaultPostTemplate;
4532
4590
  const dateFormat = "YYYY-MM-DD HH:mm:ss";
4533
- return render(template, { title, layout, date: date ? dayjs().format(dateFormat) : "" });
4591
+ return ejs.render(template, { title, layout, date: date ? dayjs().format(dateFormat) : "" });
4534
4592
  }
4535
4593
 
4536
4594
  function registerNewCommand(cli) {
@@ -4592,4 +4650,4 @@ function run() {
4592
4650
  cli.parse();
4593
4651
  }
4594
4652
 
4595
- export { mergeValaxyConfig as A, resolveValaxyConfig as B, ALL_ROUTE as C, customElements as D, EXCERPT_SEPARATOR as E, defaultViteConfig as F, GLOBAL_STATE as G, version as H, processValaxyOptions as I, resolveOptions as J, resolveThemeValaxyConfig as K, createValaxyPlugin as L, getServerInfoText as M, createServer as N, encryptContent as O, PATHNAME_PROTOCOL_RE as P, getGitTimestamp as Q, isExternal as R, isPath as S, transformObject as T, isInstalledGlobally as U, ViteValaxyPlugins as V, resolveImportUrl as W, toAtFS as X, resolveImportPath as Y, startValaxyDev as a, build$1 as b, cli as c, registerDevCommand as d, getIndexHtml as e, defineValaxyAddon as f, generateClientRedirects as g, defineAddon as h, resolveAddonsConfig as i, defaultSiteConfig as j, defineSiteConfig as k, resolveSiteConfigFromRoot as l, mergeViteConfigs as m, resolveSiteConfig as n, resolveThemeConfigFromRoot as o, postProcessForSSG as p, resolveUserThemeConfig as q, run as r, ssgBuild as s, defineValaxyTheme as t, defineTheme as u, loadConfigFromFile as v, defaultValaxyConfig as w, defineValaxyConfig as x, defineConfig as y, resolveValaxyConfigFromRoot as z };
4653
+ export { ALL_ROUTE as A, postProcessForSSG as B, processValaxyOptions as C, registerDevCommand as D, EXCERPT_SEPARATOR as E, resolveAddonsConfig as F, GLOBAL_STATE as G, resolveImportPath as H, resolveImportUrl as I, resolveOptions as J, resolveSiteConfig as K, resolveSiteConfigFromRoot as L, resolveThemeConfigFromRoot as M, resolveThemeValaxyConfig as N, resolveUserThemeConfig as O, PATHNAME_PROTOCOL_RE as P, resolveValaxyConfig as Q, resolveValaxyConfigFromRoot as R, run as S, ssgBuild as T, startValaxyDev as U, ViteValaxyPlugins as V, toAtFS as W, transformObject as X, version as Y, createServer as a, build$1 as b, cli as c, createValaxyPlugin as d, customElements as e, defaultSiteConfig as f, defaultValaxyConfig as g, defaultViteConfig as h, defineAddon as i, defineConfig as j, defineSiteConfig as k, defineTheme as l, defineValaxyAddon as m, defineValaxyConfig as n, defineValaxyTheme as o, encryptContent as p, generateClientRedirects as q, getGitTimestamp as r, getIndexHtml as s, getServerInfoText as t, isExternal as u, isInstalledGlobally as v, isPath as w, loadConfigFromFile as x, mergeValaxyConfig as y, mergeViteConfigs as z };
@@ -1,3 +1,4 @@
1
+ import { Header } from '@valaxyjs/utils';
1
2
  import { FuseOptions } from '@vueuse/integrations/useFuse';
2
3
  import { ZoomOptions } from 'medium-zoom';
3
4
  import { ILazyLoadOptions } from 'vanilla-lazyload';
@@ -5,62 +6,6 @@ import { RouteRecordRaw } from 'vue-router';
5
6
  import { UseDarkOptions } from '@vueuse/core';
6
7
  import { NodeRelations, ImageObject } from '@unhead/schema-org';
7
8
 
8
- interface ValaxyAddon<AddonOptions = Record<string, any>> {
9
- name: string;
10
- /**
11
- * be global component
12
- */
13
- global?: boolean;
14
- props?: Record<string, any>;
15
- options?: AddonOptions;
16
- }
17
-
18
- declare namespace DefaultTheme {
19
- interface Config {
20
- valaxyDarkOptions?: {
21
- /**
22
- * Options for `useDark`
23
- * disableTransition default is `true`
24
- * Its options are not computed, init when loaded.
25
- * @see https://vueuse.org/core/useDark
26
- * @url https://paco.me/writing/disable-theme-transitions
27
- *
28
- * @zh `useDark` 的选项
29
- * disableTransition 默认为 `true`,不会进行渐变过渡,这是 VueUse 的默认行为
30
- */
31
- useDarkOptions?: UseDarkOptions;
32
- /**
33
- * Enable circle transition when toggling dark mode
34
- * Then use `toggleDarkWithTransition` instead of `toggleDark`
35
- * @zh 启用圆形过渡切换暗黑模式
36
- */
37
- circleTransition?: boolean;
38
- /**
39
- * Theme color
40
- * @zh 主题色
41
- */
42
- themeColor?: {
43
- /**
44
- * Theme color for light mode
45
- * @zh 亮色主题色
46
- */
47
- light?: string;
48
- /**
49
- * Theme color for dark mode
50
- * @zh 暗色主题色
51
- */
52
- dark?: string;
53
- };
54
- };
55
- /**
56
- * Custom header levels of outline in the aside component.
57
- *
58
- * @default 2
59
- */
60
- outline?: number | [number, number] | 'deep' | false;
61
- }
62
- }
63
-
64
9
  interface CollectionConfig {
65
10
  title?: string;
66
11
  key?: string;
@@ -407,6 +352,92 @@ interface PostFrontMatter extends PageFrontMatter {
407
352
  wordCount: string;
408
353
  }
409
354
 
355
+ type Page = Partial<PageFrontMatter>;
356
+ type Post = Partial<PostFrontMatter>;
357
+
358
+ /**
359
+ * Extend vue-router's RouteMeta interface
360
+ * @see https://router.vuejs.org/guide/advanced/meta.html#TypeScript
361
+ */
362
+
363
+
364
+ declare module 'vue-router' {
365
+ interface RouteMeta {
366
+ /**
367
+ * Headers extracted from markdown
368
+ */
369
+ headers: Header[]
370
+ /**
371
+ * Frontmatter data from markdown files
372
+ */
373
+ frontmatter: Post
374
+ /**
375
+ * Excerpt from markdown content
376
+ */
377
+ excerpt?: string
378
+ /**
379
+ * Layout name
380
+ */
381
+ layout?: string
382
+ }
383
+ }
384
+
385
+ interface ValaxyAddon<AddonOptions = Record<string, any>> {
386
+ name: string;
387
+ /**
388
+ * be global component
389
+ */
390
+ global?: boolean;
391
+ props?: Record<string, any>;
392
+ options?: AddonOptions;
393
+ }
394
+
395
+ declare namespace DefaultTheme {
396
+ interface Config {
397
+ valaxyDarkOptions?: {
398
+ /**
399
+ * Options for `useDark`
400
+ * disableTransition default is `true`
401
+ * Its options are not computed, init when loaded.
402
+ * @see https://vueuse.org/core/useDark
403
+ * @url https://paco.me/writing/disable-theme-transitions
404
+ *
405
+ * @zh `useDark` 的选项
406
+ * disableTransition 默认为 `true`,不会进行渐变过渡,这是 VueUse 的默认行为
407
+ */
408
+ useDarkOptions?: UseDarkOptions;
409
+ /**
410
+ * Enable circle transition when toggling dark mode
411
+ * Then use `toggleDarkWithTransition` instead of `toggleDark`
412
+ * @zh 启用圆形过渡切换暗黑模式
413
+ */
414
+ circleTransition?: boolean;
415
+ /**
416
+ * Theme color
417
+ * @zh 主题色
418
+ */
419
+ themeColor?: {
420
+ /**
421
+ * Theme color for light mode
422
+ * @zh 亮色主题色
423
+ */
424
+ light?: string;
425
+ /**
426
+ * Theme color for dark mode
427
+ * @zh 暗色主题色
428
+ */
429
+ dark?: string;
430
+ };
431
+ };
432
+ /**
433
+ * Custom header levels of outline in the aside component.
434
+ *
435
+ * @default 2
436
+ */
437
+ outline?: number | [number, number] | 'deep' | false;
438
+ }
439
+ }
440
+
410
441
  interface FuseListItem extends Record<string, any> {
411
442
  title: string | Record<string, string>;
412
443
  excerpt?: string;
@@ -846,4 +877,4 @@ type UserSiteConfig = PartialDeep<SiteConfig>;
846
877
  type UserValaxyConfig<ThemeConfig = DefaultTheme.Config> = PartialDeep<ValaxyConfig<ThemeConfig>>;
847
878
 
848
879
  export { DefaultTheme as D };
849
- export type { Album as A, BaseFrontMatter as B, ExcerptType as E, FuseListItem as F, PartialDeep as P, RuntimeConfig as R, SiteConfig as S, UserSiteConfig as U, ValaxyConfig as V, RedirectItem as a, ValaxyAddon as b, PostFrontMatter as c, PageFrontMatter as d, SocialLink as e, RedirectRule as f, Pkg as g, UserValaxyConfig as h, Photo as i };
880
+ export type { Album as A, BaseFrontMatter as B, ExcerptType as E, FuseListItem as F, PartialDeep as P, RuntimeConfig as R, SiteConfig as S, UserSiteConfig as U, ValaxyConfig as V, RedirectItem as a, ValaxyAddon as b, Post as c, Page as d, PageFrontMatter as e, Photo as f, Pkg as g, PostFrontMatter as h, RedirectRule as i, SocialLink as j, UserValaxyConfig as k };
@@ -1,5 +1,5 @@
1
- import { c as PostFrontMatter, d as PageFrontMatter } from '../shared/valaxy.gqLhCu14.mjs';
2
- export { A as Album, B as BaseFrontMatter, D as DefaultTheme, E as ExcerptType, F as FuseListItem, P as PartialDeep, i as Photo, g as Pkg, a as RedirectItem, f as RedirectRule, R as RuntimeConfig, S as SiteConfig, e as SocialLink, U as UserSiteConfig, h as UserValaxyConfig, b as ValaxyAddon, V as ValaxyConfig } from '../shared/valaxy.gqLhCu14.mjs';
1
+ import { c as Post } from '../shared/valaxy._i636HSR.mjs';
2
+ export { A as Album, B as BaseFrontMatter, D as DefaultTheme, E as ExcerptType, F as FuseListItem, d as Page, e as PageFrontMatter, P as PartialDeep, f as Photo, g as Pkg, h as PostFrontMatter, a as RedirectItem, i as RedirectRule, R as RuntimeConfig, S as SiteConfig, j as SocialLink, U as UserSiteConfig, k as UserValaxyConfig, b as ValaxyAddon, V as ValaxyConfig } from '../shared/valaxy._i636HSR.mjs';
3
3
  import { Header } from '@valaxyjs/utils';
4
4
  import '@vueuse/integrations/useFuse';
5
5
  import 'medium-zoom';
@@ -8,9 +8,6 @@ import 'vue-router';
8
8
  import '@vueuse/core';
9
9
  import '@unhead/schema-org';
10
10
 
11
- type Page = Partial<PageFrontMatter>;
12
- type Post = Partial<PostFrontMatter>;
13
-
14
11
  type CleanUrlsMode = 'disabled' | 'without-subfolders' | 'with-subfolders';
15
12
  interface PageData {
16
13
  relativePath: string;
@@ -32,5 +29,5 @@ interface PageDataPayload {
32
29
  }
33
30
  type HeadConfig = [string, Record<string, string>] | [string, Record<string, string>, string];
34
31
 
35
- export { PageFrontMatter, PostFrontMatter };
36
- export type { CleanUrlsMode, HeadConfig, Page, PageData, PageDataPayload, Post };
32
+ export { Post };
33
+ export type { CleanUrlsMode, HeadConfig, PageData, PageDataPayload };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "valaxy",
3
3
  "type": "module",
4
- "version": "0.26.12",
4
+ "version": "0.27.0",
5
5
  "description": "📄 Vite & Vue powered static blog generator.",
6
6
  "author": {
7
7
  "email": "me@yunyoujun.cn",
@@ -62,19 +62,19 @@
62
62
  "dependencies": {
63
63
  "@antfu/install-pkg": "^1.1.0",
64
64
  "@antfu/utils": "^9.3.0",
65
- "@clack/prompts": "^0.11.0",
66
- "@iconify-json/ri": "^1.2.6",
65
+ "@clack/prompts": "^1.0.0",
66
+ "@iconify-json/ri": "^1.2.9",
67
67
  "@intlify/unplugin-vue-i18n": "^11.0.3",
68
- "@shikijs/transformers": "^3.20.0",
69
- "@types/katex": "^0.16.7",
70
- "@unhead/addons": "^2.1.1",
71
- "@unhead/schema-org": "^2.1.1",
72
- "@unhead/vue": "^2.1.1",
73
- "@vitejs/plugin-vue": "^6.0.3",
68
+ "@shikijs/transformers": "^3.22.0",
69
+ "@types/katex": "^0.16.8",
70
+ "@unhead/addons": "^2.1.2",
71
+ "@unhead/schema-org": "^2.1.2",
72
+ "@unhead/vue": "^2.1.2",
73
+ "@vitejs/plugin-vue": "^6.0.4",
74
74
  "@vue/devtools-api": "7.7.2",
75
- "@vueuse/core": "^14.1.0",
76
- "@vueuse/integrations": "^14.1.0",
77
- "beasties": "^0.3.5",
75
+ "@vueuse/core": "^14.2.0",
76
+ "@vueuse/integrations": "^14.2.0",
77
+ "beasties": "^0.4.1",
78
78
  "consola": "^3.4.2",
79
79
  "cross-spawn": "^7.0.6",
80
80
  "css-i18n": "^0.0.5",
@@ -82,10 +82,10 @@
82
82
  "debug": "^4.4.3",
83
83
  "define-config-ts": "^0.1.3",
84
84
  "defu": "^6.1.4",
85
- "ejs": "^3.1.10",
85
+ "ejs": "^4.0.1",
86
86
  "escape-html": "^1.0.3",
87
87
  "fast-glob": "^3.3.3",
88
- "feed": "^5.1.0",
88
+ "feed": "^5.2.0",
89
89
  "floating-vue": "^5.2.2",
90
90
  "fs-extra": "^11.3.3",
91
91
  "fuse.js": "^7.1.0",
@@ -95,8 +95,8 @@
95
95
  "jiti": "^2.6.1",
96
96
  "js-base64": "^3.7.8",
97
97
  "js-yaml": "^4.1.1",
98
- "katex": "^0.16.27",
99
- "lru-cache": "^11.2.4",
98
+ "katex": "^0.16.28",
99
+ "lru-cache": "^11.2.5",
100
100
  "markdown-it": "^14.1.0",
101
101
  "markdown-it-anchor": "^9.2.0",
102
102
  "markdown-it-async": "^2.2.0",
@@ -112,35 +112,34 @@
112
112
  "mlly": "^1.8.0",
113
113
  "nprogress": "^0.2.0",
114
114
  "open": "10.1.0",
115
- "ora": "^9.0.0",
115
+ "ora": "^9.1.0",
116
116
  "pascalcase": "^2.0.0",
117
117
  "pathe": "^2.0.3",
118
118
  "pinia": "^3.0.4",
119
119
  "qrcode": "^1.5.4",
120
120
  "resolve-global": "^2.0.0",
121
- "sass": "^1.97.1",
122
- "shiki": "^3.20.0",
121
+ "sass": "^1.97.3",
122
+ "shiki": "^3.22.0",
123
123
  "star-markdown-css": "^0.5.3",
124
124
  "table": "^6.9.0",
125
- "unhead": "^2.1.1",
125
+ "unhead": "^2.1.2",
126
126
  "unocss": "66.5.10",
127
127
  "unplugin-vue-components": "28.0.0",
128
128
  "unplugin-vue-markdown": "^29.2.0",
129
- "unplugin-vue-router": "^0.19.1",
130
129
  "vanilla-lazyload": "^19.1.3",
131
- "vite": "^7.3.0",
130
+ "vite": "^7.3.1",
132
131
  "vite-dev-rpc": "^1.1.0",
133
132
  "vite-plugin-vue-devtools": "^8.0.5",
134
133
  "vite-plugin-vue-layouts": "^0.11.0",
135
134
  "vite-ssg": "^28.2.2",
136
135
  "vite-ssg-sitemap": "^0.10.0",
137
- "vitepress-plugin-group-icons": "^1.6.5",
136
+ "vitepress-plugin-group-icons": "^1.7.1",
138
137
  "vue": "3.5.22",
139
- "vue-i18n": "^11.2.7",
140
- "vue-router": "^4.6.4",
138
+ "vue-i18n": "^11.2.8",
139
+ "vue-router": "^5.0.2",
141
140
  "yargs": "^18.0.0",
142
- "@valaxyjs/devtools": "0.26.12",
143
- "@valaxyjs/utils": "0.26.12"
141
+ "@valaxyjs/utils": "0.27.0",
142
+ "@valaxyjs/devtools": "0.27.0"
144
143
  },
145
144
  "devDependencies": {
146
145
  "@mdit-vue/plugin-component": "^3.0.2",
package/types/index.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  // do not export node type here
2
+ // vue-router RouteMeta augmentation
3
+ import './vue-router.d'
4
+
2
5
  export * from './addon'
3
6
  export * from './config'
4
7
  export * from './data'
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Extend vue-router's RouteMeta interface
3
+ * @see https://router.vuejs.org/guide/advanced/meta.html#TypeScript
4
+ */
5
+ import type { Header } from '@valaxyjs/utils'
6
+ import type { Post } from './posts'
7
+
8
+ export {}
9
+
10
+ declare module 'vue-router' {
11
+ interface RouteMeta {
12
+ /**
13
+ * Headers extracted from markdown
14
+ */
15
+ headers: Header[]
16
+ /**
17
+ * Frontmatter data from markdown files
18
+ */
19
+ frontmatter: Post
20
+ /**
21
+ * Excerpt from markdown content
22
+ */
23
+ excerpt?: string
24
+ /**
25
+ * Layout name
26
+ */
27
+ layout?: string
28
+ }
29
+ }
@@ -1,10 +0,0 @@
1
- <script>
2
- import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic'
3
-
4
- export const usePageData = defineBasicLoader('/relativePath', async (_to) => {
5
- // custom basic loader
6
- }, {
7
- // @see https://uvr.esm.is/data-loaders/defining-loaders.html#non-blocking-loaders-with-lazy
8
- lazy: (to, from) => to.name === from.name,
9
- })
10
- </script>