@guzhongren/sha 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,16 +2,28 @@
2
2
 
3
3
  Config-driven Astro blog theme for technical writing. The theme is consumed as an Astro integration and injects default pages, layouts, and styling.
4
4
 
5
- ## Install
5
+ ## Quick Start
6
+
7
+ Scaffold a new blog in one command:
6
8
 
7
9
  ```sh
8
- pnpm add @guzhongren/sha astro @astrojs/mdx tailwindcss @tailwindcss/vite
10
+ pnpm dlx @guzhongren/sha my-blog
11
+ cd my-blog && pnpm dev
9
12
  ```
10
13
 
11
- ## Configure
14
+ This creates a complete project with `astro.config.mjs`, content collections bridge, and a sample post.
15
+
16
+ ## Manual Setup
17
+
18
+ If you prefer to set up manually or add the theme to an existing Astro project:
19
+
20
+ ```sh
21
+ pnpm add @guzhongren/sha astro @astrojs/mdx @astrojs/markdown-remark tailwindcss @tailwindcss/vite
22
+ ```
23
+
24
+ ### astro.config.mjs
12
25
 
13
26
  ```js
14
- // astro.config.mjs
15
27
  import { defineConfig } from "astro/config";
16
28
  import mdx from "@astrojs/mdx";
17
29
  import tailwindcss from "@tailwindcss/vite";
@@ -22,21 +34,13 @@ export default defineConfig({
22
34
  integrations: [
23
35
  blogTheme({
24
36
  site: {
25
- name: "谷中的博客",
26
- description: "全栈开发者的技术写作与知识沉淀",
27
- lang: "zh-CN",
37
+ name: "My Blog",
38
+ title: "My Blog",
39
+ description: "A blog powered by @guzhongren/sha",
40
+ lang: "en",
28
41
  },
29
42
  author: {
30
- name: "谷中",
31
- headline: "全栈开发者 / 技术顾问",
32
- bio: "写工程实践、架构思考、开源与日常观察。",
33
- avatar: "/avatar.svg",
34
- },
35
- diagrams: {
36
- mermaid: true,
37
- plantuml: {
38
- serverUrl: "https://www.plantuml.com/plantuml/svg",
39
- },
43
+ name: "Author",
40
44
  },
41
45
  }),
42
46
  mdx(),
@@ -49,9 +53,7 @@ export default defineConfig({
49
53
 
50
54
  Register `blogTheme(...)` before `mdx()` when using theme shortcodes such as ECharts. The theme pre-processes content before MDX parses it.
51
55
 
52
- ## Content collections
53
-
54
- Astro requires the app to export content collections:
56
+ ### Content collections bridge
55
57
 
56
58
  ```ts
57
59
  // src/content.config.ts
