valaxy 0.2.4 → 0.3.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.
Files changed (53) hide show
  1. package/dist/{chunk-HSIBOGUA.mjs → chunk-F4NM2FOU.mjs} +43 -43
  2. package/dist/{chunk-XMNH5QY2.js → chunk-PQWGL22E.js} +42 -42
  3. package/dist/{chunk-JARRR63D.mjs → chunk-R2IXLA5A.mjs} +1 -1
  4. package/dist/{chunk-RUZ4KMBM.js → chunk-WNLPZSAR.js} +1 -1
  5. package/dist/config-408070e9.d.ts +195 -0
  6. package/dist/index.d.ts +404 -0
  7. package/dist/index.js +1 -1
  8. package/dist/index.mjs +1 -1
  9. package/dist/node/cli.d.ts +3 -0
  10. package/dist/node/cli.js +8 -8
  11. package/dist/node/cli.mjs +8 -8
  12. package/dist/node/index.d.ts +46 -0
  13. package/dist/node/index.js +1 -1
  14. package/dist/node/index.mjs +1 -1
  15. package/package.json +22 -23
  16. package/src/client/components/AppLink.vue +1 -1
  17. package/src/client/components/PostCard.vue +2 -2
  18. package/src/client/components/ValaxyCopyright.vue +2 -2
  19. package/src/client/components/ValaxyFooter.vue +1 -2
  20. package/src/client/components/ValaxyMd.vue +1 -1
  21. package/src/client/components/ValaxyOverlay.vue +1 -1
  22. package/src/client/components/ValaxyPagination.vue +2 -2
  23. package/src/client/components/ValaxyRightSidebar.vue +44 -3
  24. package/src/client/components/ValaxySidebar.vue +1 -1
  25. package/src/client/components/ValaxyToc.vue +30 -8
  26. package/src/client/composables/category.ts +7 -3
  27. package/src/client/composables/comments/twikoo.ts +1 -4
  28. package/src/client/composables/comments/waline.ts +11 -2
  29. package/src/client/composables/sidebar.ts +29 -44
  30. package/src/client/locales/zh-CN.yml +1 -1
  31. package/src/client/modules/pwa.ts +1 -1
  32. package/src/client/pages/[...all].vue +0 -0
  33. package/src/client/stores/app.ts +5 -0
  34. package/src/client/styles/common/sidebar.scss +3 -1
  35. package/src/client/styles/global/i18n.scss +29 -1
  36. package/src/client/styles/global/reset.scss +1 -1
  37. package/src/node/cli.ts +3 -3
  38. package/src/node/config.ts +9 -0
  39. package/src/node/markdown/headings.ts +7 -1
  40. package/src/node/markdown/index.ts +6 -1
  41. package/src/node/markdown/markdown-it-katex.ts +4 -4
  42. package/src/node/plugins/markdown.ts +1 -0
  43. package/src/node/plugins/preset.ts +1 -1
  44. package/src/node/plugins/unocss.ts +8 -7
  45. package/src/node/utils/cli.ts +1 -1
  46. package/src/node/vite.ts +2 -0
  47. package/src/types/config.ts +15 -3
  48. package/src/types/posts.ts +5 -0
  49. package/src/client/public/_headers +0 -3
  50. package/src/client/public/favicon.svg +0 -21
  51. package/src/client/public/pwa-192x192.png +0 -0
  52. package/src/client/public/pwa-512x512.png +0 -0
  53. package/src/client/public/safari-pinned-tab.svg +0 -41
