mirror of
https://github.com/m1ngsama/documents.git
synced 2025-12-25 02:56:26 +00:00
feat: use VitePress to serve documents (#14)
* init vitepress * fix build * add vue
This commit is contained in:
parent
f757775c10
commit
27684e03ff
41 changed files with 2092 additions and 1 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1 +1,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
.vitepress/cache
|
||||||
28
.vitepress/config.mts
Normal file
28
.vitepress/config.mts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
import { getMeetingMinutesSidebar } from '../meetings/sidebar'
|
||||||
|
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/site-config
|
||||||
|
export default defineConfig({
|
||||||
|
title: "Documents",
|
||||||
|
description: "Documents for nbtca",
|
||||||
|
themeConfig: {
|
||||||
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
|
nav: [
|
||||||
|
{ text: 'Home', link: '/' },
|
||||||
|
{ text: 'Meeting Minutes', link: '/meetings' }
|
||||||
|
],
|
||||||
|
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: 'Meeting Minutes',
|
||||||
|
link: '/meetings'
|
||||||
|
},
|
||||||
|
...getMeetingMinutesSidebar()
|
||||||
|
],
|
||||||
|
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"vue.server.includeLanguages": [
|
||||||
|
"vue",
|
||||||
|
"markdown"
|
||||||
|
]
|
||||||
|
}
|
||||||
25
index.md
Normal file
25
index.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
# https://vitepress.dev/reference/default-theme-home-page
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: "Documents"
|
||||||
|
text: "Documents for nbtca"
|
||||||
|
tagline: My great project tagline
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Meeting minutes
|
||||||
|
link: /meetings/index
|
||||||
|
# - theme: alt
|
||||||
|
# text: API Examples
|
||||||
|
# link: /api-examples
|
||||||
|
|
||||||
|
features:
|
||||||
|
- title: Feature A
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
- title: Feature B
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
- title: Feature C
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
---
|
||||||
|
|
||||||
1
meetings/index.md
Normal file
1
meetings/index.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
index
|
||||||
65
meetings/sidebar.ts
Normal file
65
meetings/sidebar.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { scanDir } from "../utils/sidebar"
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
|
||||||
|
|
||||||
|
type MeetingMinutesParsed = {
|
||||||
|
date: Date
|
||||||
|
fileNameWithoutDate: string
|
||||||
|
fileName: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stripFileExtension = (filename: string) => {
|
||||||
|
return filename.split(".").slice(0, -1).join(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseFileName = (fileName: string, link: string): MeetingMinutesParsed => {
|
||||||
|
const dateString = fileName.slice(0, 10)
|
||||||
|
const date = new Date(dateString)
|
||||||
|
|
||||||
|
return {
|
||||||
|
date,
|
||||||
|
fileNameWithoutDate: stripFileExtension(fileName.slice(10)),
|
||||||
|
fileName: fileName,
|
||||||
|
link: link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMeetingMinutesSidebar = () => {
|
||||||
|
|
||||||
|
const items = scanDir("meetings").filter(v => {
|
||||||
|
return v.filename != "index.md"
|
||||||
|
})
|
||||||
|
|
||||||
|
const groupedItems = items.reduce((acc, item) => {
|
||||||
|
const parsed = parseFileName(item.filename, item.link)
|
||||||
|
const year = parsed.date.getFullYear()
|
||||||
|
if (!acc[year]) {
|
||||||
|
acc[year] = []
|
||||||
|
}
|
||||||
|
acc[year].push(parsed)
|
||||||
|
return acc
|
||||||
|
}, {} as Record<number, MeetingMinutesParsed[]>)
|
||||||
|
|
||||||
|
const groupedSidebarItems = Object.keys(groupedItems).map(v => {
|
||||||
|
const items: MeetingMinutesParsed[] = groupedItems[v]
|
||||||
|
return {
|
||||||
|
text: v.toString(),
|
||||||
|
items: items
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.date > b.date ? 1 : -1
|
||||||
|
})
|
||||||
|
.map(v => {
|
||||||
|
return {
|
||||||
|
text: `${dayjs(v.date).format("YYYY-MM-DD")} ${v.fileNameWithoutDate}`,
|
||||||
|
link: v.link
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return groupedSidebarItems.sort((a, b) => {
|
||||||
|
return b.text > a.text ? 1 : -1
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
24
package.json
Normal file
24
package.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "documents",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "vitest",
|
||||||
|
"docs:dev": "vitepress dev",
|
||||||
|
"docs:build": "vitepress build",
|
||||||
|
"docs:preview": "vitepress preview"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"vitepress": "^1.6.3",
|
||||||
|
"vitest": "^3.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^22.10.10",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"vue": "^3.5.13"
|
||||||
|
}
|
||||||
|
}
|
||||||
1869
pnpm-lock.yaml
Normal file
1869
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.vue",
|
||||||
|
"**/*.md",
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"vueCompilerOptions": {
|
||||||
|
"vitePressExtensions": [
|
||||||
|
".md"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
40
utils/sidebar.test.ts
Normal file
40
utils/sidebar.test.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { describe, expect, test, beforeAll, afterAll } from "vitest";
|
||||||
|
import { scanDir } from "../utils/sidebar";
|
||||||
|
import { resolve } from "path";
|
||||||
|
import { mkdtempSync, writeFileSync, rmdirSync } from "fs";
|
||||||
|
import { tmpdir } from "os";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
let tempDir: string;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
tempDir = mkdtempSync(join(tmpdir(), 'test-'));
|
||||||
|
writeFileSync(join(tempDir, 'test1.md'), '# Test 1');
|
||||||
|
writeFileSync(join(tempDir, 'test2.md'), '# Test 2');
|
||||||
|
writeFileSync(join(tempDir, 'test.txt'), 'Test text file');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
rmdirSync(tempDir, { recursive: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("scanDir", () => {
|
||||||
|
test("should return markdown files with correct structure", () => {
|
||||||
|
const res = scanDir(tempDir);
|
||||||
|
expect(res).toBeInstanceOf(Array);
|
||||||
|
expect(res.length).toBe(2);
|
||||||
|
res.forEach(item => {
|
||||||
|
expect(item).toHaveProperty("filename");
|
||||||
|
expect(item).toHaveProperty("link");
|
||||||
|
expect(item.filename).toMatch(/\.md$/);
|
||||||
|
expect(item.link).toBe(resolve(tempDir, item.filename));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return an empty array if no markdown files are found", () => {
|
||||||
|
const emptyDir = mkdtempSync(join(tmpdir(), 'empty-'));
|
||||||
|
const res = scanDir(emptyDir);
|
||||||
|
expect(res).toEqual([]);
|
||||||
|
rmdirSync(emptyDir, { recursive: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
16
utils/sidebar.ts
Normal file
16
utils/sidebar.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { readdirSync } from "fs"
|
||||||
|
import path from "path"
|
||||||
|
|
||||||
|
export const scanDir = (dirname: string) => {
|
||||||
|
const dirpath = path.resolve(__dirname, `../${dirname}`)
|
||||||
|
const res = readdirSync(dirpath)
|
||||||
|
|
||||||
|
const markdownFileNames = res.filter((name) => name.endsWith('.md'))
|
||||||
|
|
||||||
|
return markdownFileNames.map(v => {
|
||||||
|
return {
|
||||||
|
filename: v,
|
||||||
|
link: path.join(dirname, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue