@wsxjs/wsx-press 0.0.18

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.
@@ -0,0 +1,171 @@
1
+ /**
2
+ * WSX-Press 主题变量定义
3
+ * 支持亮/暗模式,与 wsxjs 网站主题集成
4
+ */
5
+
6
+ :root {
7
+ /* ===== 颜色系统 - 亮色模式 ===== */
8
+ --wsx-press-bg-primary: #ffffff;
9
+ --wsx-press-bg-secondary: #f6f8fa;
10
+ --wsx-press-bg-tertiary: #f0f2f5;
11
+
12
+ --wsx-press-text-primary: #1f2328;
13
+ --wsx-press-text-secondary: #636c76;
14
+ --wsx-press-text-tertiary: #8c959f;
15
+
16
+ --wsx-press-border: #d0d7de;
17
+ --wsx-press-border-hover: #8c959f;
18
+
19
+ --wsx-press-link: #0969da;
20
+ --wsx-press-link-hover: #0550ae;
21
+
22
+ --wsx-press-accent: #dc2626; /* 继承 wsxjs 主色 */
23
+ --wsx-press-accent-hover: #b91c1c;
24
+
25
+ /* 代码高亮 */
26
+ --wsx-press-code-bg: #f6f8fa;
27
+ --wsx-press-code-text: #24292f;
28
+ --wsx-press-code-border: #d0d7de;
29
+
30
+ /* ===== 间距系统 ===== */
31
+ --wsx-press-spacing-xs: 0.25rem; /* 4px */
32
+ --wsx-press-spacing-sm: 0.5rem; /* 8px */
33
+ --wsx-press-spacing-md: 1rem; /* 16px */
34
+ --wsx-press-spacing-lg: 1.5rem; /* 24px */
35
+ --wsx-press-spacing-xl: 2rem; /* 32px */
36
+ --wsx-press-spacing-2xl: 3rem; /* 48px */
37
+ --wsx-press-spacing-3xl: 4rem; /* 64px */
38
+
39
+ /* ===== 字体系统 ===== */
40
+ --wsx-press-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
41
+ --wsx-press-font-mono: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
42
+
43
+ --wsx-press-font-size-xs: 0.75rem; /* 12px */
44
+ --wsx-press-font-size-sm: 0.875rem; /* 14px */
45
+ --wsx-press-font-size-base: 1rem; /* 16px */
46
+ --wsx-press-font-size-lg: 1.125rem; /* 18px */
47
+ --wsx-press-font-size-xl: 1.25rem; /* 20px */
48
+ --wsx-press-font-size-2xl: 1.5rem; /* 24px */
49
+ --wsx-press-font-size-3xl: 1.875rem; /* 30px */
50
+ --wsx-press-font-size-4xl: 2.25rem; /* 36px */
51
+
52
+ --wsx-press-line-height-tight: 1.25;
53
+ --wsx-press-line-height-normal: 1.5;
54
+ --wsx-press-line-height-relaxed: 1.75;
55
+
56
+ /* ===== 圆角 ===== */
57
+ --wsx-press-radius-sm: 0.25rem;
58
+ --wsx-press-radius-md: 0.5rem;
59
+ --wsx-press-radius-lg: 0.75rem;
60
+ --wsx-press-radius-xl: 1rem;
61
+
62
+ /* ===== 阴影 ===== */
63
+ --wsx-press-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
64
+ --wsx-press-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
65
+ --wsx-press-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
66
+ --wsx-press-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
67
+
68
+ /* ===== 布局 ===== */
69
+ --wsx-press-sidebar-width: 280px;
70
+ --wsx-press-toc-width: 240px;
71
+ --wsx-press-content-max-width: 800px;
72
+ --wsx-press-layout-max-width: 1440px;
73
+
74
+ /* ===== 动画 ===== */
75
+ --wsx-press-transition-fast: 150ms ease;
76
+ --wsx-press-transition-base: 200ms ease;
77
+ --wsx-press-transition-slow: 300ms ease;
78
+
79
+ /* ===== Z-index ===== */
80
+ --wsx-press-z-dropdown: 1000;
81
+ --wsx-press-z-modal: 1050;
82
+ --wsx-press-z-tooltip: 1100;
83
+ }
84
+
85
+ /* ===== 暗色模式(系统偏好) ===== */
86
+ @media (prefers-color-scheme: dark) {
87
+ :root {
88
+ --wsx-press-bg-primary: #0d1117;
89
+ --wsx-press-bg-secondary: #161b22;
90
+ --wsx-press-bg-tertiary: #21262d;
91
+
92
+ --wsx-press-text-primary: #e6edf3;
93
+ --wsx-press-text-secondary: #8b949e;
94
+ --wsx-press-text-tertiary: #6e7681;
95
+
96
+ --wsx-press-border: #30363d;
97
+ --wsx-press-border-hover: #484f58;
98
+
99
+ --wsx-press-link: #58a6ff;
100
+ --wsx-press-link-hover: #79c0ff;
101
+
102
+ --wsx-press-accent: #f87171;
103
+ --wsx-press-accent-hover: #fca5a5;
104
+
105
+ --wsx-press-code-bg: #161b22;
106
+ --wsx-press-code-text: #e6edf3;
107
+ --wsx-press-code-border: #30363d;
108
+
109
+ --wsx-press-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
110
+ --wsx-press-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
111
+ --wsx-press-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
112
+ --wsx-press-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
113
+ }
114
+ }
115
+
116
+ /* ===== 显式主题类(强制覆盖) ===== */
117
+ [data-theme="light"] {
118
+ --wsx-press-bg-primary: #ffffff;
119
+ --wsx-press-bg-secondary: #f6f8fa;
120
+ --wsx-press-bg-tertiary: #f0f2f5;
121
+
122
+ --wsx-press-text-primary: #1f2328;
123
+ --wsx-press-text-secondary: #636c76;
124
+ --wsx-press-text-tertiary: #8c959f;
125
+
126
+ --wsx-press-border: #d0d7de;
127
+ --wsx-press-border-hover: #8c959f;
128
+
129
+ --wsx-press-link: #0969da;
130
+ --wsx-press-link-hover: #0550ae;
131
+
132
+ --wsx-press-accent: #dc2626;
133
+ --wsx-press-accent-hover: #b91c1c;
134
+
135
+ --wsx-press-code-bg: #f6f8fa;
136
+ --wsx-press-code-text: #24292f;
137
+ --wsx-press-code-border: #d0d7de;
138
+
139
+ --wsx-press-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
140
+ --wsx-press-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
141
+ --wsx-press-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
142
+ --wsx-press-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
143
+ }
144
+
145
+ [data-theme="dark"] {
146
+ --wsx-press-bg-primary: #0d1117;
147
+ --wsx-press-bg-secondary: #161b22;
148
+ --wsx-press-bg-tertiary: #21262d;
149
+
150
+ --wsx-press-text-primary: #e6edf3;
151
+ --wsx-press-text-secondary: #8b949e;
152
+ --wsx-press-text-tertiary: #6e7681;
153
+
154
+ --wsx-press-border: #30363d;
155
+ --wsx-press-border-hover: #484f58;
156
+
157
+ --wsx-press-link: #58a6ff;
158
+ --wsx-press-link-hover: #79c0ff;
159
+
160
+ --wsx-press-accent: #f87171;
161
+ --wsx-press-accent-hover: #fca5a5;
162
+
163
+ --wsx-press-code-bg: #161b22;
164
+ --wsx-press-code-text: #e6edf3;
165
+ --wsx-press-code-border: #30363d;
166
+
167
+ --wsx-press-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
168
+ --wsx-press-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
169
+ --wsx-press-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
170
+ --wsx-press-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
171
+ }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * WSX-Press 排版系统
3
+ * Markdown 内容样式
4
+ */
5
+
6
+ .wsx-press-typography {
7
+ font-family: var(--wsx-press-font-family);
8
+ font-size: var(--wsx-press-font-size-base);
9
+ line-height: var(--wsx-press-line-height-normal);
10
+ color: var(--wsx-press-text-primary);
11
+ word-wrap: break-word;
12
+ }
13
+
14
+ /* ===== 标题 ===== */
15
+ .wsx-press-typography h1,
16
+ .wsx-press-typography h2,
17
+ .wsx-press-typography h3,
18
+ .wsx-press-typography h4,
19
+ .wsx-press-typography h5,
20
+ .wsx-press-typography h6 {
21
+ margin-top: var(--wsx-press-spacing-xl);
22
+ margin-bottom: var(--wsx-press-spacing-md);
23
+ font-weight: 600;
24
+ line-height: var(--wsx-press-line-height-tight);
25
+ color: var(--wsx-press-text-primary);
26
+ }
27
+
28
+ .wsx-press-typography h1:first-child,
29
+ .wsx-press-typography h2:first-child,
30
+ .wsx-press-typography h3:first-child {
31
+ margin-top: 0;
32
+ }
33
+
34
+ .wsx-press-typography h1 {
35
+ font-size: var(--wsx-press-font-size-3xl);
36
+ font-weight: 700;
37
+ padding-bottom: var(--wsx-press-spacing-md);
38
+ border-bottom: 2px solid var(--wsx-press-border);
39
+ }
40
+
41
+ .wsx-press-typography h2 {
42
+ font-size: var(--wsx-press-font-size-2xl);
43
+ padding-bottom: var(--wsx-press-spacing-sm);
44
+ border-bottom: 1px solid var(--wsx-press-border);
45
+ }
46
+
47
+ .wsx-press-typography h3 {
48
+ font-size: var(--wsx-press-font-size-xl);
49
+ }
50
+
51
+ .wsx-press-typography h4 {
52
+ font-size: var(--wsx-press-font-size-lg);
53
+ }
54
+
55
+ .wsx-press-typography h5,
56
+ .wsx-press-typography h6 {
57
+ font-size: var(--wsx-press-font-size-base);
58
+ }
59
+
60
+ /* ===== 段落 ===== */
61
+ .wsx-press-typography p {
62
+ margin-top: 0;
63
+ margin-bottom: var(--wsx-press-spacing-md);
64
+ line-height: var(--wsx-press-line-height-relaxed);
65
+ }
66
+
67
+ /* ===== 链接 ===== */
68
+ .wsx-press-typography a {
69
+ color: var(--wsx-press-link);
70
+ text-decoration: none;
71
+ transition: color var(--wsx-press-transition-fast);
72
+ }
73
+
74
+ .wsx-press-typography a:hover {
75
+ color: var(--wsx-press-link-hover);
76
+ text-decoration: underline;
77
+ }
78
+
79
+ /* ===== 列表 ===== */
80
+ .wsx-press-typography ul,
81
+ .wsx-press-typography ol {
82
+ margin-top: 0;
83
+ margin-bottom: var(--wsx-press-spacing-md);
84
+ padding-left: var(--wsx-press-spacing-xl);
85
+ }
86
+
87
+ .wsx-press-typography li {
88
+ margin-bottom: var(--wsx-press-spacing-sm);
89
+ line-height: var(--wsx-press-line-height-relaxed);
90
+ }
91
+
92
+ .wsx-press-typography li > p {
93
+ margin-bottom: var(--wsx-press-spacing-sm);
94
+ }
95
+
96
+ .wsx-press-typography ul ul,
97
+ .wsx-press-typography ol ul,
98
+ .wsx-press-typography ul ol,
99
+ .wsx-press-typography ol ol {
100
+ margin-top: var(--wsx-press-spacing-sm);
101
+ margin-bottom: 0;
102
+ }
103
+
104
+ /* ===== 引用 ===== */
105
+ .wsx-press-typography blockquote {
106
+ margin: var(--wsx-press-spacing-lg) 0;
107
+ padding: var(--wsx-press-spacing-sm) var(--wsx-press-spacing-md);
108
+ padding-left: var(--wsx-press-spacing-lg);
109
+ border-left: 4px solid var(--wsx-press-accent);
110
+ background: var(--wsx-press-bg-secondary);
111
+ border-radius: var(--wsx-press-radius-sm);
112
+ color: var(--wsx-press-text-secondary);
113
+ }
114
+
115
+ .wsx-press-typography blockquote > :first-child {
116
+ margin-top: 0;
117
+ }
118
+
119
+ .wsx-press-typography blockquote > :last-child {
120
+ margin-bottom: 0;
121
+ }
122
+
123
+ /* ===== 行内代码 ===== */
124
+ .wsx-press-typography code {
125
+ font-family: var(--wsx-press-font-mono);
126
+ font-size: 0.9em;
127
+ padding: 0.2em 0.4em;
128
+ background: var(--wsx-press-code-bg);
129
+ border: 1px solid var(--wsx-press-code-border);
130
+ border-radius: var(--wsx-press-radius-sm);
131
+ color: var(--wsx-press-code-text);
132
+ }
133
+
134
+ .wsx-press-typography a code {
135
+ color: var(--wsx-press-link);
136
+ }
137
+
138
+ /* ===== 代码块 ===== */
139
+ .wsx-press-typography pre {
140
+ margin: var(--wsx-press-spacing-lg) 0;
141
+ padding: var(--wsx-press-spacing-md);
142
+ background: var(--wsx-press-code-bg);
143
+ border: 1px solid var(--wsx-press-code-border);
144
+ border-radius: var(--wsx-press-radius-md);
145
+ overflow-x: auto;
146
+ line-height: var(--wsx-press-line-height-normal);
147
+ }
148
+
149
+ .wsx-press-typography pre code {
150
+ padding: 0;
151
+ background: none;
152
+ border: none;
153
+ font-size: var(--wsx-press-font-size-sm);
154
+ color: var(--wsx-press-code-text);
155
+ }
156
+
157
+ /* ===== 表格 ===== */
158
+ .wsx-press-typography table {
159
+ width: 100%;
160
+ border-collapse: collapse;
161
+ margin: var(--wsx-press-spacing-lg) 0;
162
+ display: block;
163
+ overflow-x: auto;
164
+ }
165
+
166
+ .wsx-press-typography th,
167
+ .wsx-press-typography td {
168
+ padding: var(--wsx-press-spacing-sm) var(--wsx-press-spacing-md);
169
+ border: 1px solid var(--wsx-press-border);
170
+ text-align: left;
171
+ }
172
+
173
+ .wsx-press-typography thead th {
174
+ background: var(--wsx-press-bg-secondary);
175
+ font-weight: 600;
176
+ color: var(--wsx-press-text-primary);
177
+ }
178
+
179
+ .wsx-press-typography tbody tr:hover {
180
+ background: var(--wsx-press-bg-tertiary);
181
+ }
182
+
183
+ /* ===== 分隔线 ===== */
184
+ .wsx-press-typography hr {
185
+ height: 1px;
186
+ border: none;
187
+ background: var(--wsx-press-border);
188
+ margin: var(--wsx-press-spacing-2xl) 0;
189
+ }
190
+
191
+ /* ===== 图片 ===== */
192
+ .wsx-press-typography img {
193
+ max-width: 100%;
194
+ height: auto;
195
+ display: block;
196
+ margin: var(--wsx-press-spacing-lg) auto;
197
+ border-radius: var(--wsx-press-radius-md);
198
+ }
199
+
200
+ /* ===== 任务列表 ===== */
201
+ .wsx-press-typography input[type="checkbox"] {
202
+ margin-right: var(--wsx-press-spacing-sm);
203
+ }
204
+
205
+ .wsx-press-typography .task-list-item {
206
+ list-style-type: none;
207
+ }
208
+
209
+ .wsx-press-typography .task-list-item input[type="checkbox"] {
210
+ margin-left: calc(var(--wsx-press-spacing-xl) * -1);
211
+ }
212
+
213
+ /* ===== 强调 ===== */
214
+ .wsx-press-typography strong {
215
+ font-weight: 600;
216
+ color: var(--wsx-press-text-primary);
217
+ }
218
+
219
+ .wsx-press-typography em {
220
+ font-style: italic;
221
+ }
222
+
223
+ /* ===== 删除线 ===== */
224
+ .wsx-press-typography del {
225
+ text-decoration: line-through;
226
+ color: var(--wsx-press-text-tertiary);
227
+ }
228
+
229
+ /* ===== 键盘按键 ===== */
230
+ .wsx-press-typography kbd {
231
+ display: inline-block;
232
+ padding: 0.1em 0.4em;
233
+ font-family: var(--wsx-press-font-mono);
234
+ font-size: 0.85em;
235
+ background: var(--wsx-press-bg-tertiary);
236
+ border: 1px solid var(--wsx-press-border);
237
+ border-radius: var(--wsx-press-radius-sm);
238
+ box-shadow: inset 0 -1px 0 var(--wsx-press-border);
239
+ }
package/src/index.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @wsxjs/wsx-press
3
+ * Main entry point
4
+ */
5
+
6
+ // Export types
7
+ export type {
8
+ DocMetadata,
9
+ DocsMetaCollection,
10
+ SearchDocument,
11
+ SearchResult,
12
+ SearchIndex,
13
+ SearchIndexOptions,
14
+ RouteParams,
15
+ ApiRouteParams,
16
+ LoadingState,
17
+ DocumentLoadErrorCode,
18
+ } from "./types";
19
+
20
+ export { DocumentLoadError } from "./types";
21
+
22
+ // Export client components (will be implemented later)
23
+ // export * from "./client/index";
24
+
25
+ // Export node utilities (will be implemented later)
26
+ // export * from "./node/index";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @wsxjs/wsx-press/node
3
+ * Node.js build tools entry point
4
+ */
5
+
6
+ // Export metadata utilities
7
+ export { scanDocsMetadata, extractFrontmatter, addPrevNextLinks } from "./metadata";
8
+
9
+ // Export search utilities
10
+ export { generateSearchIndex } from "./search";
11
+
12
+ // Export TypeDoc utilities
13
+ export { generateApiDocs, type TypeDocConfig } from "./typedoc";
14
+
15
+ // Export Vite plugin
16
+ export { wsxPress, type WSXPressOptions } from "./plugin";
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @wsxjs/wsx-press/node/metadata
3
+ * Document metadata scanning and processing
4
+ */
5
+
6
+ import { glob } from "glob";
7
+ import path from "path";
8
+ import fs from "fs-extra";
9
+ import type { DocsMetaCollection, DocMetadata } from "../types";
10
+
11
+ /**
12
+ * 扫描文档目录,生成元数据集合
13
+ *
14
+ * @param docsRoot - 文档根目录路径
15
+ * @returns 文档元数据集合
16
+ */
17
+ export async function scanDocsMetadata(docsRoot: string): Promise<DocsMetaCollection> {
18
+ const files = await glob("**/*.md", { cwd: docsRoot, absolute: true });
19
+ const metadata: DocsMetaCollection = {};
20
+
21
+ for (const file of files) {
22
+ const relativePath = path.relative(docsRoot, file);
23
+ const content = await fs.readFile(file, "utf-8");
24
+ const frontmatter = extractFrontmatter(content);
25
+ const key = relativePath.replace(/\.md$/, "");
26
+
27
+ const dirname = path.dirname(relativePath);
28
+ metadata[key] = {
29
+ title: frontmatter.title || path.basename(file, ".md"),
30
+ category: dirname === "." ? "." : dirname,
31
+ route: `/docs/${key}`,
32
+ ...frontmatter,
33
+ };
34
+ }
35
+
36
+ return addPrevNextLinks(metadata);
37
+ }
38
+
39
+ /**
40
+ * 从 Markdown 中提取 frontmatter
41
+ * 返回部分 DocMetadata,因为不是所有字段都在 frontmatter 中
42
+ *
43
+ * @param markdown - Markdown 内容
44
+ * @returns 提取的 frontmatter 数据
45
+ */
46
+ export function extractFrontmatter(markdown: string): Partial<DocMetadata> {
47
+ const match = markdown.match(/^---\n([\s\S]*?)\n---/);
48
+ if (!match) {
49
+ return {};
50
+ }
51
+
52
+ const yaml = match[1];
53
+ const meta: Partial<DocMetadata> = {};
54
+
55
+ yaml.split("\n").forEach((line) => {
56
+ const colonIndex = line.indexOf(":");
57
+ if (colonIndex === -1) {
58
+ return;
59
+ }
60
+
61
+ const key = line.substring(0, colonIndex).trim();
62
+ const value = line.substring(colonIndex + 1).trim();
63
+
64
+ if (key && value) {
65
+ // 类型安全的属性赋值
66
+ if (key === "title" || key === "description" || key === "category") {
67
+ (meta as Record<string, string>)[key] = value;
68
+ } else if (key === "tags") {
69
+ // 简单的数组解析(实际应使用 YAML 解析器)
70
+ meta.tags = value
71
+ .replace(/[[\]]/g, "")
72
+ .split(",")
73
+ .map((t) => t.trim());
74
+ } else {
75
+ // 其他扩展字段
76
+ (meta as Record<string, unknown>)[key] = value;
77
+ }
78
+ }
79
+ });
80
+
81
+ return meta;
82
+ }
83
+
84
+ /**
85
+ * 为元数据集合添加上一页/下一页链接
86
+ *
87
+ * @param metadata - 元数据集合
88
+ * @returns 添加了导航链接的元数据集合
89
+ */
90
+ export function addPrevNextLinks(metadata: DocsMetaCollection): DocsMetaCollection {
91
+ const categories = new Map<string, string[]>();
92
+
93
+ // 按类别分组
94
+ for (const [key, meta] of Object.entries(metadata)) {
95
+ const category = meta.category;
96
+ if (!categories.has(category)) {
97
+ categories.set(category, []);
98
+ }
99
+ categories.get(category)!.push(key);
100
+ }
101
+
102
+ // 为每个类别添加 prev/next
103
+ for (const [_category, keys] of categories) {
104
+ keys.sort();
105
+ for (let i = 0; i < keys.length; i++) {
106
+ const key = keys[i];
107
+ metadata[key].prev = i > 0 ? `/docs/${keys[i - 1]}` : null;
108
+ metadata[key].next = i < keys.length - 1 ? `/docs/${keys[i + 1]}` : null;
109
+ }
110
+ }
111
+
112
+ return metadata;
113
+ }