@@ -0,0 +1,46 @@
1
+ import * as vite from 'vite';
2
+ import { InlineConfig } from 'vite';
3
+ import { V as ValaxyConfig } from '../config-408070e9.js';
4
+ import 'type-fest';
5
+ import 'unocss/vite';
6
+ import 'markdown-it';
7
+ import 'markdown-it-anchor';
8
+ import 'katex';
9
+ import 'vite-plugin-md';
10
+
11
+ interface ResolvedValaxyOptions {
12
+ mode: 'dev' | 'build';
13
+ /**
14
+ * Client root path
15
+ * @default 'valaxy/src/client'
16
+ */
17
+ clientRoot: string;
18
+ /**
19
+ * User root path
20
+ * @default process.cwd()
21
+ */
22
+ userRoot: string;
23
+ /**
24
+ * Theme root path
25
+ */
26
+ themeRoot: string;
27
+ /**
28
+ * Theme name
29
+ */
30
+ theme: string;
31
+ /**
32
+ * Valaxy Config
33
+ */
34
+ config: ValaxyConfig;
35
+ /**
36
+ * config file path
37
+ */
38
+ configFile: string;
39
+ }
40
+ interface ValaxyServerOptions {
41
+ onConfigReload?: (newConfig: ValaxyConfig, config: ValaxyConfig) => void;
42
+ }
43
+
44
+ declare function createServer(options: ResolvedValaxyOptions, viteConfig?: InlineConfig, serverOptions?: ValaxyServerOptions): Promise<vite.ViteDevServer>;
45
+
46
+ export { createServer };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkXMNH5QY2js = require('../chunk-XMNH5QY2.js');var _chunkRUZ4KMBMjs = require('../chunk-RUZ4KMBM.js');_chunkRUZ4KMBMjs.f.call(void 0, );exports.createServer = _chunkXMNH5QY2js.i;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkPQWGL22Ejs = require('../chunk-PQWGL22E.js');var _chunkWNLPZSARjs = require('../chunk-WNLPZSAR.js');_chunkWNLPZSARjs.f.call(void 0, );exports.createServer = _chunkPQWGL22Ejs.i;
@@ -1 +1 @@
1
- import{i as r}from"../chunk-HSIBOGUA.mjs";import{f as o}from"../chunk-JARRR63D.mjs";o();export{r as createServer};
1
+ import{i as r}from"../chunk-F4NM2FOU.mjs";import{f as o}from"../chunk-R2IXLA5A.mjs";o();export{r as createServer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valaxy",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "📄 Vite & Vue powered static blog generator.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,26 +37,26 @@
37
37
  "https-localhost": "^4.7.1",
38
38
  "markdown-it-attrs": "^4.1.3",
39
39
  "type-fest": "^2.12.2",
40
- "vue-tsc": "^0.34.2"
40
+ "vue-tsc": "^0.34.11"
41
41
  },
