mirror of
https://github.com/m1ngsama/documents.git
synced 2025-12-24 10:51:23 +00:00
Merge changes from origin/main
This commit is contained in:
commit
33432c1149
42 changed files with 2092 additions and 1 deletions
4
.gitignore
vendored
4
.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