Skip to content

Commit 6a13db1

Browse files
committed
feat: add article metadata (word count, reading time) and optimize config
1 parent e71bd9f commit 6a13db1

File tree

17 files changed

+2456
-12
lines changed

17 files changed

+2456
-12
lines changed

.gitignore

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
1+
# Node.js
12
node_modules
3+
npm-debug.log*
4+
yarn-debug.log*
5+
yarn-error.log*
6+
pnpm-debug.log*
7+
.pnpm-store
8+
9+
# VitePress / Build
210
dist
3-
.vitepress/cache
4-
.vitepress/dist
11+
docs/.vitepress/dist
12+
docs/.vitepress/cache
13+
docs/.vitepress/theme/node_modules
14+
docs/.vitepress/theme/.vitepress
15+
coverage
16+
.turbo
17+
.nyc_output
18+
19+
# System Files
20+
.DS_Store
21+
Thumbs.db
22+
.fsevents_cache
23+
24+
# Editors
25+
.vscode
26+
.idea
27+
*.suo
28+
*.ntvs
29+
*.njsproj
30+
*.sln
31+
32+
# Environment
33+
.env
34+
.env.local
35+
.env.*.local
36+
37+
# Logs
38+
*.log

docs/.vitepress/config.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import { defineConfig } from 'vitepress';
2+
import fs from 'fs';
3+
import path from 'path';
24

35
export default defineConfig({
46
title: 'NapLink',
57
description: '现代化的 NapCat WebSocket 客户端 SDK',
68
base: '/', // 组织主页使用根路径
79

810
themeConfig: {
11+
lastUpdated: {
12+
text: '最后更新于',
13+
formatOptions: {
14+
dateStyle: 'short',
15+
timeStyle: 'medium'
16+
}
17+
},
918
logo: '/logo.svg',
1019

1120
nav: [
@@ -67,5 +76,33 @@ export default defineConfig({
6776
search: {
6877
provider: 'local'
6978
}
79+
},
80+
81+
transformPageData(pageData) {
82+
// Content might not be available in pageData, read from file
83+
let content = '';
84+
// pageData.filePath seems to be relative in this version, so we force construction
85+
const absolutePath = path.resolve(process.cwd(), 'docs', pageData.relativePath);
86+
87+
if (absolutePath) {
88+
try {
89+
content = fs.readFileSync(absolutePath, 'utf-8');
90+
} catch (e) {
91+
92+
}
93+
}
94+
95+
// CJK characters count
96+
const cjkRegex = /[\u4e00-\u9fa5]/g;
97+
const cjkCount = (content.match(cjkRegex) || []).length;
98+
// Latin words count
99+
const wordRegex = /[a-zA-Z0-9_\-]+/g;
100+
const wordCount = (content.match(wordRegex) || []).length;
101+
102+
const totalCount = cjkCount + wordCount;
103+
const readTime = Math.ceil(totalCount / 400); // Assume 400 chars/min reading speed
104+
105+
pageData.frontmatter.wordCount = totalCount;
106+
pageData.frontmatter.readingTime = readTime;
70107
}
71108
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script setup>
2+
import { useData } from 'vitepress'
3+
import { computed } from 'vue'
4+
5+
const { page, theme } = useData()
6+
7+
const wordCount = computed(() => page.value.frontmatter.wordCount)
8+
const readingTime = computed(() => page.value.frontmatter.readingTime)
9+
const lastUpdated = computed(() => {
10+
// If VitePress default lastUpdated date handling is used, it might be available.
11+
// However, VitePress usually shows it at the bottom.
12+
// We can also format the timestamp if `lastUpdated` timestamp is available.
13+
// For now, let's focus on wordCount and readingTime as lastUpdated is natively handled by themeConfig,
14+
// but the user asked for a "template" to display elements.
15+
// Let's show all if possible, or just the custom ones.
16+
return page.value.lastUpdated
17+
})
18+
</script>
19+
20+
<template>
21+
<div class="article-metadata" v-if="wordCount || readingTime">
22+
<span class="meta-item" v-if="wordCount">
23+
<span class="icon">📝</span>
24+
<span class="text">字数: {{ wordCount }}</span>
25+
</span>
26+
<span class="meta-item" v-if="readingTime">
27+
<span class="icon">⏱️</span>
28+
<span class="text">阅读时间: {{ readingTime }} 分钟</span>
29+
</span>
30+
</div>
31+
</template>
32+
33+
<style scoped>
34+
.article-metadata {
35+
margin-top: 1rem;
36+
margin-bottom: 2rem;
37+
display: flex;
38+
gap: 1.5rem;
39+
align-items: center;
40+
color: var(--vp-c-text-2);
41+
font-size: 0.9rem;
42+
}
43+
44+
.meta-item {
45+
display: flex;
46+
align-items: center;
47+
gap: 0.5rem;
48+
}
49+
50+
.icon {
51+
font-size: 1.1em;
52+
}
53+
</style>

docs/.vitepress/theme/custom.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* Custom styles */

docs/.vitepress/theme/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import DefaultTheme from 'vitepress/theme'
2+
import ArticleMetadata from './ArticleMetadata.vue'
3+
import { h } from 'vue'
4+
import './custom.css'
5+
6+
export default {
7+
extends: DefaultTheme,
8+
Layout: () => {
9+
return h(DefaultTheme.Layout, null, {
10+
// Use the doc-before slot to insert metadata before the content
11+
'doc-before': () => h(ArticleMetadata)
12+
})
13+
}
14+
}

0 commit comments

Comments
 (0)