42
42
  "dependencies": {
43
- "@ctrl/tinycolor": "^3.4.0",
44
- "@iconify-json/carbon": "^1.1.3",
43
+ "@ctrl/tinycolor": "^3.4.1",
44
+ "@iconify-json/carbon": "^1.1.4",
45
45
  "@iconify-json/ri": "^1.1.1",
46
46
  "@intlify/vite-plugin-vue-i18n": "^3.4.0",
47
47
  "@vitejs/plugin-vue": "^2.3.1",
48
- "@vueuse/core": "^8.2.5",
49
- "@vueuse/head": "^0.7.5",
48
+ "@vueuse/core": "^8.3.1",
49
+ "@vueuse/head": "^0.7.6",
50
50
  "consola": "^2.15.3",
51
51
  "critters": "^0.0.16",
52
- "dayjs": "^1.11.0",
52
+ "dayjs": "^1.11.1",
53
53
  "escape-html": "^1.0.3",
54
54
  "fast-deep-equal": "^3.1.3",
55
55
  "feed": "^4.2.2",
56
56
  "katex": "^0.15.3",
57
57
  "markdown-it-anchor": "^8.6.2",
58
58
  "markdown-it-container": "^3.0.0",
59
- "markdown-it-emoji": "^2.0.0",
59
+ "markdown-it-emoji": "^2.0.2",
60
60
  "markdown-it-link-attributes": "^4.0.0",
61
61
  "markdown-it-table-of-contents": "^0.6.0",
62
62
  "markdown-it-task-lists": "^2.1.1",
@@ -64,23 +64,23 @@
64
64
  "open": "^8.4.0",
65
65
  "pinia": "^2.0.13",
66
66
  "prism-theme-vars": "^0.2.2",
67
- "prismjs": "^1.27.0",
68
- "sass": "^1.50.0",
67
+ "prismjs": "^1.28.0",
68
+ "sass": "^1.51.0",
69
69
  "star-markdown-css": "^0.3.3",
70
- "unconfig": "^0.3.2",
71
- "unocss": "^0.31.0",
72
- "unplugin-vue-components": "^0.19.1",
73
- "vite": "^2.9.1",
74
- "vite-plugin-inspect": "^0.4.3",
75
- "vite-plugin-md": "^0.12.4",
76
- "vite-plugin-pages": "^0.22.0",
77
- "vite-plugin-pwa": "^0.11.13",
70
+ "unconfig": "^0.3.3",
71
+ "unocss": "^0.32.9",
72
+ "unplugin-vue-components": "^0.19.3",
73
+ "vite": "^2.9.7",
74
+ "vite-plugin-inspect": "^0.5.0",
75
+ "vite-plugin-md": "^0.13.0",
76
+ "vite-plugin-pages": "^0.23.0",
77
+ "vite-plugin-pwa": "^0.12.0",
78
78
  "vite-plugin-vue-layouts": "^0.6.0",
79
79
  "vite-ssg": "^0.19.2",
80
- "vite-ssg-sitemap": "0.2.2",
81
- "vue": "^3.2.31",
80
+ "vite-ssg-sitemap": "0.2.6",
81
+ "vue": "^3.2.33",
82
82
  "vue-demi": "^0.12.5",
83
- "vue-i18n": "^9.1.9",
83
+ "vue-i18n": "^9.1.10",
84
84
  "vue-router": "^4.0.14",
85
85
  "yargs": "^17.4.1"
86
86
  },
@@ -91,6 +91,5 @@
91
91
  "preview": "vite preview",
92
92
  "preview-https": "serve dist",
93
93
  "typecheck": "vue-tsc --noEmit"
94
- },
95
- "readme": "# Valaxy\n\n🌌 Next Generation Static Blog Framework, powered by Vite & Vue.\n\nRead [YunYouJun/valaxy](https://github.com/YunYouJun/valaxy) for more info.\n"
94
+ }
96
95
  }
