valaxy 0.0.2 → 0.0.7

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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/bin/valaxy.js +11 -0
  4. package/dist/build-OOT6HK6S.js +1 -0
  5. package/dist/build-SG32QSQ3.mjs +1 -0
  6. package/dist/chunk-7JDYOPID.js +1 -0
  7. package/dist/chunk-JJEBEWGI.mjs +1 -0
  8. package/dist/chunk-L3EDI35I.js +1 -0
  9. package/dist/chunk-L5SNNWFJ.js +78 -0
  10. package/dist/chunk-MVJUGWXR.mjs +1 -0
  11. package/dist/chunk-QI435Q25.mjs +78 -0
  12. package/dist/config-d6527c8c.d.ts +174 -0
  13. package/dist/node/cli.d.ts +3 -0
  14. package/dist/node/cli.js +6 -0
  15. package/dist/node/cli.mjs +6 -0
  16. package/dist/node/index.d.ts +45 -0
  17. package/dist/node/index.js +1 -0
  18. package/dist/node/index.mjs +1 -0
  19. package/dist/types/index.d.ts +110 -0
  20. package/dist/types/index.js +1 -0
  21. package/dist/types/index.mjs +1 -0
  22. package/package.json +75 -3
  23. package/src/client/App.vue +16 -0
  24. package/src/client/components/AppLink.vue +20 -0
  25. package/src/client/components/PostCard.vue +69 -0
  26. package/src/client/components/PostList.vue +50 -0
  27. package/src/client/components/README.md +7 -0
  28. package/src/client/components/ValaxyCopyright.vue +80 -0
  29. package/src/client/components/ValaxyFooter.vue +53 -0
  30. package/src/client/components/ValaxyHamburger.vue +21 -0
  31. package/src/client/components/ValaxyMd.vue +71 -0
  32. package/src/client/components/ValaxyOverlay.vue +44 -0
  33. package/src/client/components/ValaxyPagination.vue +122 -0
  34. package/src/client/components/ValaxyRightSidebar.vue +32 -0
  35. package/src/client/components/ValaxySidebar.vue +35 -0
  36. package/src/client/components/ValaxyToc.vue +70 -0
  37. package/src/client/composables/category.ts +101 -0
  38. package/src/client/composables/comments/index.ts +1 -0
  39. package/src/client/composables/comments/waline.ts +60 -0
  40. package/src/client/composables/common.ts +27 -0
  41. package/src/client/composables/dark.ts +4 -0
  42. package/src/client/composables/features/index.ts +1 -0
  43. package/src/client/composables/features/katex.ts +15 -0
  44. package/src/client/composables/helper.ts +26 -0
  45. package/src/client/composables/index.ts +17 -0
  46. package/src/client/composables/layout.ts +7 -0
  47. package/src/client/composables/post.ts +96 -0
  48. package/src/client/composables/search/algolia.ts +114 -0
  49. package/src/client/composables/search/index.ts +0 -0
  50. package/src/client/composables/sidebar.ts +128 -0
  51. package/src/client/composables/tag.ts +70 -0
  52. package/src/client/composables/widgets/aplayer.ts +23 -0
  53. package/src/client/composables/widgets/backToTop.ts +28 -0
  54. package/src/client/composables/widgets/codepen.ts +12 -0
  55. package/src/client/composables/widgets/index.ts +3 -0
  56. package/src/client/index.html +24 -0
  57. package/src/client/layouts/404.vue +25 -0
  58. package/src/client/layouts/README.md +14 -0
  59. package/src/client/locales/README.md +7 -0
  60. package/src/client/locales/en.yml +107 -0
  61. package/src/client/locales/zh-CN.yml +106 -0
  62. package/src/client/main.ts +30 -0
  63. package/src/client/modules/README.md +11 -0
  64. package/src/client/modules/nprogress.ts +14 -0
  65. package/src/client/modules/pinia.ts +17 -0
  66. package/src/client/modules/pwa.ts +12 -0
  67. package/src/client/modules/valaxy.ts +42 -0
  68. package/src/client/pages/README.md +20 -0
  69. package/src/client/pages/[...all].vue +15 -0
  70. package/src/client/pages/about/index.md +5 -0
  71. package/src/client/pages/hi/[name].vue +52 -0
  72. package/src/client/pages/index.vue +3 -0
  73. package/src/client/pages/page/[page].vue +12 -0
  74. package/src/client/pages/posts/index.md +5 -0
  75. package/src/client/public/_headers +3 -0
  76. package/src/client/public/favicon.svg +21 -0
  77. package/src/client/public/pwa-192x192.png +0 -0
  78. package/src/client/public/pwa-512x512.png +0 -0
  79. package/src/client/public/safari-pinned-tab.svg +41 -0
  80. package/src/client/shims.d.ts +36 -0
  81. package/src/client/stores/app.ts +14 -0
  82. package/src/client/stores/user.ts +35 -0
  83. package/src/client/styles/common/button.scss +29 -0
  84. package/src/client/styles/common/code.scss +35 -0
  85. package/src/client/styles/common/hamburger.scss +56 -0
  86. package/src/client/styles/common/markdown.scss +43 -0
  87. package/src/client/styles/common/scrollbar.scss +34 -0
  88. package/src/client/styles/common/sidebar.scss +30 -0
  89. package/src/client/styles/common/transition.scss +23 -0
  90. package/src/client/styles/css-vars/dark.scss +17 -0
  91. package/src/client/styles/css-vars/index.scss +18 -0
  92. package/src/client/styles/css-vars/light.scss +9 -0
  93. package/src/client/styles/global/helper.scss +3 -0
  94. package/src/client/styles/global/index.scss +38 -0
  95. package/src/client/styles/global/nprogress.scss +14 -0
  96. package/src/client/styles/global/reset.scss +20 -0
  97. package/src/client/styles/index.scss +18 -0
  98. package/src/client/styles/mixins/config.scss +1 -0
  99. package/src/client/styles/mixins/index.scss +2 -0
  100. package/src/client/styles/mixins/size.scss +49 -0
  101. package/src/client/styles/mixins/variable.scss +30 -0
  102. package/src/client/styles/palette.scss +61 -0
  103. package/src/client/styles/vars.scss +39 -0
  104. package/src/client/styles/widgets/banner.scss +116 -0
  105. package/src/client/types.ts +3 -0
  106. package/src/client/utils/helper.ts +30 -0
  107. package/src/client/utils/index.ts +2 -0
  108. package/src/client/utils/time.ts +23 -0
  109. package/src/core/config.ts +51 -0
  110. package/src/core/index.ts +5 -0
  111. package/src/core/utils.ts +1 -0
  112. package/src/index.ts +2 -0
  113. package/src/node/build.ts +12 -0
  114. package/src/node/cli.ts +177 -0
  115. package/src/node/config.ts +43 -0
  116. package/src/node/index.ts +1 -0
  117. package/src/node/markdown/headings.ts +24 -0
  118. package/src/node/markdown/index.ts +74 -0
  119. package/src/node/markdown/markdown-it-container.ts +53 -0
  120. package/src/node/markdown/markdown-it-katex.ts +200 -0
  121. package/src/node/markdown/parseHeader.ts +70 -0
  122. package/src/node/markdown/slugify.ts +24 -0
  123. package/src/node/options.ts +90 -0
  124. package/src/node/plugins/extendConfig.ts +28 -0
  125. package/src/node/plugins/index.ts +91 -0
  126. package/src/node/plugins/markdown.ts +62 -0
  127. package/src/node/plugins/preset.ts +174 -0
  128. package/src/node/plugins/unocss.ts +106 -0
  129. package/src/node/plugins/valaxy.ts +1 -0
  130. package/src/node/server.ts +21 -0
  131. package/src/node/shims.d.ts +23 -0
  132. package/src/node/utils/cli.ts +105 -0
  133. package/src/node/utils/index.ts +26 -0
  134. package/src/node/vite.ts +83 -0
  135. package/src/types/config.ts +250 -0
  136. package/src/types/index.ts +2 -0
  137. package/src/types/posts.ts +107 -0
  138. package/tsup.config.ts +17 -0
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from 'vue'
3
+ import type { Post } from 'valaxy'
4
+ import { usePostList } from '~/composables'
5
+
6
+ const props = withDefaults(defineProps<{
7
+ type?: string
8
+ posts?: Post[]
9
+ curPage?: number
10
+ }>(), {
11
+ curPage: 1,
12
+ })
13
+
14
+ const pageSize = ref(7)
15
+
16
+ const routes = usePostList({ type: props.type || '' })
17
+ const posts = computed(() => props.posts || routes.value)
18
+ const displayedPosts = computed(() => posts.value.slice((props.curPage - 1) * pageSize.value, props.curPage * pageSize.value))
19
+ </script>
20
+
21
+ <template>
22
+ <ul w="full" p="x-4 lt-sm:0">
23
+ <template v-if="!displayedPosts.length">
24
+ <div py2 op50>
25
+ 博主还什么都没写哦~
26
+ </div>
27
+ </template>
28
+
29
+ <Transition v-for="route, i in displayedPosts" :key="i" name="fade">
30
+ <PostCard :post="route" />
31
+ </Transition>
32
+ </ul>
33
+
34
+ <ValaxyPagination :cur-page="curPage" :page-size="pageSize" :total="posts.length" />
35
+ </template>
36
+
37
+ <style lang="scss">
38
+ .yun-card-actions {
39
+ border-top: 1px solid rgba(122, 122, 122, 0.15);
40
+ min-height: 2.5rem;
41
+ }
42
+
43
+ .post-categories {
44
+ color: var(--yun-c-text);
45
+ }
46
+
47
+ .post-tag {
48
+ color: var(--yun-c-text);
49
+ }
50
+ </style>
@@ -0,0 +1,7 @@
1
+ # Components
2
+
3
+ Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components).
4
+
5
+ ## Icons
6
+
7
+ You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/).
@@ -0,0 +1,80 @@
1
+ <script lang="ts" setup>
2
+ import { useConfig } from 'valaxy'
3
+ import { computed } from 'vue'
4
+ import { useI18n } from 'vue-i18n'
5
+
6
+ const { t, locale } = useI18n()
7
+
8
+ withDefaults(defineProps<{
9
+ url?: string
10
+ }>(), {
11
+ url: '',
12
+ })
13
+
14
+ const config = useConfig()
15
+
16
+ const ccVersion = (config.value.license.type === 'zero') ? '1.0' : '4.0'
17
+ const ccPrefix = (config.value.license.type === 'zero') ? 'publicdomain' : 'licenses'
18
+ const ccURL = computed(() => {
19
+ const ccLang = config.value.license.language ? config.value.license.language : (locale.value === 'zh-CN') ? 'zh' : 'en'
20
+ return `https://creativecommons.org/${ccPrefix}/${config.value.license.type}/${ccVersion}/deed.${ccLang}`
21
+ })
22
+
23
+ const licenseHtml = computed(() => {
24
+ return t('post.copyright.license_content', [`<a href="${ccURL.value}" target="_blank" rel="noopener" title="CC ${`${config.value.license.type.toUpperCase()} ${ccVersion}`} ">CC ${config.value.license.type.toUpperCase()}</a>`])
25
+ })
26
+ </script>
27
+
28
+ <template>
29
+ <ul class="post-copyright">
30
+ <li class="post-copyright-author">
31
+ <strong>
32
+ {{ t('post.copyright.author') + t('symbol.colon') }}
33
+ </strong>
34
+ <span>{{ config.author.name }}</span>
35
+ </li>
36
+ <li v-if="url" class="post-copyright-link">
37
+ <strong>
38
+ {{ t('post.copyright.link') + t('symbol.colon') }}
39
+ </strong>
40
+ <a :href="url">
41
+ {{ url }}
42
+ </a>
43
+ </li>
44
+ <li class="post-copyright-license">
45
+ <strong>
46
+ {{ t('post.copyright.license_title') + t('symbol.colon') }}
47
+ </strong>
48
+ <span v-html="licenseHtml" />
49
+ </li>
50
+ </ul>
51
+ </template>
52
+
53
+ <style lang="scss">
54
+ @use "~/styles/mixins" as *;
55
+
56
+ .post-copyright {
57
+ font-size: 0.9rem;
58
+ padding: 0.5rem 1rem;
59
+ border-left: 4px solid #ff5252;
60
+ background-color: var(--yun-c-bg-dark);
61
+ list-style: none;
62
+ word-break: break-all;
63
+ position: relative;
64
+ overflow: hidden;
65
+
66
+ &::after {
67
+ pointer-events: none;
68
+
69
+ position: absolute;
70
+ color: white;
71
+ background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 496 512'%3E%3Cpath fill='gray' d='M245.8 214.9l-33.2 17.3c-9.4-19.6-25.2-20-27.4-20-22.2 0-33.3 14.6-33.3 43.9 0 23.5 9.2 43.8 33.3 43.8 14.4 0 24.6-7 30.5-21.3l30.6 15.5a73.2 73.2 0 01-65.1 39c-22.6 0-74-10.3-74-77 0-58.7 43-77 72.6-77 30.8-.1 52.7 11.9 66 35.8zm143 0l-32.7 17.3c-9.5-19.8-25.7-20-27.9-20-22.1 0-33.2 14.6-33.2 43.9 0 23.5 9.2 43.8 33.2 43.8 14.5 0 24.7-7 30.5-21.3l31 15.5c-2 3.8-21.3 39-65 39-22.7 0-74-9.9-74-77 0-58.7 43-77 72.6-77C354 179 376 191 389 214.8zM247.7 8C104.7 8 0 123 0 256c0 138.4 113.6 248 247.6 248C377.5 504 496 403 496 256 496 118 389.4 8 247.6 8zm.8 450.8c-112.5 0-203.7-93-203.7-202.8 0-105.5 85.5-203.3 203.8-203.3A201.7 201.7 0 01451.3 256c0 121.7-99.7 202.9-202.9 202.9z'/%3E%3C/svg%3E");
72
+ content: ' ';
73
+ height: 10rem;
74
+ width: 10rem;
75
+ right: -2rem;
76
+ top: -2rem;
77
+ opacity: 0.1;
78
+ }
79
+ }
80
+ </style>
@@ -0,0 +1,53 @@
1
+ <script lang="ts" setup>
2
+ import { capitalize, computed } from 'vue'
3
+ import { useConfig, useThemeConfig } from 'valaxy'
4
+ import { useI18n } from 'vue-i18n'
5
+
6
+ import themePkg from 'valaxy-theme-yun/package.json'
7
+ import pkg from '~/../../package.json'
8
+
9
+ const { t } = useI18n()
10
+
11
+ const config = useConfig()
12
+ const themeConfig = useThemeConfig()
13
+
14
+ const year = new Date().getFullYear()
15
+
16
+ const isThisYear = computed(() => {
17
+ return year === themeConfig.value.footer.since
18
+ })
19
+
20
+ const poweredHtml = computed(() => t('footer.powered', [`<a href="${pkg.repository}" target="_blank" rel="noopener">Valaxy</a> v${pkg.version}`]))
21
+ </script>
22
+
23
+ <template>
24
+ <footer class="val-footer p-4 opacity-80" text="center sm">
25
+ <div v-if="themeConfig.footer.beian.enable && themeConfig.footer.beian.icp" class="beian" m="y-2">
26
+ <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">
27
+ {{ themeConfig.footer.beian.icp }}
28
+ </a>
29
+ </div>
30
+
31
+ <div class="copyright flex justify-center items-center" p="1">
32
+ <span>
33
+ &copy;
34
+ <template v-if="!isThisYear">
35
+ {{ themeConfig.footer.since }} -
36
+ </template>
37
+ {{ year }}
38
+ </span>
39
+
40
+ <a m="x-2" class="inline-flex animate-pulse" :href="themeConfig.footer.icon.url" target="_blank" :title="themeConfig.footer.icon.title">
41
+ <div :class="themeConfig.footer.icon.name" />
42
+ </a>
43
+
44
+ <span>{{ config.author.name }}</span>
45
+ </div>
46
+
47
+ <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>
49
+ </div>
50
+
51
+ <slot />
52
+ </footer>
53
+ </template>
@@ -0,0 +1,21 @@
1
+ <script lang="ts" setup>
2
+ defineProps<{
3
+ active?: boolean
4
+ }>()
5
+ </script>
6
+
7
+ <template>
8
+ <button
9
+ type="button"
10
+ class="vt-hamburger"
11
+ :class="{ 'is-active': active }"
12
+ aria-label="mobile navigation"
13
+ :aria-expanded="active"
14
+ >
15
+ <span class="vt-hamburger-container">
16
+ <span class="vt-hamburger-top" />
17
+ <span class="vt-hamburger-middle" />
18
+ <span class="vt-hamburger-bottom" />
19
+ </span>
20
+ </button>
21
+ </template>
@@ -0,0 +1,71 @@
1
+ <script lang="ts" setup>
2
+ import type { Post } from 'valaxy'
3
+ import { onMounted, ref } from 'vue'
4
+ import { useI18n } from 'vue-i18n'
5
+ import { useAplayer, useCodePen, useKatex } from '~/composables'
6
+ import { wrapTable } from '~/utils'
7
+
8
+ const props = defineProps<{
9
+ frontmatter: Post
10
+ excerpt?: string
11
+ }>()
12
+
13
+ const { t } = useI18n()
14
+
15
+ const content = ref()
16
+ function updateDom() {
17
+ wrapTable(content.value)
18
+ }
19
+
20
+ onMounted(() => {
21
+ updateDom()
22
+ })
23
+
24
+ // features
25
+ if (props.frontmatter.katex)
26
+ useKatex()
27
+
28
+ // widgets
29
+ if (props.frontmatter.aplayer)
30
+ useAplayer()
31
+
32
+ if (props.frontmatter.codepen)
33
+ useCodePen()
34
+ </script>
35
+
36
+ <template>
37
+ <article v-if="$slots.default" class="markdown-body">
38
+ <slot ref="content" @vnode-updated="updateDom" />
39
+
40
+ <div text="center">
41
+ <a
42
+ v-if="frontmatter.url"
43
+ :href="frontmatter.url"
44
+ class="post-link-btn shadow hover:shadow-md"
45
+ rounded
46
+ target="_blank"
47
+ m="b-4"
48
+ >
49
+ {{ t('post.view_link') }}
50
+ </a>
51
+ </div>
52
+
53
+ <slot v-if="typeof frontmatter.end !== 'undefined'" name="end">
54
+ <div m="y-4" class="end flex justify-center items-center">
55
+ <hr class="line inline-flex" w="full" m="!y-2">
56
+ <span p="x-4" font="serif" class="whitespace-nowrap">
57
+ {{ frontmatter.end ? 'Q.E.D.' : 'To Be Continued.' }}
58
+ </span>
59
+ <hr class="line inline-flex" w="full" m="!y-2">
60
+ </div>
61
+ </slot>
62
+ </article>
63
+ </template>
64
+
65
+ <style lang="scss">
66
+ .end {
67
+ .line {
68
+ height: 1px;
69
+ }
70
+ }
71
+ </style>
@@ -0,0 +1,44 @@
1
+ <script lang="ts" setup>
2
+ withDefaults(defineProps<{
3
+ show: boolean
4
+ }>(), {
5
+ show: false,
6
+ })
7
+ </script>
8
+
9
+ <template>
10
+ <transition name="fade">
11
+ <div v-if="show" class="val-overlay backdrop-filter backdrop-blur" />
12
+ </transition>
13
+ </template>
14
+
15
+ <style lang="scss">
16
+ @use "sass:map";
17
+
18
+ @use "~/styles/vars" as *;
19
+ @use "~/styles/mixins" as *;
20
+
21
+ .val-overlay {
22
+ background-color: rgba(0, 0, 0, 0.3);
23
+ position: fixed;
24
+ top: 0;
25
+ right: 0;
26
+ bottom: 0;
27
+ left: 0;
28
+ z-index: map.get($z-index, 'sidebar') - 1;
29
+ transition: opacity 0.4s;
30
+
31
+ display: none;
32
+
33
+ &.fade-enter-from,
34
+ &.fade-leave-to {
35
+ opacity: 0;
36
+ }
37
+ }
38
+
39
+ @include mobile {
40
+ .val-overlay {
41
+ display: block;
42
+ }
43
+ }
44
+ </style>
@@ -0,0 +1,122 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+ const props = defineProps<{
4
+ /**
5
+ * Cur Page Number
6
+ */
7
+ curPage: number
8
+ /**
9
+ * Total Pages
10
+ */
11
+ total: number
12
+ /**
13
+ * Page Size
14
+ */
15
+ pageSize: number
16
+ }>()
17
+
18
+ const emit = defineEmits(['page-change'])
19
+
20
+ const totalPages = computed(() => Math.ceil(props.total / props.pageSize))
21
+
22
+ /**
23
+ * 围绕的长度
24
+ */
25
+ const surLen = computed(() => {
26
+ if (props.curPage === 1 || props.curPage === totalPages.value)
27
+ return 3
28
+ else
29
+ return 2
30
+ })
31
+
32
+ const showPage = (i: number) => {
33
+ if (i === 1) return true
34
+ else if (i === totalPages.value) return true
35
+ return i > props.curPage - surLen.value && i < props.curPage + surLen.value
36
+ }
37
+
38
+ const jumpTo = (page: number) => {
39
+ emit('page-change', page)
40
+ if (page === 1) return '/'
41
+ else return `/page/${page}`
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <nav class="pagination">
47
+ <router-link v-if="curPage !== 1" class="page-number" :to="jumpTo(curPage - 1)">
48
+ <div i-ri-arrow-left-s-line />
49
+ </router-link>
50
+
51
+ <template v-for="i in totalPages">
52
+ <router-link v-if="showPage(i)" :key="i" class="page-number" :class="curPage === i && 'active'" :to="jumpTo(i)">
53
+ {{ i }}
54
+ </router-link>
55
+ <span v-else-if="i === curPage - surLen" :key="`prev-space-${i}`" class="space" disabled>
56
+ ...
57
+ </span>
58
+ <span v-else-if="i === curPage + surLen" :key="`next-space-${i}`" class="space" disabled>
59
+ ...
60
+ </span>
61
+ </template>
62
+
63
+ <router-link v-if="curPage !== totalPages" class="page-number" :to="jumpTo(curPage + 1)">
64
+ <div i-ri-arrow-right-s-line />
65
+ </router-link>
66
+ </nav>
67
+ </template>
68
+
69
+ <style lang="scss">
70
+ :root {
71
+ --page-btn-bg-color: rgba(255, 255, 255, 0.5);
72
+ --page-btn-hover-bg-color: var(--yun-c-primary-lighter);
73
+ --page-btn-active-bg-color: var(--yun-c-primary-light);
74
+ }
75
+
76
+ .dark {
77
+ --page-btn-bg-color: var(--yun-c-bg-light);
78
+ }
79
+
80
+ .pagination {
81
+ display: flex;
82
+ justify-content: center;
83
+ align-items: center;
84
+
85
+ .prev, .next, .page-number, .space {
86
+ display: inline-flex;
87
+ justify-content: center;
88
+ align-items: center;
89
+
90
+ width: 2rem;
91
+ height: 2rem;
92
+ margin: 0;
93
+ transition: background-color var(--yun-transition-duration) ease;
94
+ }
95
+
96
+ .prev, .next, .page-number {
97
+ cursor: pointer;
98
+
99
+ color: var(--yun-c-text);
100
+ text-decoration: none;
101
+ background-color: var(--page-btn-bg-color);
102
+
103
+ &:hover {
104
+ color: var(--yun-c-bg);
105
+ background: var(--page-btn-hover-bg-color);
106
+ }
107
+
108
+ &:active {
109
+ color: var(--yun-c-bg);
110
+ background: var(--page-btn-active-bg-color);
111
+ }
112
+
113
+ &.active {
114
+ font-weight: normal;
115
+ background: var(--page-btn-active-bg-color);
116
+ color: var(--yun-c-bg);
117
+ cursor: default;
118
+ }
119
+ }
120
+ }
121
+
122
+ </style>
@@ -0,0 +1,32 @@
1
+ <script lang="ts" setup>
2
+ import { useI18n } from 'vue-i18n'
3
+ import type { Post } from '../../types'
4
+ const { t } = useI18n()
5
+
6
+ defineProps<{ frontmatter: Post }>()
7
+ </script>
8
+
9
+ <template>
10
+ <aside class="right-sidebar val-card relative" m="l-4" text="center">
11
+ <h2 v-if="frontmatter.toc" m="t-6 b-2" font="serif black">
12
+ {{ t('sidebar.toc') }}
13
+ </h2>
14
+
15
+ <div class="right-sidebar-container sticky">
16
+ <ValaxyToc v-if="frontmatter.toc" />
17
+
18
+ <div v-if="$slots.custom" class="custom-container">
19
+ <slot name="custom" />
20
+ </div>
21
+ </div>
22
+ </aside>
23
+ </template>
24
+
25
+ <style lang="scss">
26
+ .right-sidebar {
27
+ width: var(--yun-sidebar-width-mobile);
28
+ }
29
+ .right-sidebar-container {
30
+ top: 1rem;
31
+ }
32
+ </style>
@@ -0,0 +1,35 @@
1
+ <script lang="ts" setup>
2
+ import { useLayout } from '~/composables'
3
+ import { useAppStore } from '~/stores/app'
4
+
5
+ const app = useAppStore()
6
+ const isHome = useLayout('home')
7
+ </script>
8
+
9
+ <template>
10
+ <ValaxyOverlay :show="app.isSidebarOpen" @click="app.toggleSidebar()" />
11
+
12
+ <ValaxyHamburger :active="app.isSidebarOpen" class="menu-btn sidebar-toggle yun-icon-btn" :class="isHome ? '' : 'md:hidden'" @click="app.toggleSidebar()" />
13
+
14
+ <aside class="val-card" :class="['sidebar', app.isSidebarOpen && 'open', !isHome && 'md:translate-x-0']">
15
+ <YunSidebar />
16
+
17
+ <YunConfig />
18
+ </aside>
19
+ </template>
20
+
21
+ <style lang="scss">
22
+ @use "sass:map";
23
+
24
+ @use "~/styles/vars" as *;
25
+
26
+ .menu-btn {
27
+ display: inline-flex;
28
+ position: fixed;
29
+ left: 0.8rem;
30
+ top: 0.6rem;
31
+ line-height: 1;
32
+ z-index: map.get($z-index, 'menu-btn');
33
+ cursor: pointer;
34
+ }
35
+ </style>
@@ -0,0 +1,70 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+ import { useRoute } from 'vue-router'
4
+
5
+ import { useActiveSidebarLinks } from '~/composables'
6
+
7
+ const route = useRoute()
8
+ const headers = computed(() => route.meta.headers)
9
+
10
+ useActiveSidebarLinks()
11
+
12
+ function getStylesByLevel(level: number) {
13
+ return {
14
+ fontSize: `${(6 - level) * 0.2 + 0.4}rem`,
15
+ paddingLeft: `${level * 1 - 1}rem`,
16
+ }
17
+ }
18
+
19
+ // todo mobile toc widget
20
+ </script>
21
+
22
+ <template>
23
+ <ul class="val-toc" p="l-4">
24
+ <li v-for="header, i in headers" :key="i" :style="getStylesByLevel(header.level)">
25
+ <a class="toc-link-item" :href="`#${header.slug}`">{{ header.title }}</a>
26
+ </li>
27
+ </ul>
28
+ </template>
29
+
30
+ <style lang="scss">
31
+ .val-toc {
32
+ top: 10px;
33
+ width: var(--yun-sidebar-width-mobile);
34
+
35
+ background-color: var(--yun-c-bg-light);
36
+
37
+ font-size: 1rem;
38
+ font-family: var(--yun-font-serif);
39
+ font-weight: 900;
40
+ line-height: 1.6;
41
+
42
+ text-align: left;
43
+
44
+ a {
45
+ display: block;
46
+ color: var(--c-toc-link);
47
+ transition: color var(--yun-transition-duration);
48
+
49
+ overflow: hidden;
50
+ white-space: nowrap;
51
+ text-overflow: ellipsis;
52
+
53
+ &:hover {
54
+ color: var(--yun-c-text);
55
+ }
56
+ }
57
+
58
+ .toc-link-item {
59
+ color: var(--yun-c-text-light);
60
+
61
+ &:hover {
62
+ color: var(--yun-c-text);
63
+ }
64
+
65
+ &.active {
66
+ color: var(--yun-c-primary);
67
+ }
68
+ }
69
+ }
70
+ </style>
@@ -0,0 +1,101 @@
1
+ import type { Post } from 'valaxy'
2
+ import { usePostList } from './post'
3
+
4
+ export interface ParentCategory {
5
+ total: number
6
+ children: Categories
7
+ }
8
+
9
+ export interface PostCategory {
10
+ total: number
11
+ posts: Post[]
12
+ }
13
+
14
+ export type Category = ParentCategory | PostCategory
15
+
16
+ // export type Categories = Map<string, Post[] | Category>
17
+ export type Categories = Map<string, Category>
18
+
19
+ /**
20
+ * get categories from posts
21
+ * @returns
22
+ */
23
+ export function useCategory() {
24
+ const posts = usePostList()
25
+
26
+ const categoryMap: Category = {
27
+ total: posts.value.length,
28
+ children: new Map([
29
+ ['Uncategorized', { total: 0, posts: [] }],
30
+ ]),
31
+ }
32
+
33
+ const uncategorized = categoryMap.children.get('Uncategorized') as PostCategory
34
+
35
+ posts.value.forEach((post) => {
36
+ if (post.categories) {
37
+ if (Array.isArray(post.categories)) {
38
+ const len = post.categories.length
39
+
40
+ let c: ParentCategory = categoryMap
41
+ post.categories.forEach((category, i) => {
42
+ if (i === len - 1) {
43
+ if (c.children.has(category)) {
44
+ const cur = c.children.get(category) as PostCategory
45
+ if (cur.posts) {
46
+ cur.total += 1
47
+ cur.posts!.push(post)
48
+ }
49
+ }
50
+ else {
51
+ c.children?.set(category, {
52
+ total: 1,
53
+ posts: [post],
54
+ })
55
+ }
56
+ }
57
+ else {
58
+ if (c.children?.has(category)) {
59
+ const cur = c.children.get(category) as ParentCategory
60
+ cur.total += 1
61
+ c = cur
62
+ }
63
+ else {
64
+ const temp = {
65
+ total: 1,
66
+ children: new Map(),
67
+ }
68
+ c.children?.set(category, temp)
69
+ c = temp
70
+ }
71
+ }
72
+ })
73
+ }
74
+ else {
75
+ // for string
76
+ const category = post.categories
77
+ if (categoryMap.children.has(category)) {
78
+ const cur = categoryMap.children.get(category) as PostCategory
79
+ cur.total += 1
80
+ cur.posts.push(post)
81
+ }
82
+ else {
83
+ categoryMap.children.set(category, {
84
+ total: 1,
85
+ posts: [post],
86
+ })
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ uncategorized.total += 1
92
+ uncategorized.posts.push(post)
93
+ }
94
+ })
95
+
96
+ // clear uncategorized
97
+ if (uncategorized!.total === 0)
98
+ categoryMap.children?.delete('Uncategorized')
99
+
100
+ return categoryMap
101
+ }
@@ -0,0 +1 @@
1
+ export * from './waline'