~repos /website
git clone https://pyrossh.dev/repos/website.git
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
6d177b0b
—
pyrossh 1 month ago
update packages
- src/consts.ts +17 -3
- src/content.config.ts +1 -80
- src/utils/files.ts +76 -3
src/consts.ts
CHANGED
|
@@ -18,7 +18,7 @@ export const REPOS = [
|
|
|
18
18
|
badges: [
|
|
19
19
|
{
|
|
20
20
|
href: "https://crates.io/crates/rust-embed",
|
|
21
|
-
img: "https://img.shields.io/crates/v/rust-embed
|
|
21
|
+
img: "https://img.shields.io/crates/v/rust-embed",
|
|
22
22
|
alt: "crates.io",
|
|
23
23
|
}
|
|
24
24
|
]
|
|
@@ -46,12 +46,26 @@ export const REPOS = [
|
|
|
46
46
|
{
|
|
47
47
|
title: "atoms-element",
|
|
48
48
|
description: "A simple web component library for defining your custom elements. It works on both client and server.",
|
|
49
|
-
tags: ['js']
|
|
49
|
+
tags: ['js'],
|
|
50
|
+
badges: [
|
|
51
|
+
{
|
|
52
|
+
href: "https://www.npmjs.com/package/atoms-element",
|
|
53
|
+
img: "https://img.shields.io/npm/v/atoms-element?color=ba271a",
|
|
54
|
+
alt: "npmjs.com",
|
|
55
|
+
}
|
|
56
|
+
]
|
|
50
57
|
},
|
|
51
58
|
{
|
|
52
59
|
title: "atoms-state",
|
|
53
60
|
description: "Simple State management for react",
|
|
54
|
-
tags: ['js', 'react', 'flux']
|
|
61
|
+
tags: ['js', 'react', 'flux'],
|
|
62
|
+
badges: [
|
|
63
|
+
{
|
|
64
|
+
href: "https://www.npmjs.com/package/atoms-state",
|
|
65
|
+
img: "https://img.shields.io/npm/v/atoms-state?color=ba271a",
|
|
66
|
+
alt: "npmjs.com",
|
|
67
|
+
}
|
|
68
|
+
]
|
|
55
69
|
},
|
|
56
70
|
{
|
|
57
71
|
title: "remote-monitor",
|
src/content.config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { simpleGit } from "simple-git";
|
|
|
3
3
|
import { glob } from 'astro/loaders';
|
|
4
4
|
import { defineCollection, z } from 'astro:content';
|
|
5
5
|
import { REPOS } from './consts';
|
|
6
|
+
import { buildFileTree, sortChildren, fileNodeSchema } from "./utils/files";
|
|
6
7
|
|
|
7
8
|
async function checkFileExists(filePath: string) {
|
|
8
9
|
try {
|
|
@@ -13,72 +14,6 @@ async function checkFileExists(filePath: string) {
|
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
interface FileNode {
|
|
17
|
-
name: string;
|
|
18
|
-
path: string;
|
|
19
|
-
isDirectory: boolean;
|
|
20
|
-
children?: FileNode[];
|
|
21
|
-
size?: number;
|
|
22
|
-
ext?: string;
|
|
23
|
-
absolutePath?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function buildFileTree(files: any[]): FileNode[] {
|
|
27
|
-
const root: FileNode[] = [];
|
|
28
|
-
|
|
29
|
-
for (const file of files) {
|
|
30
|
-
const parts = file.name.split('/');
|
|
31
|
-
let currentLevel = root;
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < parts.length; i++) {
|
|
34
|
-
const part = parts[i];
|
|
35
|
-
const isLastPart = i === parts.length - 1;
|
|
36
|
-
const currentPath = parts.slice(0, i + 1).join('/');
|
|
37
|
-
|
|
38
|
-
let existingNode = currentLevel.find(node => node.name === part);
|
|
39
|
-
|
|
40
|
-
if (!existingNode) {
|
|
41
|
-
const newNode: FileNode = {
|
|
42
|
-
name: part,
|
|
43
|
-
path: currentPath,
|
|
44
|
-
isDirectory: !isLastPart,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
if (isLastPart) {
|
|
48
|
-
// It's a file, add file metadata
|
|
49
|
-
newNode.size = file.size;
|
|
50
|
-
newNode.ext = file.ext;
|
|
51
|
-
newNode.absolutePath = file.absolutePath;
|
|
52
|
-
} else {
|
|
53
|
-
// It's a directory
|
|
54
|
-
newNode.children = [];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
currentLevel.push(newNode);
|
|
58
|
-
existingNode = newNode;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!isLastPart) {
|
|
62
|
-
currentLevel = existingNode.children!;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return root;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const fileNodeSchema: z.ZodType<FileNode> = z.lazy(() =>
|
|
71
|
-
z.object({
|
|
72
|
-
name: z.string(),
|
|
73
|
-
path: z.string(),
|
|
74
|
-
isDirectory: z.boolean(),
|
|
75
|
-
children: z.array(fileNodeSchema),
|
|
76
|
-
size: z.number(),
|
|
77
|
-
ext: z.string(),
|
|
78
|
-
absolutePath: z.string(),
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
|
|
82
17
|
export const collections = {
|
|
83
18
|
repos: defineCollection({
|
|
84
19
|
loader: {
|
|
@@ -99,20 +34,6 @@ export const collections = {
|
|
|
99
34
|
.then((stat) => ({ name: p, absolutePath: `${repoPath}/${p}`, ...stat }))
|
|
100
35
|
.catch(() => null)
|
|
101
36
|
));
|
|
102
|
-
const sortAll = (a: FileNode, b: FileNode): number => {
|
|
103
|
-
if (a.isDirectory && !b.isDirectory) return -1;
|
|
104
|
-
if (!a.isDirectory && b.isDirectory) return 1;
|
|
105
|
-
return a.name.localeCompare(b.name);
|
|
106
|
-
}
|
|
107
|
-
const sortChildren = (nodes: FileNode[]) => {
|
|
108
|
-
for (const node of nodes) {
|
|
109
|
-
if (node.isDirectory && node.children) {
|
|
110
|
-
node.children.sort(sortAll);
|
|
111
|
-
sortChildren(node.children);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return nodes.sort(sortAll);
|
|
115
|
-
};
|
|
116
37
|
const fileTree = sortChildren(buildFileTree(files.filter((f) => f !== null)));
|
|
117
38
|
const readmeContent = await checkFileExists(readmePath) ? await renderMarkdown(await fs.readFile(readmePath, 'utf-8')) : {
|
|
118
39
|
html: '',
|
src/utils/files.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { z } from 'astro:content';
|
|
2
|
+
|
|
1
|
-
interface FileNode {
|
|
3
|
+
export interface FileNode {
|
|
2
4
|
name: string;
|
|
3
5
|
path: string;
|
|
4
6
|
isDirectory: boolean;
|
|
@@ -8,9 +10,21 @@ interface FileNode {
|
|
|
8
10
|
absolutePath?: string;
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
export const fileNodeSchema: z.ZodType<FileNode> = z.lazy(() =>
|
|
14
|
+
z.object({
|
|
15
|
+
name: z.string(),
|
|
16
|
+
path: z.string(),
|
|
17
|
+
isDirectory: z.boolean(),
|
|
18
|
+
children: z.array(fileNodeSchema),
|
|
19
|
+
size: z.number(),
|
|
20
|
+
ext: z.string(),
|
|
21
|
+
absolutePath: z.string(),
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
|
|
11
25
|
export const collectFiles = (nodes: FileNode[]): FileNode[] => {
|
|
12
26
|
const files: FileNode[] = [];
|
|
13
|
-
|
|
27
|
+
|
|
14
28
|
for (const node of nodes) {
|
|
15
29
|
if (node.isDirectory && node.children) {
|
|
16
30
|
files.push(...collectFiles(node.children));
|
|
@@ -18,6 +32,65 @@ export const collectFiles = (nodes: FileNode[]): FileNode[] => {
|
|
|
18
32
|
files.push(node);
|
|
19
33
|
}
|
|
20
34
|
}
|
|
21
|
-
|
|
35
|
+
|
|
22
36
|
return files;
|
|
23
37
|
};
|
|
38
|
+
|
|
39
|
+
export const sortAll = (a: FileNode, b: FileNode): number => {
|
|
40
|
+
if (a.isDirectory && !b.isDirectory) return -1;
|
|
41
|
+
if (!a.isDirectory && b.isDirectory) return 1;
|
|
42
|
+
return a.name.localeCompare(b.name);
|
|
43
|
+
}
|
|
44
|
+
export const sortChildren = (nodes: FileNode[]) => {
|
|
45
|
+
for (const node of nodes) {
|
|
46
|
+
if (node.isDirectory && node.children) {
|
|
47
|
+
node.children.sort(sortAll);
|
|
48
|
+
sortChildren(node.children);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return nodes.sort(sortAll);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const buildFileTree = (files: any[]): FileNode[] => {
|
|
55
|
+
const root: FileNode[] = [];
|
|
56
|
+
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
const parts = file.name.split('/');
|
|
59
|
+
let currentLevel = root;
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < parts.length; i++) {
|
|
62
|
+
const part = parts[i];
|
|
63
|
+
const isLastPart = i === parts.length - 1;
|
|
64
|
+
const currentPath = parts.slice(0, i + 1).join('/');
|
|
65
|
+
|
|
66
|
+
let existingNode = currentLevel.find(node => node.name === part);
|
|
67
|
+
|
|
68
|
+
if (!existingNode) {
|
|
69
|
+
const newNode: FileNode = {
|
|
70
|
+
name: part,
|
|
71
|
+
path: currentPath,
|
|
72
|
+
isDirectory: !isLastPart,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (isLastPart) {
|
|
76
|
+
// It's a file, add file metadata
|
|
77
|
+
newNode.size = file.size;
|
|
78
|
+
newNode.ext = file.ext;
|
|
79
|
+
newNode.absolutePath = file.absolutePath;
|
|
80
|
+
} else {
|
|
81
|
+
// It's a directory
|
|
82
|
+
newNode.children = [];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
currentLevel.push(newNode);
|
|
86
|
+
existingNode = newNode;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!isLastPart) {
|
|
90
|
+
currentLevel = existingNode.children!;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return root;
|
|
96
|
+
}
|