@@ -14,7 +14,7 @@ const isExternalLink = computed(() => {
14
14
  <a v-if="isExternalLink" v-bind="$attrs" :href="to" target="_blank">
15
15
  <slot />
16
16
  </a>
17
- <router-link v-else v-bind="$props">
17
+ <router-link v-else v-bind="$props as any">
18
18
  <slot />
19
19
  </router-link>
20
20
  </template>
@@ -46,7 +46,7 @@ const { icon, styles } = usePostProperty(props.post.type)
46
46
  v-if="post.categories"
47
47
  :to="{
48
48
  path: '/categories/',
49
- query: {category: Array.isArray(post.categories) ? post.categories[post.categories.length - 1] : post.categories}
49
+ query: { category: Array.isArray(post.categories) ? post.categories[post.categories.length - 1] : post.categories },
50
50
  }"
51
51
  class="post-categories inline-flex justify-center items-center" m="l-2"
52
52
  >
@@ -57,7 +57,7 @@ const { icon, styles } = usePostProperty(props.post.type)
57
57
 
58
58
  <div class="post-tags inline-flex" m="r-2">
59
59
  <template v-if="post.tags">
60
- <router-link v-for="tag,i in post.tags" :key="i" :to="{path: '/tags/', query: {tag: tag}}" m="x-1" class="post-tag inline-flex justify-center items-center">
60
+ <router-link v-for="tag, i in post.tags" :key="i" :to="{ path: '/tags/', query: { tag } }" m="x-1" class="post-tag inline-flex justify-center items-center">
61
61
  <div m="r-1" i-ri-price-tag-3-line />
62
62
  {{ tag }}
63
63
  </router-link>
@@ -3,14 +3,14 @@ import { computed } from 'vue'
3
3
  import { useI18n } from 'vue-i18n'
4
4
  import { useConfig } from '../config'
5
5
 
6
- const { t, locale } = useI18n()
7
-
8
6
  withDefaults(defineProps<{
9
7
  url?: string
10
8
  }>(), {
11
9
  url: '',
12
10
  })
13
11
 
12
+ const { t, locale } = useI18n()
13
+
14
14
  const config = useConfig()
15
15
 
16
16
  const ccVersion = (config.value.license.type === 'zero') ? '1.0' : '4.0'
@@ -3,7 +3,6 @@ import { capitalize, computed } from 'vue'
3
3
  import { useConfig, useThemeConfig } from 'valaxy'
4
4
  import { useI18n } from 'vue-i18n'
5
5
 
6
- import themePkg from 'valaxy-theme-yun/package.json'
7
6
  import pkg from '~/../../package.json'
8
7
 
9
8
  const { t } = useI18n()
@@ -45,7 +44,7 @@ const poweredHtml = computed(() => t('footer.powered', [`<a href="${pkg.reposito
45
44
  </div>
46
45
 
47
46
  <div v-if="themeConfig.footer.powered" class="powered" m="2">
48
- <span v-html="poweredHtml" /> | <span>{{ t('footer.theme') }} - <a :href="themePkg.homepage" :title="'valaxy-theme-' + config.theme" target="_blank">{{ capitalize(config.theme) }}</a> v{{ themePkg.version }}</span>
47
+ <span v-html="poweredHtml" /> | <span>{{ t('footer.theme') }} - <a :href="themeConfig.pkg.homepage" :title="`valaxy-theme-${config.theme}`" target="_blank">{{ capitalize(config.theme) }}</a> v{{ themeConfig.pkg.version }}</span>
49
48
  </div>
50
49
 
51
50
  <slot />
@@ -34,7 +34,7 @@ if (props.frontmatter.codepen)
34
34
  </script>
35
35
 
36
36
  <template>
37
- <article v-if="$slots.default" class="markdown-body">
37
+ <article v-if="$slots.default" :class="frontmatter.markdown !== false && 'markdown-body'">
38
38
  <slot ref="content" @vnode-updated="updateDom" />
39
39
 
40
40
  <div text="center">
@@ -8,7 +8,7 @@ withDefaults(defineProps<{
8
8
 
9
9
  <template>
10
10
  <transition name="fade">
11
- <div v-if="show" class="va-overlay backdrop-filter backdrop-blur" />
11
+ <div v-if="show" class="va-overlay" />
12
12
  </transition>
13
13
  </template>
14
14
 
@@ -15,7 +15,7 @@ const props = defineProps<{
15
15
  pageSize: number
16
16
  }>()
17
17
 
18
- const emit = defineEmits(['page-change'])
18
+ const emit = defineEmits(['pageChange'])
19
19
 
20
20
  const totalPages = computed(() => Math.ceil(props.total / props.pageSize))
21
21
 
@@ -38,7 +38,7 @@ const showPage = (i: number) => {
38
38
  }
39
39
 
40
40
  const jumpTo = (page: number) => {
41
- emit('page-change', page)
41
+ emit('pageChange', page)
42
42
  if (page === 1)
43
43
  return '/'
44
44
  else return `/page/${page}`
@@ -1,18 +1,30 @@
1
1
  <script lang="ts" setup>
2
2
  import { useI18n } from 'vue-i18n'
3
3
  import type { Post } from '../../types'
4
+ import { useAppStore } from '~/stores/app'
5
+ defineProps<{ frontmatter: Post }>()
4
6
  const { t } = useI18n()
5
7
 
6
- defineProps<{ frontmatter: Post }>()
8
+ const app = useAppStore()
7
9
  </script>
8
10
 
9
11
  <template>
10
- <aside class="right-sidebar va-card relative" m="l-4" text="center">
12
+ <button
13
+ class="xl:hidden toc-btn shadow fixed yun-icon-btn z-350"
14
+ opacity="75" right="2" bottom="19"
15
+ @click="app.toggleRightSidebar()"
16
+ >
17
+ <div i-ri-file-list-line />
18
+ </button>
19
+
20
+ <ValaxyOverlay :show="app.isRightSidebarOpen" @click="app.toggleRightSidebar()" />
21
+
22
+ <aside class="right-sidebar fixed va-card" :class="app.isRightSidebarOpen && 'open'" m="l-4" text="center">
11
23
  <h2 v-if="frontmatter.toc !== false" m="t-6 b-2" font="serif black">
12
24
  {{ t('sidebar.toc') }}
13
25
  </h2>
14
26
 
15
- <div class="right-sidebar-container sticky">
27
+ <div class="right-sidebar-container">
16
28
  <ValaxyToc v-if="frontmatter.toc !== false" />
17
29
 
18
30
  <div v-if="$slots.custom" class="custom-container">
@@ -23,10 +35,39 @@ defineProps<{ frontmatter: Post }>()
23
35
  </template>
24
36
 
25
37
  <style lang="scss">
38
+ @use '~/styles/mixins' as *;
39
+
40
+ @include xl {
41
+ .right-sidebar {
42
+ transform: translateX(0) !important;
43
+ }
44
+ }
45
+
26
46
  .right-sidebar {
27
47
  width: var(--va-sidebar-width-mobile);
48
+
49
+ position: fixed;
50
+ top: 0;
51
+ bottom: 0;
52
+ right: 0;
53
+
54
+ transform: translateX(100%);
55
+
56
+ transition: box-shadow var(--va-transition-duration),
57
+ background-color var(--va-transition-duration), opacity 0.25s,
58
+ transform var(--va-transition-duration) cubic-bezier(0.19, 1, 0.22, 1);
59
+
60
+ &.open {
61
+ z-index: 10;
62
+ transform: translateX(0);
63
+ }
28
64
  }
29
65
  .right-sidebar-container {
30
66
  top: 1rem;
31
67
  }
68
+
69
+ .toc-btn {
70
+ color: var(--va-c-primary);
71
+ background-color: white;
72
+ }
32
73
  </style>
@@ -11,7 +11,7 @@ const isHome = useLayout('home')
11
11
 
12
12
  <ValaxyHamburger :active="app.isSidebarOpen" class="menu-btn sidebar-toggle yun-icon-btn" :class="isHome ? '' : 'md:hidden'" @click="app.toggleSidebar()" />
13
13
 
14
- <aside class="va-card" :class="['sidebar', app.isSidebarOpen && 'open', !isHome && 'md:translate-x-0']">
14
+ <aside class="va-card transition sidebar" :class="[app.isSidebarOpen && 'open', !isHome && 'md:translate-x-0']">
15
15
  <slot />
16
16
  </aside>
17
17
  </template>
@@ -1,5 +1,6 @@
1
1
  <script lang="ts" setup>
2
- import { computed } from 'vue'
2
+ import { computed, ref } from 'vue'
3
+ import { useI18n } from 'vue-i18n'
3
4
  import { useRoute } from 'vue-router'
4
5
 
5
6
  import { useActiveSidebarLinks } from '~/composables'
@@ -7,27 +8,48 @@ import { useActiveSidebarLinks } from '~/composables'
7
8
  const route = useRoute()
8
9
  const headers = computed(() => route.meta.headers)
9
10
 
10
- useActiveSidebarLinks()
11
+ const container = ref()
12
+ const marker = ref()
13
+ useActiveSidebarLinks(container, marker)
11
14
 
12
15
  function getStylesByLevel(level: number) {
13
16
  return {
14
- fontSize: `${(6 - level) * 0.2 + 0.4}rem`,
17
+ // fontSize: `${(6 - level) * 0.1 + 0.7}rem`,
15
18
  paddingLeft: `${level * 1 - 1}rem`,
16
19
  }
17
20
  }
18
21
 
22
+ const { locale } = useI18n()
23
+
19
24
  // todo mobile toc widget
20
25
  </script>
21
26
 
22
27
  <template>
23
- <ul class="va-toc" p="l-4">
24
- <li v-for="header, i in headers" :key="i" class="va-toc-item" :style="getStylesByLevel(header.level)">
25
- <a class="toc-link-item" :href="`#${header.slug}`">{{ header.title }}</a>
26
- </li>
27
- </ul>
28
+ <div v-if="headers" ref="container">
29
+ <div ref="marker" class="outline-marker" />
30
+ <ul class="va-toc" p="l-4">
31
+ <li v-for="header, i in headers" :key="i" :lang="header.lang || locale" class="va-toc-item" :style="getStylesByLevel(header.level)">
32
+ <a class="toc-link-item" :href="`#${header.slug}`">{{ header.title }}</a>
33
+ </li>
34
+ </ul>
35
+ </div>
28
36
  </template>
29
37
 
30
38
  <style lang="scss">
39
+ .outline-marker {
40
+ opacity: 0;
41
+ position: absolute;
42
+ background-color: var(--va-c-primary);
43
+ border-radius: 4px;
44
+ width: 4px;
45
+ height: 20px;
46
+ top: 32px;
47
+ left: 20px;
48
+ z-index: 0;
49
+ transition: top 0.25s cubic-bezier(0, 1, 0.5, 1), opacity 0.25s,
50
+ background-color 0.5s;
51
+ }
52
+
31
53
  .va-toc {
32
54
  top: 10px;
33
55
  width: var(--yun-sidebar-width-mobile);
@@ -2,13 +2,15 @@ import { unref } from 'vue'
2
2
  import type { Post } from '../../types'
3
3
  import { usePostList } from './post'
4
4
 
5
- export interface ParentCategory {
5
+ export interface BaseCategory {
6
6
  total: number
7
+ }
8
+
9
+ export interface ParentCategory extends BaseCategory {
7
10
  children: Categories
8
11
  }
9
12
 
10
- export interface PostCategory {
11
- total: number
13
+ export interface PostCategory extends BaseCategory {
12
14
  posts: Post[]
13
15
  }
14
16
 
@@ -17,6 +19,8 @@ export type Category = ParentCategory | PostCategory
17
19
  // export type Categories = Map<string, Post[] | Category>
18
20
  export type Categories = Map<string, Category>
19
21
 
22
+ export const isParentCategory = (category: any): category is ParentCategory => category.children
23
+
20
24
  /**
21
25
  * get categories from posts
22
26
  * @returns
@@ -4,11 +4,8 @@ import { useRoute } from 'vue-router'
4
4
 
5
5
  export function useTwikoo(options: {} = {}) {
6
6
  const route = useRoute()
7
-
8
7
  const { locale } = useI18n()
9
8
 
10
- let twikoo: any
11
-
12
9
  /**
13
10
  * init twikoo
14
11
  * @param options twikoo options
@@ -30,6 +27,6 @@ export function useTwikoo(options: {} = {}) {
30
27
  // 直接使用 CDN
31
28
  useScriptTag('//cdn.jsdelivr.net/npm/twikoo@1.5.1/dist/twikoo.all.min.js', () => {
32
29
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
- twikoo = initTwikoo(options)
30
+ initTwikoo(options)
34
31
  })
35
32
  }
@@ -1,9 +1,16 @@
1
1
  import { isClient, useScriptTag } from '@vueuse/core'
2
+ import { useHead } from '@vueuse/head'
2
3
  import { onUnmounted, watch } from 'vue'
3
4
  import { useI18n } from 'vue-i18n'
4
5
  import { useRoute } from 'vue-router'
5
6
 
6
7
  export function useWaline(options: {} = {}) {
8
+ useHead({
9
+ link: [
10
+ { rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/@waline/client/dist/waline.css' },
11
+ ],
12
+ })
13
+
7
14
  const route = useRoute()
8
15
 
9
16
  const { locale } = useI18n()
@@ -31,11 +38,11 @@ export function useWaline(options: {} = {}) {
31
38
  path: route.path,
32
39
  }
33
40
  const walineOptions = Object.assign(defaultOptions, options)
34
- return window.Waline(walineOptions)
41
+ return window.Waline.init(walineOptions)
35
42
  }
36
43
 
37
44
  // 直接使用 CDN
38
- useScriptTag('//cdn.jsdelivr.net/npm/@waline/client', () => {
45
+ useScriptTag('//cdn.jsdelivr.net/npm/@waline/client/dist/waline.js', () => {
39
46
  waline = initWaline(options)
40
47
  })
41
48
 
@@ -60,4 +67,6 @@ export function useWaline(options: {} = {}) {
60
67
  return
61
68
  waline.destroy()
62
69
  })
70
+
71
+ return waline
63
72
  }
@@ -1,16 +1,21 @@
1
- import { onMounted, onUnmounted, onUpdated } from 'vue'
1
+ import type { Ref } from 'vue'
2
+ import { onMounted, onUnmounted } from 'vue'
2
3
 
3
4
  // todo: refactor
4
5
 
5
- export function useActiveSidebarLinks() {
6
- let rootActiveLink: HTMLAnchorElement | null = null
7
- let activeLink: HTMLAnchorElement | null = null
8
-
6
+ export function useActiveSidebarLinks(container: Ref<HTMLElement>, marker: Ref<HTMLElement>) {
9
7
  const onScroll = throttleAndDebounce(setActiveLink, 200)
10
8
 
11
9
  function setActiveLink(): void {
12
- const sidebarLinks = getSidebarLinks()
13
- const anchors = getAnchors(sidebarLinks)
10
+ const sidebarLinks = [].slice.call(
11
+ document.querySelectorAll('.va-toc a.toc-link-item'),
12
+ ) as HTMLAnchorElement[]
13
+
14
+ const anchors = [].slice
15
+ .call(document.querySelectorAll('main .header-anchor'))
16
+ .filter((anchor: HTMLAnchorElement) =>
17
+ sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash),
18
+ ) as HTMLAnchorElement[]
14
19
 
15
20
  for (let i = 0; i < anchors.length; i++) {
16
21
  const anchor = anchors[i]
@@ -26,26 +31,25 @@ export function useActiveSidebarLinks() {
26
31
  }
27
32
  }
28
33
 
29
- function activateLink(hash: string | null): void {
30
- deactiveLink(activeLink)
31
- deactiveLink(rootActiveLink)
32
-
33
- activeLink = document.querySelector(`.va-toc a[href="${hash}"]`)
34
-
35
- if (!activeLink)
36
- return
37
-
38
- activeLink.classList.add('active')
39
-
40
- // also add active class to parent h2 anchors
41
- const rootLi = activeLink.closest('.right-sidebar-container > ul > li')
34
+ let prevActiveLink: HTMLAnchorElement | null = null
42
35
 
43
- if (rootLi && rootLi !== activeLink.parentElement) {
44
- rootActiveLink = rootLi.querySelector('a')
45
- rootActiveLink && rootActiveLink.classList.add('active')
36
+ function activateLink(hash: string | null): void {
37
+ deactiveLink(prevActiveLink)
38
+
39
+ const activeLink = (prevActiveLink
40
+ = hash == null
41
+ ? null
42
+ : container.value.querySelector(`.va-toc a[href="${hash}"]`) as HTMLAnchorElement)
43
+
44
+ // marker animation
45
+ if (activeLink) {
46
+ activeLink.classList.add('active')
47
+ marker.value.style.opacity = '1'
48
+ marker.value.style.top = `${activeLink.offsetTop + 2}px`
46
49
  }
47
50
  else {
48
- rootActiveLink = null
51
+ marker.value.style.opacity = '0'
52
+ marker.value.style.top = '54px'
49
53
  }
50
54
  }
51
55
 
@@ -54,34 +58,15 @@ export function useActiveSidebarLinks() {
54
58
  }
55
59
 
56
60
  onMounted(() => {
57
- setActiveLink()
61
+ requestAnimationFrame(setActiveLink)
58
62
  window.addEventListener('scroll', onScroll)
59
63
  })
60
64
 
61
- onUpdated(() => {
62
- // sidebar update means a route change
63
- activateLink(decodeURIComponent(location.hash))
64
- })
65
-
66
65
  onUnmounted(() => {
67
66
  window.removeEventListener('scroll', onScroll)
68
67
  })
69
68
  }
70
69
 
71
- function getSidebarLinks(): HTMLAnchorElement[] {
72
- return [].slice.call(
73
- document.querySelectorAll('.va-toc a.toc-link-item'),
74
- )
75
- }
76
-
77
- function getAnchors(sidebarLinks: HTMLAnchorElement[]): HTMLAnchorElement[] {
78
- return [].slice
79
- .call(document.querySelectorAll('.header-anchor'))
80
- .filter((anchor: HTMLAnchorElement) =>
81
- sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash),
82
- ) as HTMLAnchorElement[]
83
- }
84
-
85
70
  function getAnchorTop(anchor: HTMLAnchorElement): number {
86
71
  return anchor.parentElement!.offsetTop - 50
87
72
  }
@@ -59,7 +59,7 @@ footer:
59
59
  total_visitors: 总访客量
60
60
 
61
61
  counter:
62
- archives: 暂无日志 | 共计 1 篇日志 | 共计 {count} 篇日志
62
+ archives: 暂无日志 | 共计 {count} 篇日志
63
63
  categories: 暂无分类 | 共计 {count} 个分类
64
64
  tags: 暂无标签 | 共计 {count} 个标签
65
65
  albums:
@@ -5,7 +5,7 @@ export const install: UserModule = ({ isClient, router }) => {
5
5
  if (!isClient)
6
6
  return
7
7
 
8
- router.isReady().then(async() => {
8
+ router.isReady().then(async () => {
9
9
  const { registerSW } = await import('virtual:pwa-register')
10
10
  registerSW({ immediate: true })
11
11
  })
File without changes
@@ -3,10 +3,15 @@ import { useToggle } from '@vueuse/core'
3
3
 
4
4
  export const useAppStore = defineStore('app', () => {
5
5
  const [isSidebarOpen, toggleSidebar] = useToggle(false)
6
+ // right sidebar with toc
7
+ const [isRightSidebarOpen, toggleRightSidebar] = useToggle(false)
6
8
 
7
9
  return {
8
10
  isSidebarOpen,
9
11
  toggleSidebar,
12
+
13
+ isRightSidebarOpen,
14
+ toggleRightSidebar,
10
15
  }
11
16
  })
12
17
 
@@ -22,7 +22,9 @@
22
22
  z-index: var(--yun-z-sidebar);
23
23
 
24
24
  transform: translateX(-100%);
25
- transition: transform var(--va-transition-duration);
25
+ transition: box-shadow var(--va-transition-duration),
26
+ background-color var(--va-transition-duration), opacity 0.25s,
27
+ transform var(--va-transition-duration) cubic-bezier(0.19, 1, 0.22, 1) !important;
26
28
 
27
29
  &.open {
28
30
  transform: translateX(0);