mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
feat: support reading time
This commit is contained in:
parent
99f04bb2d0
commit
aa9b8727db
149
pnpm-lock.yaml
generated
149
pnpm-lock.yaml
generated
@ -511,17 +511,20 @@ importers:
|
||||
specifier: 4.2.5
|
||||
version: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-comment2:
|
||||
specifier: 2.0.0-rc.5
|
||||
version: 2.0.0-rc.5(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-plugin-md-enhance:
|
||||
specifier: 2.0.0-rc.5
|
||||
version: 2.0.0-rc.5(markdown-it@13.0.2)(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(markdown-it@13.0.2)(typescript@5.3.3)
|
||||
vuepress-plugin-reading-time2:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-plugin-seo2:
|
||||
specifier: 2.0.0-rc.5
|
||||
version: 2.0.0-rc.5(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-plugin-sitemap2:
|
||||
specifier: 2.0.0-rc.5
|
||||
version: 2.0.0-rc.5(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
devDependencies:
|
||||
'@types/lodash.merge':
|
||||
specifier: ^4.6.9
|
||||
@ -1956,14 +1959,14 @@ packages:
|
||||
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
|
||||
dev: false
|
||||
|
||||
/@lit-labs/ssr-dom-shim@1.1.0:
|
||||
resolution: {integrity: sha512-92uQ5ARf7UXYrzaFcAX3T2rTvaS9Z1//ukV+DqjACM4c8s0ZBQd7ayJU5Dh2AFLD/Ayuyz4uMmxQec8q3U4Ong==}
|
||||
/@lit-labs/ssr-dom-shim@1.1.2:
|
||||
resolution: {integrity: sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==}
|
||||
dev: false
|
||||
|
||||
/@lit/reactive-element@1.6.1:
|
||||
resolution: {integrity: sha512-va15kYZr7KZNNPZdxONGQzpUr+4sxVu7V/VG7a8mRfPPXUyhEYj5RzXCQmGrlP3tAh0L3HHm5AjBMFYRqlM9SA==}
|
||||
/@lit/reactive-element@2.0.2:
|
||||
resolution: {integrity: sha512-SVOwLAWUQg3Ji1egtOt1UiFe4zdDpnWHyc5qctSceJ5XIu0Uc76YmGpIjZgx9YJ0XtdW0Jm507sDvjOu+HnB8w==}
|
||||
dependencies:
|
||||
'@lit-labs/ssr-dom-shim': 1.1.0
|
||||
'@lit-labs/ssr-dom-shim': 1.1.2
|
||||
dev: false
|
||||
|
||||
/@lukeed/ms@2.0.1:
|
||||
@ -9425,10 +9428,10 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/giscus@1.3.0:
|
||||
resolution: {integrity: sha512-A3tVLgSmpnh2sX9uGjo9MbzmTTEJirSyFUPRvkipvy37y9rhxUYDoh9kO37QVrP7Sc7QuJ+gihB6apkO0yDyTw==}
|
||||
/giscus@1.4.0:
|
||||
resolution: {integrity: sha512-Pll+pcclTx47NcFDw8nuka2Ja85Gc4XWpzSgL0rszOQaMQRQIV8UMR+zP4a+/N3tV2TXc1SZ537kWlsN6EsAaw==}
|
||||
dependencies:
|
||||
lit: 2.7.6
|
||||
lit: 3.1.0
|
||||
dev: false
|
||||
|
||||
/git-hooks-list@3.0.0:
|
||||
@ -11280,26 +11283,26 @@ packages:
|
||||
wrap-ansi: 9.0.0
|
||||
dev: true
|
||||
|
||||
/lit-element@3.3.1:
|
||||
resolution: {integrity: sha512-Gl+2409uXWbf7n6cCl7Kzasm7zjT9xmdwi2BhLNi70sRKAgRkqueDu5mSIH3hPYMM0/vqBCdPXod3NbGkRA2ww==}
|
||||
/lit-element@4.0.2:
|
||||
resolution: {integrity: sha512-/W6WQZUa5VEXwC7H9tbtDMdSs9aWil3Ou8hU6z2cOKWbsm/tXPAcsoaHVEtrDo0zcOIE5GF6QgU55tlGL2Nihg==}
|
||||
dependencies:
|
||||
'@lit-labs/ssr-dom-shim': 1.1.0
|
||||
'@lit/reactive-element': 1.6.1
|
||||
lit-html: 2.7.2
|
||||
'@lit-labs/ssr-dom-shim': 1.1.2
|
||||
'@lit/reactive-element': 2.0.2
|
||||
lit-html: 3.1.0
|
||||
dev: false
|
||||
|
||||
/lit-html@2.7.2:
|
||||
resolution: {integrity: sha512-ZJCfKlA2XELu5tn7XuzOziGFGvf1SeQm+ngLWoJ8bXtSkRrrR3ms6SWy+gsdxeYwySLij5xAhdd2C3EX0ftxdQ==}
|
||||
/lit-html@3.1.0:
|
||||
resolution: {integrity: sha512-FwAjq3iNsaO6SOZXEIpeROlJLUlrbyMkn4iuv4f4u1H40Jw8wkeR/OUXZUHUoiYabGk8Y4Y0F/rgq+R4MrOLmA==}
|
||||
dependencies:
|
||||
'@types/trusted-types': 2.0.2
|
||||
dev: false
|
||||
|
||||
/lit@2.7.6:
|
||||
resolution: {integrity: sha512-1amFHA7t4VaaDe+vdQejSVBklwtH9svGoG6/dZi9JhxtJBBlqY5D1RV7iLUYY0trCqQc4NfhYYZilZiVHt7Hxg==}
|
||||
/lit@3.1.0:
|
||||
resolution: {integrity: sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==}
|
||||
dependencies:
|
||||
'@lit/reactive-element': 1.6.1
|
||||
lit-element: 3.3.1
|
||||
lit-html: 2.7.2
|
||||
'@lit/reactive-element': 2.0.2
|
||||
lit-element: 4.0.2
|
||||
lit-html: 3.1.0
|
||||
dev: false
|
||||
|
||||
/load-json-file@4.0.0:
|
||||
@ -16383,14 +16386,14 @@ packages:
|
||||
typescript: 5.3.3
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-comment2@2.0.0-rc.5(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-EVYsUIIWLFUQoxrALdVcBPnSDPJfXWrsrpbryuWUFDkpjstm7gMHgNGJr6vkaqmP92BkysXcwJ2EuN4OweMtcA==}
|
||||
/vuepress-plugin-comment2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-NOGhWS9jrmcFgkaNd5AGtuERok3mbSPBQQ5CV8Uegs0409Zm1L0kmhOPB959Z1KwLxfoNvhD97XruWcQ29bhUw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
'@waline/client': ^2.15.8 || ^3.0.0-alpha.7
|
||||
artalk: ^2.6.4
|
||||
'@waline/client': ^2.15.8 || ^3.0.0-alpha.8
|
||||
artalk: ^2.7.2
|
||||
sass-loader: ^13.3.2
|
||||
twikoo: ^1.6.26
|
||||
twikoo: ^1.5.0
|
||||
vuepress: 2.0.0-rc.0
|
||||
vuepress-vite: 2.0.0-rc.0
|
||||
vuepress-webpack: 2.0.0-rc.0
|
||||
@ -16413,34 +16416,34 @@ packages:
|
||||
'@vuepress/client': 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
giscus: 1.3.0
|
||||
giscus: 1.4.0
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-md-enhance@2.0.0-rc.5(markdown-it@13.0.2)(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-e7xiodPfKLIG8vVHZ9Guk97sc+7w4t0FzBlye6YYKTOd1Csm40hRqvBMp69WmDgzmp6zYdprifw1mC9do17dhw==}
|
||||
/vuepress-plugin-md-enhance@2.0.0-rc.6(markdown-it@13.0.2)(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-cEsMccjqdNFq4UjnFbg9OlBwrIF9Ducr2MX2G+6p4h17yJ8yf7NctpGZwnVMh2FGmQ7oYjcIpkuUDrkLn4elzw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
'@types/reveal.js': ^4.4.5
|
||||
'@vue/repl': ^3.0.0
|
||||
chart.js: ^4.4.0
|
||||
echarts: ^5.4.3
|
||||
flowchart.ts: ^2.0.0
|
||||
katex: ^0.16.9
|
||||
kotlin-playground: ^1.29.0
|
||||
markmap-lib: ^0.15.7
|
||||
markmap-toolbar: ^0.15.6
|
||||
markmap-view: ^0.15.6
|
||||
chart.js: ^4.0.0
|
||||
echarts: ^5.0.0
|
||||
flowchart.ts: ^2.0.0 || ^3.0.0
|
||||
katex: ^0.16.0
|
||||
kotlin-playground: ^1.23.0
|
||||
markmap-lib: ^0.15.5
|
||||
markmap-toolbar: ^0.15.5
|
||||
markmap-view: ^0.15.5
|
||||
mathjax-full: ^3.2.2
|
||||
mermaid: ^10.6.1
|
||||
reveal.js: ^5.0.2
|
||||
mermaid: ^10.6.0
|
||||
reveal.js: ^5.0.0
|
||||
sass-loader: ^13.3.2
|
||||
vuepress: 2.0.0-rc.0
|
||||
vuepress-vite: 2.0.0-rc.0
|
||||
@ -16511,8 +16514,8 @@ packages:
|
||||
js-yaml: 4.1.0
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- markdown-it
|
||||
@ -16520,8 +16523,32 @@ packages:
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-sass-palette@2.0.0-rc.5(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-ovAv5xGSu5T2+VlszjZpstDKKVH0wedVm13Vvt6RI6VJujh1fpQy+/g4yNK09U+HNd+sDMZoYCY7epF8CWXOXA==}
|
||||
/vuepress-plugin-reading-time2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-GgyKWS66QvlrXV2zMF0qhgtEpELvN0kSOEAqgGn8mR+01TgLirdq+k9rExp1zab7UH7h8FjtRgWlcYgfPUbGEA==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
vuepress-vite: 2.0.0-rc.0
|
||||
vuepress-webpack: 2.0.0-rc.0
|
||||
peerDependenciesMeta:
|
||||
vuepress:
|
||||
optional: true
|
||||
vuepress-vite:
|
||||
optional: true
|
||||
vuepress-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vuepress/client': 2.0.0-rc.0(typescript@5.3.3)
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-sass-palette@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-/LAcJvznI5C/cSO0IM2btGivA9IgOON+YwpEzHGhkZKwBKx/lLqOpHH4ghaKmC/hX72QISyM1pjQJ/9pjOQEOg==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
sass-loader: ^13.3.2
|
||||
@ -16542,15 +16569,15 @@ packages:
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
chokidar: 3.5.3
|
||||
sass: 1.69.5
|
||||
vuepress-shared: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-seo2@2.0.0-rc.5(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-VwnBF1zuIjwrIQzAKQQm2l0QucZ/MqEnm3l5Hdg/katGuSna4AjEnhVDswwr4plHliNYWNzcu9V2o0tqEaRouw==}
|
||||
/vuepress-plugin-seo2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-ZvYQNV/aZV5iCi7D7qg1Bz7rrQ00f9exPQ+m/JEsJr+uH0g1frAbCI46Ilu0Y42+XTU6id/wO23yKoS0GFQ8jw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16566,15 +16593,15 @@ packages:
|
||||
dependencies:
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
vuepress-shared: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-sitemap2@2.0.0-rc.5(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-b1ylNdPLsmhQ+R0NzyaIXHaAybFf0sB47TnYc43X9O8Ql+O8TI6jpBcF8DID7pWp5scQIdf3BIQ1yd/Q0wQgnw==}
|
||||
/vuepress-plugin-sitemap2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-b9gNdmaUsXRBpE1OKkTmp/WhCBKQgkHQHhEK1oK9oZiCEAP4Xhmnob5UhtS7WeBK9HBsjCCCUwAEBbNZ8WdiEw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16591,15 +16618,15 @@ packages:
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
sitemap: 7.1.1
|
||||
vuepress-shared: 2.0.0-rc.5(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-shared@2.0.0-rc.5(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-J+N3/sb966uI5wSs4k6QLrwxSE78Z77hBRdNKNN9HrhTXQX5SqIV5gqqnS24OfI5GxEWrl4Eba40ECwJk9hKlA==}
|
||||
/vuepress-shared@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-bcEBxOX0ulWtCeRCBOdIpvFC+m4HvyWGLm6CPXedPiHaSl6avp/S6akYNcj2dyBPXxC5v3WfiGJDumis0fqYbg==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
|
||||
@ -73,10 +73,11 @@
|
||||
"ts-debounce": "^4.0.0",
|
||||
"vue": "^3.3.13",
|
||||
"vue-router": "4.2.5",
|
||||
"vuepress-plugin-comment2": "2.0.0-rc.5",
|
||||
"vuepress-plugin-md-enhance": "2.0.0-rc.5",
|
||||
"vuepress-plugin-seo2": "2.0.0-rc.5",
|
||||
"vuepress-plugin-sitemap2": "2.0.0-rc.5"
|
||||
"vuepress-plugin-comment2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-md-enhance": "2.0.0-rc.6",
|
||||
"vuepress-plugin-reading-time2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-seo2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-sitemap2": "2.0.0-rc.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash.merge": "^4.6.9"
|
||||
|
||||
@ -5,11 +5,14 @@ import type {
|
||||
PlumeThemePageData,
|
||||
PlumeThemePostFrontmatter,
|
||||
} from '../../shared/index.js'
|
||||
import { useReadingTime } from '../composables/index.js'
|
||||
import IconBooks from './icons/IconBooks.vue'
|
||||
import IconClock from './icons/IconClock.vue'
|
||||
import IconTag from './icons/IconTag.vue'
|
||||
|
||||
const page = usePageData<PlumeThemePageData>()
|
||||
const matter = usePageFrontmatter<PlumeThemePostFrontmatter>()
|
||||
const readingTime = useReadingTime()
|
||||
|
||||
const createTime = computed(() => {
|
||||
if (matter.value.createTime) {
|
||||
@ -48,13 +51,19 @@ const hasMeta = computed(() => tags.value.length || createTime.value)
|
||||
{{ page.title }}
|
||||
</h2>
|
||||
<div v-if="hasMeta" class="page-meta-wrapper">
|
||||
<p v-if="readingTime.times" class="reading-time">
|
||||
<IconBooks class="icon" />
|
||||
<span>{{ readingTime.words }}</span>
|
||||
<span>{{ readingTime.times }}</span>
|
||||
</p>
|
||||
<p v-if="tags.length > 0">
|
||||
<IconTag class="icon" />
|
||||
<span v-for="tag in tags" :key="tag" class="tag">
|
||||
<span v-for="(tag, index) in tags" :key="tag" class="tag">
|
||||
{{ tag }}
|
||||
<template v-if="index < tags.length - 1">,</template>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="createTime">
|
||||
<p v-if="createTime" class="create-time">
|
||||
<IconClock class="icon" /><span>{{ createTime }}</span>
|
||||
</p>
|
||||
</div>
|
||||
@ -95,7 +104,8 @@ const hasMeta = computed(() => tags.value.length || createTime.value)
|
||||
.page-meta-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
padding: 1rem 0 0.5rem;
|
||||
margin-bottom: 2rem;
|
||||
color: var(--vp-c-text-3);
|
||||
@ -118,8 +128,7 @@ const hasMeta = computed(() => tags.value.length || createTime.value)
|
||||
.page-meta-wrapper .tag {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
margin-right: 0.3rem;
|
||||
padding: 3px 6px;
|
||||
padding: 3px 3px;
|
||||
color: var(--vp-c-text-2);
|
||||
background-color: var(--vp-c-mute);
|
||||
border-radius: 4px;
|
||||
@ -128,4 +137,20 @@ const hasMeta = computed(() => tags.value.length || createTime.value)
|
||||
.page-meta-wrapper .tag:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.page-meta-wrapper .reading-time span {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.page-meta-wrapper .reading-time span:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.page-meta-wrapper .create-time {
|
||||
flex: 1;
|
||||
min-width: 110px;
|
||||
justify-content: right;
|
||||
text-align: right;
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
3
theme/src/client/components/icons/IconBooks.vue
Normal file
3
theme/src/client/components/icons/IconBooks.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M256 160c16-63.16 76.43-95.41 208-96a15.94 15.94 0 0 1 16 16v288a16 16 0 0 1-16 16c-128 0-177.45 25.81-208 64c-30.37-38-80-64-208-64c-9.88 0-16-8.05-16-17.93V80a15.94 15.94 0 0 1 16-16c131.57.59 192 32.84 208 96m0 0v288"/></svg>
|
||||
</template>
|
||||
@ -5,3 +5,4 @@ export * from './useResolveRouteWithRedirect.js'
|
||||
export * from './sidebar.js'
|
||||
export * from './aside.js'
|
||||
export * from './page.js'
|
||||
export * from './readingTime.js'
|
||||
|
||||
153
theme/src/client/composables/readingTime.ts
Normal file
153
theme/src/client/composables/readingTime.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import { usePageData } from '@vuepress/client'
|
||||
import { computed } from 'vue'
|
||||
import type {
|
||||
PlumeThemePageData,
|
||||
} from '../../shared/index.js'
|
||||
|
||||
/**
|
||||
* Default locale config for `vuepress-plugin-reading-time2` plugin
|
||||
*/
|
||||
export const readingTimeLocales = {
|
||||
"en": {
|
||||
word: "About $word words",
|
||||
less1Minute: "Less than 1 minute",
|
||||
time: "About $time min",
|
||||
},
|
||||
|
||||
"zh": {
|
||||
word: "约 $word 字",
|
||||
less1Minute: "小于 1 分钟",
|
||||
time: "大约 $time 分钟",
|
||||
},
|
||||
|
||||
"zh-tw": {
|
||||
word: "約 $word 字",
|
||||
less1Minute: "小於 1 分鐘",
|
||||
time: "大约 $time 分鐘",
|
||||
},
|
||||
|
||||
"de": {
|
||||
word: "Ungefähr $word Wörter",
|
||||
less1Minute: "Weniger als eine Minute",
|
||||
time: "Ungefähr $time min",
|
||||
},
|
||||
|
||||
"de-at": {
|
||||
word: "Um die $word Wörter",
|
||||
less1Minute: "Weniger als eine Minute",
|
||||
time: "Ungefähr $time min",
|
||||
},
|
||||
|
||||
"vi": {
|
||||
word: "Khoảng $word từ",
|
||||
less1Minute: "Ít hơn 1 phút",
|
||||
time: "Khoảng $time phút",
|
||||
},
|
||||
|
||||
"uk": {
|
||||
word: "Про $word слова",
|
||||
less1Minute: "Менше 1 хвилини",
|
||||
time: "Приблизно $time хв",
|
||||
},
|
||||
|
||||
"ru": {
|
||||
word: "Около $word слов",
|
||||
less1Minute: "Меньше 1 минуты",
|
||||
time: "Около $time мин",
|
||||
},
|
||||
|
||||
"br": {
|
||||
word: "Por volta de $word palavras",
|
||||
less1Minute: "Menos de 1 minuto",
|
||||
time: "Por volta de $time min",
|
||||
},
|
||||
|
||||
"pl": {
|
||||
word: "Około $word słów",
|
||||
less1Minute: "Mniej niż 1 minuta",
|
||||
time: "Około $time minut",
|
||||
},
|
||||
|
||||
"sk": {
|
||||
word: "Okolo $word slov",
|
||||
less1Minute: "Menej ako 1 minúta",
|
||||
time: "Okolo $time minút",
|
||||
},
|
||||
|
||||
"fr": {
|
||||
word: "Environ $word mots",
|
||||
less1Minute: "Moins de 1 minute",
|
||||
time: "Environ $time min",
|
||||
},
|
||||
|
||||
"es": {
|
||||
word: "Alrededor de $word palabras",
|
||||
less1Minute: "Menos de 1 minuto",
|
||||
time: "Alrededor de $time min",
|
||||
},
|
||||
|
||||
"ja": {
|
||||
word: "$word字程度",
|
||||
less1Minute: "1分以内",
|
||||
time: "約$time分",
|
||||
},
|
||||
|
||||
"tr": {
|
||||
word: "Yaklaşık $word kelime",
|
||||
less1Minute: "1 dakikadan az",
|
||||
time: "Yaklaşık $time dakika",
|
||||
},
|
||||
|
||||
"ko": {
|
||||
word: "약 $word 단어",
|
||||
less1Minute: "1분 미만",
|
||||
time: "약 $time 분",
|
||||
},
|
||||
|
||||
"fi": {
|
||||
word: "Noin $word sanaa",
|
||||
less1Minute: "Alle minuutti",
|
||||
time: "Noin $time minuuttia",
|
||||
},
|
||||
|
||||
"hu": {
|
||||
word: "Körülbelül $word szó",
|
||||
less1Minute: "Kevesebb, mint 1 perc",
|
||||
time: "Körülbelül $time perc",
|
||||
},
|
||||
|
||||
"id": {
|
||||
word: "Sekitar $word kata",
|
||||
less1Minute: "Kurang dari 1 menit",
|
||||
time: "Sekitar $time menit",
|
||||
},
|
||||
|
||||
"nl": {
|
||||
word: "Ongeveer $word woorden",
|
||||
less1Minute: "Minder dan 1 minuut",
|
||||
time: "Ongeveer $time minuten",
|
||||
},
|
||||
};
|
||||
|
||||
export const useReadingTime = () => {
|
||||
const page = usePageData<PlumeThemePageData>()
|
||||
|
||||
return computed(() => {
|
||||
if (!page.value.readingTime) return { times: '', words: '' }
|
||||
|
||||
const locale = readingTimeLocales[page.value.lang] ?? readingTimeLocales.en
|
||||
|
||||
const minutes = page.value.readingTime.minutes
|
||||
const words = page.value.readingTime.words
|
||||
|
||||
const times = (minutes < 1 ? locale.less1Minute : locale.time).replace(
|
||||
'$time',
|
||||
Math.round(minutes)
|
||||
)
|
||||
|
||||
return {
|
||||
times,
|
||||
words: locale.word.replace('$word', words),
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -19,6 +19,7 @@ import { notesDataPlugin } from '@vuepress-plume/plugin-notes-data'
|
||||
import { shikijiPlugin } from '@vuepress-plume/plugin-shikiji'
|
||||
import { commentPlugin } from 'vuepress-plugin-comment2'
|
||||
import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
|
||||
import { useReadingTimePlugin } from 'vuepress-plugin-reading-time2'
|
||||
import { seoPlugin } from 'vuepress-plugin-seo2'
|
||||
import { sitemapPlugin } from 'vuepress-plugin-sitemap2'
|
||||
import type {
|
||||
@ -44,6 +45,10 @@ export const setupPlugins = (
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
if (options.readingTime !== false) {
|
||||
useReadingTimePlugin(app, options.readingTime || {}, true)
|
||||
}
|
||||
|
||||
return [
|
||||
palettePlugin({ preset: 'sass' }),
|
||||
themeDataPlugin({
|
||||
|
||||
@ -7,6 +7,7 @@ import type { CopyCodeOptions } from '@vuepress-plume/plugin-copy-code'
|
||||
import type { ShikijiPluginOptions } from '@vuepress-plume/plugin-shikiji'
|
||||
import type { CommentPluginOptions } from 'vuepress-plugin-comment2'
|
||||
import type { MarkdownEnhanceOptions } from 'vuepress-plugin-md-enhance'
|
||||
import type { ReadingTimeOptions } from 'vuepress-plugin-reading-time2'
|
||||
|
||||
export interface PlumeThemePluginOptions {
|
||||
/**
|
||||
@ -50,4 +51,6 @@ export interface PlumeThemePluginOptions {
|
||||
baiduTongji?: false | BaiduTongjiOptions
|
||||
|
||||
frontmatter?: AutoFrontmatterOptions
|
||||
|
||||
readingTime?: false | ReadingTimeOptions
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
import type { GitPluginPageData } from '@vuepress/plugin-git'
|
||||
|
||||
interface ReadingTime {
|
||||
/** 分钟数 */
|
||||
minutes: number;
|
||||
/** 字数 */
|
||||
words: number;
|
||||
}
|
||||
|
||||
export interface PlumeThemePageData extends GitPluginPageData {
|
||||
isBlogPost: boolean
|
||||
type: 'blog' | 'product'
|
||||
categoryList?: PageCategoryData[]
|
||||
filePathRelative: string | null
|
||||
readingTime?: ReadingTime
|
||||
}
|
||||
|
||||
export interface PageCategoryData {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user