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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/bin/valaxy.js +11 -0
- package/dist/build-OOT6HK6S.js +1 -0
- package/dist/build-SG32QSQ3.mjs +1 -0
- package/dist/chunk-7JDYOPID.js +1 -0
- package/dist/chunk-JJEBEWGI.mjs +1 -0
- package/dist/chunk-L3EDI35I.js +1 -0
- package/dist/chunk-L5SNNWFJ.js +78 -0
- package/dist/chunk-MVJUGWXR.mjs +1 -0
- package/dist/chunk-QI435Q25.mjs +78 -0
- package/dist/config-d6527c8c.d.ts +174 -0
- package/dist/node/cli.d.ts +3 -0
- package/dist/node/cli.js +6 -0
- package/dist/node/cli.mjs +6 -0
- package/dist/node/index.d.ts +45 -0
- package/dist/node/index.js +1 -0
- package/dist/node/index.mjs +1 -0
- package/dist/types/index.d.ts +110 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +75 -3
- package/src/client/App.vue +16 -0
- package/src/client/components/AppLink.vue +20 -0
- package/src/client/components/PostCard.vue +69 -0
- package/src/client/components/PostList.vue +50 -0
- package/src/client/components/README.md +7 -0
- package/src/client/components/ValaxyCopyright.vue +80 -0
- package/src/client/components/ValaxyFooter.vue +53 -0
- package/src/client/components/ValaxyHamburger.vue +21 -0
- package/src/client/components/ValaxyMd.vue +71 -0
- package/src/client/components/ValaxyOverlay.vue +44 -0
- package/src/client/components/ValaxyPagination.vue +122 -0
- package/src/client/components/ValaxyRightSidebar.vue +32 -0
- package/src/client/components/ValaxySidebar.vue +35 -0
- package/src/client/components/ValaxyToc.vue +70 -0
- package/src/client/composables/category.ts +101 -0
- package/src/client/composables/comments/index.ts +1 -0
- package/src/client/composables/comments/waline.ts +60 -0
- package/src/client/composables/common.ts +27 -0
- package/src/client/composables/dark.ts +4 -0
- package/src/client/composables/features/index.ts +1 -0
- package/src/client/composables/features/katex.ts +15 -0
- package/src/client/composables/helper.ts +26 -0
- package/src/client/composables/index.ts +17 -0
- package/src/client/composables/layout.ts +7 -0
- package/src/client/composables/post.ts +96 -0
- package/src/client/composables/search/algolia.ts +114 -0
- package/src/client/composables/search/index.ts +0 -0
- package/src/client/composables/sidebar.ts +128 -0
- package/src/client/composables/tag.ts +70 -0
- package/src/client/composables/widgets/aplayer.ts +23 -0
- package/src/client/composables/widgets/backToTop.ts +28 -0
- package/src/client/composables/widgets/codepen.ts +12 -0
- package/src/client/composables/widgets/index.ts +3 -0
- package/src/client/index.html +24 -0
- package/src/client/layouts/404.vue +25 -0
- package/src/client/layouts/README.md +14 -0
- package/src/client/locales/README.md +7 -0
- package/src/client/locales/en.yml +107 -0
- package/src/client/locales/zh-CN.yml +106 -0
- package/src/client/main.ts +30 -0
- package/src/client/modules/README.md +11 -0
- package/src/client/modules/nprogress.ts +14 -0
- package/src/client/modules/pinia.ts +17 -0
- package/src/client/modules/pwa.ts +12 -0
- package/src/client/modules/valaxy.ts +42 -0
- package/src/client/pages/README.md +20 -0
- package/src/client/pages/[...all].vue +15 -0
- package/src/client/pages/about/index.md +5 -0
- package/src/client/pages/hi/[name].vue +52 -0
- package/src/client/pages/index.vue +3 -0
- package/src/client/pages/page/[page].vue +12 -0
- package/src/client/pages/posts/index.md +5 -0
- package/src/client/public/_headers +3 -0
- package/src/client/public/favicon.svg +21 -0
- package/src/client/public/pwa-192x192.png +0 -0
- package/src/client/public/pwa-512x512.png +0 -0
- package/src/client/public/safari-pinned-tab.svg +41 -0
- package/src/client/shims.d.ts +36 -0
- package/src/client/stores/app.ts +14 -0
- package/src/client/stores/user.ts +35 -0
- package/src/client/styles/common/button.scss +29 -0
- package/src/client/styles/common/code.scss +35 -0
- package/src/client/styles/common/hamburger.scss +56 -0
- package/src/client/styles/common/markdown.scss +43 -0
- package/src/client/styles/common/scrollbar.scss +34 -0
- package/src/client/styles/common/sidebar.scss +30 -0
- package/src/client/styles/common/transition.scss +23 -0
- package/src/client/styles/css-vars/dark.scss +17 -0
- package/src/client/styles/css-vars/index.scss +18 -0
- package/src/client/styles/css-vars/light.scss +9 -0
- package/src/client/styles/global/helper.scss +3 -0
- package/src/client/styles/global/index.scss +38 -0
- package/src/client/styles/global/nprogress.scss +14 -0
- package/src/client/styles/global/reset.scss +20 -0
- package/src/client/styles/index.scss +18 -0
- package/src/client/styles/mixins/config.scss +1 -0
- package/src/client/styles/mixins/index.scss +2 -0
- package/src/client/styles/mixins/size.scss +49 -0
- package/src/client/styles/mixins/variable.scss +30 -0
- package/src/client/styles/palette.scss +61 -0
- package/src/client/styles/vars.scss +39 -0
- package/src/client/styles/widgets/banner.scss +116 -0
- package/src/client/types.ts +3 -0
- package/src/client/utils/helper.ts +30 -0
- package/src/client/utils/index.ts +2 -0
- package/src/client/utils/time.ts +23 -0
- package/src/core/config.ts +51 -0
- package/src/core/index.ts +5 -0
- package/src/core/utils.ts +1 -0
- package/src/index.ts +2 -0
- package/src/node/build.ts +12 -0
- package/src/node/cli.ts +177 -0
- package/src/node/config.ts +43 -0
- package/src/node/index.ts +1 -0
- package/src/node/markdown/headings.ts +24 -0
- package/src/node/markdown/index.ts +74 -0
- package/src/node/markdown/markdown-it-container.ts +53 -0
- package/src/node/markdown/markdown-it-katex.ts +200 -0
- package/src/node/markdown/parseHeader.ts +70 -0
- package/src/node/markdown/slugify.ts +24 -0
- package/src/node/options.ts +90 -0
- package/src/node/plugins/extendConfig.ts +28 -0
- package/src/node/plugins/index.ts +91 -0
- package/src/node/plugins/markdown.ts +62 -0
- package/src/node/plugins/preset.ts +174 -0
- package/src/node/plugins/unocss.ts +106 -0
- package/src/node/plugins/valaxy.ts +1 -0
- package/src/node/server.ts +21 -0
- package/src/node/shims.d.ts +23 -0
- package/src/node/utils/cli.ts +105 -0
- package/src/node/utils/index.ts +26 -0
- package/src/node/vite.ts +83 -0
- package/src/types/config.ts +250 -0
- package/src/types/index.ts +2 -0
- package/src/types/posts.ts +107 -0
- 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
|
+
©
|
|
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'
|