package/create.mjs ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { execSync } from "node:child_process";
5
+
6
+ const name = process.argv[2];
7
+ if (!name) {
8
+ console.error("Usage: pnpm dlx @guzhongren/sha <project-dir>");
9
+ console.error(" node create.mjs <project-dir>");
10
+ process.exit(1);
11
+ }
12
+
13
+ const root = join(process.cwd(), name);
14
+
15
+ // Dir tree
16
+ mkdirSync(join(root, "src", "content", "posts"), { recursive: true });
17
+
18
+ // package.json
19
+ writeFileSync(
20
+ join(root, "package.json"),
21
+ JSON.stringify(
22
+ {
23
+ name: name,
24
+ version: "0.0.1",
25
+ type: "module",
26
+ private: true,
27
+ scripts: {
28
+ dev: "astro dev",
29
+ sync: "astro sync",
30
+ build: "astro build",
31
+ preview: "astro preview",
32
+ },
33
+ dependencies: {
34
+ "@astrojs/markdown-remark": "^7.0.0",
35
+ "@astrojs/mdx": "^7.0.5",
36
+ "@guzhongren/sha": "^0.1.1",
37
+ "@tailwindcss/vite": "^4.3.3",
38
+ astro: "^7.1.6",
39
+ tailwindcss: "^4.3.3",
40
+ },
41
+ },
42
+ null,
43
+ 2,
44
+ ) + "\n",
45
+ );
46
+
47
+ // astro.config.mjs
48
+ writeFileSync(
49
+ join(root, "astro.config.mjs"),
50
+ `import { defineConfig } from "astro/config";
51
+ import mdx from "@astrojs/mdx";
52
+ import tailwindcss from "@tailwindcss/vite";
53
+ import blogTheme from "@guzhongren/sha";
54
+
55
+ export default defineConfig({
56
+ site: "https://example.com",
57
+ integrations: [
58
+ blogTheme({
59
+ site: {
60
+ name: "My Blog",
61
+ title: "My Blog",
62
+ description: "A blog powered by @guzhongren/sha",
63
+ lang: "en",
64
+ },
65
+ author: {
66
+ name: "Author",
67
+ },
68
+ }),
69
+ mdx(),
70
+ ],
71
+ vite: {
72
+ plugins: [tailwindcss()],
73
+ },
74
+ });
75
+ `,
76
+ );
77
+
78
+ // src/content.config.ts
79
+ writeFileSync(
80
+ join(root, "src", "content.config.ts"),
81
+ `export { collections } from "@guzhongren/sha/content";\n`,
82
+ );
83
+
84
+ // hello-world post
85
+ writeFileSync(
86
+ join(root, "src", "content", "posts", "hello-world.md"),
87
+ `---
88
+ title: "Hello World"
89
+ description: "My first blog post"
90
+ publishDate: ${new Date().toISOString().slice(0, 10)}
91
+ category: "Uncategorized"
92
+ tags: ["hello"]
93
+ ---
94
+
95
+ Welcome to my blog! 🎉
96
+ `,
97
+ );
98
+
99
+ // tsconfig.json
100
+ writeFileSync(
101
+ join(root, "tsconfig.json"),
102
+ `{
103
+ "extends": "astro/tsconfigs/strict"
104
+ }
105
+ `,
106
+ );
107
+
108
+ // .gitignore
109
+ writeFileSync(join(root, ".gitignore"), "node_modules/\n.astro/\ndist/\n");
110
+
111
+ // pnpm-workspace.yaml (minimumReleaseAgeExclude for fresh packages)
112
+ writeFileSync(
113
+ join(root, "pnpm-workspace.yaml"),
114
+ `allowBuilds:
115
+ esbuild: true
116
+ minimumReleaseAgeExclude:
117
+ - "@guzhongren/sha"
118
+ `,
119
+ );
120
+
121
+ // Install deps
122
+ console.log(`\n✓ Scaffolded "${name}"`);
123
+ console.log("Installing dependencies...\n");
124
+ execSync("pnpm install", { cwd: root, stdio: "inherit" });
125
+
126
+ console.log(`\n✓ Done! Start the dev server:\n`);
127
+ console.log(` cd ${name} && pnpm dev\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guzhongren/sha",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "个人 Astro 博客主题 — 开箱即用的内容驱动博客",
6
6
  "license": "MIT",
@@ -15,22 +15,27 @@
15
15
  ],
16
16
  "files": [
17
17
  "src/",
18
+ "create.mjs",
18
19
  "README.md",
19
20
  "LICENSE"
20
21
  ],
22
+ "bin": {
23
+ "create-sha-blog": "./create.mjs"
24
+ },
21
25
  "exports": {
22
26
  ".": "./src/index.ts",
23
27
  "./content": "./src/content.ts",
24
28
  "./styles.css": "./src/styles/global.css"
25
29
  },
26
30
  "peerDependencies": {
27
- "astro": "^7.1.3",
28
- "@astrojs/mdx": "^7.0.0",
29
31
  "@astrojs/markdown-remark": "^7.0.0",
32
+ "@astrojs/mdx": "^7.0.0",
30
33
  "@tailwindcss/vite": "^4.0.0",
34
+ "astro": "^7.1.3",
31
35
  "tailwindcss": "^4.0.0"
32
36
  },
33
37
  "dependencies": {
38
+ "@astrojs/rss": "^4.0.19",
34
39
  "echarts": "^6.1.0",
35
40
  "gemoji": "^8.1.0",
36
41
  "mermaid": "^11.16.0",
package/src/config.ts CHANGED
@@ -49,6 +49,7 @@ export function normalizeOptions(options: BlogThemeOptions): NormalizedBlogTheme
49
49
  categories: false,
50
50
  about: false,
51
51
  search: false,
52
+ rss: false,
52
53
  }
53
54
  : {
54
55
  home: options.routes?.home ?? true,
@@ -57,6 +58,7 @@ export function normalizeOptions(options: BlogThemeOptions): NormalizedBlogTheme
57
58
  categories: options.routes?.categories ?? true,
58
59
  about: options.routes?.about ?? true,
59
60
  search: options.routes?.search ?? true,
61
+ rss: options.routes?.rss ?? true,
60
62
  },
61
63
  };
62
64
  }
package/src/index.ts CHANGED
@@ -100,6 +100,7 @@ export default function blogTheme(options: BlogThemeOptions): AstroIntegration {
100
100
  }
101
101
  if (config.routes.about) injectRoute({ pattern: "/about", entrypoint: route("./pages/about.astro") });
102
102
  if (config.routes.search) injectRoute({ pattern: "/search", entrypoint: route("./pages/search.astro") });
103
+ if (config.routes.rss) injectRoute({ pattern: "/rss.xml", entrypoint: route("./pages/rss.xml.ts") });
103
104
  },
104
105
  "astro:build:done": async ({ dir }) => {
105
106
  if (!config.routes.search) return;
@@ -0,0 +1,22 @@
1
+ import rss from "@astrojs/rss";
2
+ import { getCollection } from "astro:content";
3
+ import config from "virtual:blog-theme/config";
4
+ import { isPublished, sortPosts, postHref } from "../utils";
5
+
6
+ export async function GET(context: { site: URL }) {
7
+ const posts = sortPosts((await getCollection("posts")).filter(isPublished));
8
+
9
+ return rss({
10
+ xmlns: { atom: "http://www.w3.org/2005/Atom" },
11
+ title: config.site.title,
12
+ description: config.site.description,
13
+ site: context.site,
14
+ items: posts.map((post) => ({
15
+ title: post.data.title,
16
+ description: post.data.description,
17
+ pubDate: post.data.publishDate ?? new Date(),
18
+ link: postHref(post),
19
+ })),
20
+ customData: `<language>${config.site.lang}</language>`,
21
+ });
22
+ }
package/src/types.ts CHANGED
@@ -46,6 +46,7 @@ export type BlogThemeOptions = {
46
46
  categories?: boolean;
47
47
  about?: boolean;
48
48
  search?: boolean;
49
+ rss?: boolean;
49
50
  };
50
51
  };
51
52
 
@@ -90,5 +91,6 @@ export type NormalizedBlogThemeOptions = {
90
91
  categories: boolean;
91
92
  about: boolean;
92
93
  search: boolean;
94
+ rss: boolean;
93
95
  };
94
96
  };