@flun/html-template 4.0.10

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.
Files changed (59) hide show
  1. package/.env +9 -0
  2. package/LICENSE +15 -0
  3. package/build.js +3 -0
  4. package/compile.js +349 -0
  5. package/copy-files.js +200 -0
  6. package/customize/account.js +726 -0
  7. package/customize/data.json +484 -0
  8. package/customize/functions.js +48 -0
  9. package/customize/hotReloadInjector.js +25 -0
  10. package/customize/routes.js +141 -0
  11. package/customize/users.json +44 -0
  12. package/customize/variables.js +70 -0
  13. package/dev-server.js +344 -0
  14. package/dev.js +4 -0
  15. package/f-CHANGELOG.md +4 -0
  16. package/f-README.md +485 -0
  17. package/index.d.ts +133 -0
  18. package/index.js +4 -0
  19. package/package.json +77 -0
  20. package/restoreDefaults.js +8 -0
  21. package/services/templateService.js +962 -0
  22. package/static/about.css +118 -0
  23. package/static/auth.js +27 -0
  24. package/static/constants.css +138 -0
  25. package/static/img/dark.png +0 -0
  26. package/static/img/favicon.ico +0 -0
  27. package/static/img/light.png +0 -0
  28. package/static/img/top.png +0 -0
  29. package/static/index.css +86 -0
  30. package/static/mouseOrTouch.js +156 -0
  31. package/static/public.css +288 -0
  32. package/static/script.css +318 -0
  33. package/static/script.js +392 -0
  34. package/static/styling.css +874 -0
  35. package/static/styling.js +933 -0
  36. package/static/themeImg.css +10 -0
  37. package/static/themeImg.js +19 -0
  38. package/static/themeModule.js +222 -0
  39. package/static/topImg.css +19 -0
  40. package/static/topImg.js +21 -0
  41. package/static/utils/browser13.js +270 -0
  42. package/static/utils/closebrackets.js +166 -0
  43. package/static/utils/css-lint.js +308 -0
  44. package/static/utils/custom-css-hint.js +876 -0
  45. package/static/utils/foldgutter.js +141 -0
  46. package/static/utils/match-highlighter.js +70 -0
  47. package/templates/about.html +236 -0
  48. package/templates/account/2fa.html +184 -0
  49. package/templates/account/forgot-password.html +226 -0
  50. package/templates/account/login.html +230 -0
  51. package/templates/account/profile.html +977 -0
  52. package/templates/account/register.html +224 -0
  53. package/templates/account/reset-password.html +205 -0
  54. package/templates/account/verify-email.html +163 -0
  55. package/templates/base.html +71 -0
  56. package/templates/footer-content.html +5 -0
  57. package/templates/index.html +140 -0
  58. package/templates/script.html +209 -0
  59. package/templates/test-include.html +11 -0
@@ -0,0 +1,484 @@
1
+ {
2
+ "topImg": {
3
+ "1492x874": {
4
+ "style": {
5
+ "left": "1375px",
6
+ "top": "793.5px",
7
+ "right": "auto",
8
+ "bottom": "auto"
9
+ }
10
+ },
11
+ "384x682": {
12
+ "style": {
13
+ "left": "321.722px",
14
+ "top": "602.178px",
15
+ "right": "auto",
16
+ "bottom": "auto"
17
+ }
18
+ },
19
+ "357x669": {
20
+ "style": {
21
+ "left": "334.089px",
22
+ "top": "522.044px",
23
+ "right": "auto",
24
+ "bottom": "auto"
25
+ }
26
+ }
27
+ },
28
+ "themeImg": {
29
+ "1492x874": {
30
+ "style": {
31
+ "left": "22px",
32
+ "top": "24.5px",
33
+ "right": "auto",
34
+ "bottom": "auto"
35
+ }
36
+ },
37
+ "384x682": {
38
+ "style": {
39
+ "left": "14.4px",
40
+ "top": "9.18329px",
41
+ "right": "auto",
42
+ "bottom": "auto"
43
+ }
44
+ },
45
+ "1492x332": {
46
+ "style": {
47
+ "left": "15px",
48
+ "top": "17px",
49
+ "right": "auto",
50
+ "bottom": "auto"
51
+ }
52
+ },
53
+ "1479x544": {
54
+ "style": {
55
+ "left": "26.5px",
56
+ "top": "23.5px",
57
+ "right": "auto",
58
+ "bottom": "auto"
59
+ }
60
+ },
61
+ "1492x359": {
62
+ "style": {
63
+ "left": "28.5px",
64
+ "top": "15px",
65
+ "right": "auto",
66
+ "bottom": "auto"
67
+ }
68
+ },
69
+ "1492x564": {
70
+ "style": {
71
+ "left": "50px",
72
+ "top": "70.5px",
73
+ "right": "auto",
74
+ "bottom": "auto"
75
+ }
76
+ },
77
+ "1492x273": {
78
+ "style": {
79
+ "left": "30.5px",
80
+ "top": "25.5px",
81
+ "right": "auto",
82
+ "bottom": "auto"
83
+ }
84
+ },
85
+ "1480x544": {
86
+ "style": {
87
+ "left": "136px",
88
+ "top": "129.5px",
89
+ "right": "auto",
90
+ "bottom": "auto"
91
+ }
92
+ },
93
+ "700x800": {
94
+ "style": {
95
+ "left": "18px",
96
+ "top": "28px",
97
+ "right": "auto",
98
+ "bottom": "auto"
99
+ }
100
+ },
101
+ "1492x868": {
102
+ "style": {
103
+ "left": "25px",
104
+ "top": "25.5px",
105
+ "right": "auto",
106
+ "bottom": "auto"
107
+ }
108
+ }
109
+ },
110
+ "longPic": {
111
+ "1492x874": {
112
+ "style": {
113
+ "left": "50%",
114
+ "top": "50%",
115
+ "right": "auto",
116
+ "bottom": "auto"
117
+ }
118
+ },
119
+ "1492x868": {
120
+ "style": {
121
+ "left": "931px",
122
+ "top": "246px",
123
+ "right": "auto",
124
+ "bottom": "auto"
125
+ }
126
+ }
127
+ },
128
+ "cssEditor": {
129
+ "1492x874": {
130
+ "style": {
131
+ "left": "721.5px",
132
+ "top": "50px",
133
+ "right": "auto",
134
+ "bottom": "auto"
135
+ }
136
+ },
137
+ "384x682": {
138
+ "style": {
139
+ "left": "15.4555px",
140
+ "top": "14.4833px",
141
+ "right": "auto",
142
+ "bottom": "auto"
143
+ }
144
+ },
145
+ "1492x602": {
146
+ "style": {
147
+ "left": "390px",
148
+ "top": "24px",
149
+ "right": "auto",
150
+ "bottom": "auto"
151
+ }
152
+ },
153
+ "1492x288": {
154
+ "style": {
155
+ "left": "383px",
156
+ "top": "74px",
157
+ "right": "auto",
158
+ "bottom": "auto"
159
+ }
160
+ },
161
+ "1479x542": {
162
+ "style": {
163
+ "left": "400px",
164
+ "top": "17px",
165
+ "right": "auto",
166
+ "bottom": "auto"
167
+ }
168
+ },
169
+ "1479x544": {
170
+ "style": {
171
+ "left": "256px",
172
+ "top": "30.5px",
173
+ "right": "auto",
174
+ "bottom": "auto"
175
+ }
176
+ },
177
+ "1492x359": {
178
+ "style": {
179
+ "left": "563.5px",
180
+ "top": "71px",
181
+ "right": "auto",
182
+ "bottom": "auto"
183
+ }
184
+ },
185
+ "1492x564": {
186
+ "style": {
187
+ "left": "564px",
188
+ "top": "74px",
189
+ "right": "auto",
190
+ "bottom": "auto"
191
+ }
192
+ },
193
+ "1492x273": {
194
+ "style": {
195
+ "left": "766.5px",
196
+ "top": "35.5px",
197
+ "right": "auto",
198
+ "bottom": "auto"
199
+ }
200
+ },
201
+ "1500x849": {
202
+ "style": {
203
+ "left": "769px",
204
+ "top": "41px",
205
+ "right": "auto",
206
+ "bottom": "auto"
207
+ }
208
+ },
209
+ "400x685": {
210
+ "style": {
211
+ "left": "730.5px",
212
+ "top": "38.5px",
213
+ "right": "auto",
214
+ "bottom": "auto"
215
+ }
216
+ },
217
+ "384x691": {
218
+ "style": {
219
+ "left": "52.5333px",
220
+ "top": "-2.31111px",
221
+ "right": "auto",
222
+ "bottom": "auto"
223
+ }
224
+ },
225
+ "357x669": {
226
+ "style": {
227
+ "left": "32.7722px",
228
+ "top": "6px",
229
+ "right": "auto",
230
+ "bottom": "auto"
231
+ }
232
+ },
233
+ "1492x868": {
234
+ "style": {
235
+ "left": "753px",
236
+ "top": "33.5px",
237
+ "right": "auto",
238
+ "bottom": "auto"
239
+ }
240
+ },
241
+ "384x693": {
242
+ "style": {
243
+ "left": "24.2923px",
244
+ "top": "1.08228px",
245
+ "right": "auto",
246
+ "bottom": "auto"
247
+ }
248
+ },
249
+ "desktop": {
250
+ "top": 27,
251
+ "left": 764
252
+ },
253
+ "1492x170": {
254
+ "style": {
255
+ "left": "764px",
256
+ "top": "25px",
257
+ "right": "auto",
258
+ "bottom": "auto"
259
+ }
260
+ },
261
+ "1479x606": {
262
+ "style": {
263
+ "left": "743.5px",
264
+ "top": "15px",
265
+ "right": "auto",
266
+ "bottom": "auto"
267
+ }
268
+ },
269
+ "1492x464": {
270
+ "style": {
271
+ "left": "750px",
272
+ "top": "40px",
273
+ "right": "auto",
274
+ "bottom": "auto"
275
+ }
276
+ },
277
+ "1492x150": {
278
+ "style": {
279
+ "left": "757px",
280
+ "top": "48px",
281
+ "right": "auto",
282
+ "bottom": "auto"
283
+ }
284
+ },
285
+ "1492x153": {
286
+ "style": {
287
+ "left": "753px",
288
+ "top": "34px",
289
+ "right": "auto",
290
+ "bottom": "auto"
291
+ }
292
+ },
293
+ "1492x271": {
294
+ "style": {
295
+ "left": "750px",
296
+ "top": "40px",
297
+ "right": "auto",
298
+ "bottom": "auto"
299
+ }
300
+ },
301
+ "1492x231": {
302
+ "style": {
303
+ "left": "741px",
304
+ "top": "33px",
305
+ "right": "auto",
306
+ "bottom": "auto"
307
+ }
308
+ },
309
+ "1492x182": {
310
+ "style": {
311
+ "left": "744px",
312
+ "top": "32px",
313
+ "right": "auto",
314
+ "bottom": "auto"
315
+ }
316
+ },
317
+ "1492x622": {
318
+ "style": {
319
+ "left": "745px",
320
+ "top": "43.5px",
321
+ "right": "auto",
322
+ "bottom": "auto"
323
+ }
324
+ },
325
+ "1492x194": {
326
+ "style": {
327
+ "left": "740px",
328
+ "top": "29.5px",
329
+ "right": "auto",
330
+ "bottom": "auto"
331
+ }
332
+ },
333
+ "1492x405": {
334
+ "style": {
335
+ "left": "766px",
336
+ "top": "29px",
337
+ "right": "auto",
338
+ "bottom": "auto"
339
+ }
340
+ },
341
+ "1492x336": {
342
+ "style": {
343
+ "left": "754px",
344
+ "top": "47px",
345
+ "right": "auto",
346
+ "bottom": "auto"
347
+ }
348
+ },
349
+ "1492x547": {
350
+ "style": {
351
+ "left": "756px",
352
+ "top": "34px",
353
+ "right": "auto",
354
+ "bottom": "auto"
355
+ }
356
+ },
357
+ "1492x161": {
358
+ "style": {
359
+ "left": "744px",
360
+ "top": "38px",
361
+ "right": "auto",
362
+ "bottom": "auto"
363
+ }
364
+ }
365
+ },
366
+ "preview": {
367
+ "1492x874": {
368
+ "style": {
369
+ "left": "31px",
370
+ "top": "53px",
371
+ "right": "auto",
372
+ "bottom": "auto"
373
+ }
374
+ },
375
+ "384x682": {
376
+ "style": {
377
+ "left": "-236.989px",
378
+ "top": "52.5556px",
379
+ "right": "auto",
380
+ "bottom": "auto"
381
+ }
382
+ },
383
+ "1492x602": {
384
+ "style": {
385
+ "left": "390px",
386
+ "top": "24px",
387
+ "right": "auto",
388
+ "bottom": "auto"
389
+ }
390
+ },
391
+ "1492x288": {
392
+ "style": {
393
+ "left": "383px",
394
+ "top": "74px",
395
+ "right": "auto",
396
+ "bottom": "auto"
397
+ }
398
+ },
399
+ "1479x542": {
400
+ "style": {
401
+ "left": "400px",
402
+ "top": "17px",
403
+ "right": "auto",
404
+ "bottom": "auto"
405
+ }
406
+ },
407
+ "1479x544": {
408
+ "style": {
409
+ "left": "256px",
410
+ "top": "30.5px",
411
+ "right": "auto",
412
+ "bottom": "auto"
413
+ }
414
+ },
415
+ "1492x359": {
416
+ "style": {
417
+ "left": "563.5px",
418
+ "top": "71px",
419
+ "right": "auto",
420
+ "bottom": "auto"
421
+ }
422
+ },
423
+ "1492x564": {
424
+ "style": {
425
+ "left": "564px",
426
+ "top": "74px",
427
+ "right": "auto",
428
+ "bottom": "auto"
429
+ }
430
+ },
431
+ "1492x273": {
432
+ "style": {
433
+ "left": "766.5px",
434
+ "top": "35.5px",
435
+ "right": "auto",
436
+ "bottom": "auto"
437
+ }
438
+ },
439
+ "1500x849": {
440
+ "style": {
441
+ "left": "44px",
442
+ "top": "39px",
443
+ "right": "auto",
444
+ "bottom": "auto"
445
+ }
446
+ },
447
+ "400x685": {
448
+ "style": {
449
+ "left": "-269px",
450
+ "top": "39px",
451
+ "right": "auto",
452
+ "bottom": "auto"
453
+ }
454
+ },
455
+ "357x669": {
456
+ "style": {
457
+ "left": "-320px",
458
+ "top": "114.599px",
459
+ "right": "auto",
460
+ "bottom": "auto"
461
+ }
462
+ },
463
+ "1492x868": {
464
+ "style": {
465
+ "left": "15px",
466
+ "top": "38.5px",
467
+ "right": "auto",
468
+ "bottom": "auto"
469
+ }
470
+ },
471
+ "384x693": {
472
+ "style": {
473
+ "left": "-157.932px",
474
+ "top": "57.3333px",
475
+ "right": "auto",
476
+ "bottom": "auto"
477
+ }
478
+ },
479
+ "desktop": {
480
+ "top": 11,
481
+ "left": -3
482
+ }
483
+ }
484
+ }
@@ -0,0 +1,48 @@
1
+ // 自定义工具函数示例
2
+
3
+ export default {
4
+ functions: {
5
+ // 简单计算器函数
6
+ add: (a, b) => {
7
+ return a + b;
8
+ },
9
+
10
+ subtract: (a, b) => {
11
+ return a - b;
12
+ },
13
+
14
+ multiply: (a, b) => {
15
+ return a * b;
16
+ },
17
+
18
+ divide: (a, b) => {
19
+ return b !== 0 ? a / b : '错误: 除零错误';
20
+ },
21
+
22
+ // 简单问候函数
23
+ greet: name => {
24
+ return `你好, ${name}!`;
25
+ },
26
+
27
+ // 带时间的问候
28
+ greetWithTime: name => {
29
+ return `你好, ${name}! 现在是 ${new Date().toLocaleTimeString()}`;
30
+ },
31
+
32
+ // 格式化日期
33
+ formatDate: date => {
34
+ // 处理无参数调用
35
+ if (date === undefined) return new Date().toLocaleDateString('zh-CN');
36
+
37
+ // 处理字符串输入
38
+ if (typeof date === 'string') {
39
+ const parsedDate = new Date(date);
40
+ return isNaN(parsedDate.getTime()) ? '字符串无效' : parsedDate.toLocaleDateString('zh-CN');
41
+ }
42
+
43
+ // 处理其他类型
44
+ const dateObj = new Date(date);
45
+ return isNaN(dateObj.getTime()) ? '无效日期' : dateObj.toLocaleDateString('zh-CN');
46
+ }
47
+ }
48
+ };
@@ -0,0 +1,25 @@
1
+ /**注入热重载脚本到 HTML 中
2
+ * > 查看定义:@see {@link injectScript}
3
+ * @param {string} html - 原始 HTML 内容
4
+ * @returns {string} 注入热重载脚本后的 HTML 内容
5
+ */
6
+ const injectScript = html => {
7
+ if (/hot-reload-socket|socket\.io\.js/.test(html)) return html; // 避免重复注入
8
+ const socketScript = `
9
+ <script src="/socket.io/socket.io.js"></script>
10
+ <script>
11
+ (function() {
12
+ var socket = io();
13
+ socket.on('hot-reload', delay => {
14
+ console.log('[热重载] 检测到文件更改,' + delay + '毫秒后重新加载页面...');
15
+ setTimeout(() => window.location.reload(), delay);
16
+ });
17
+ })();
18
+ </script>
19
+ `;
20
+
21
+ if (html.includes('</body>')) return html.replace('</body>', `${socketScript}</body>`);
22
+ return html + socketScript;
23
+ };
24
+
25
+ export { injectScript };
@@ -0,0 +1,141 @@
1
+ // /customize/routes.js
2
+ import express from 'express';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url), __dirname = path.dirname(__filename),
8
+ dataFile = path.join(__dirname, 'data.json'), imgDir = path.join(__dirname, '../static/img');
9
+
10
+ /** @type {(app: import('express').Express) => void} */
11
+ let accountRouter;
12
+ try {
13
+ /**
14
+ * 尝试加载 account.js 中的 accountRouter 函数,如果文件不存在或没有导出该函数,则继续执行后续代码;
15
+ * 当前的设计是为了兼容启用了登录模式的用户;只有启用登录模式才会创建 account.js;
16
+ */
17
+ ({ accountRouter } = await import('./account.js'));
18
+ } catch { }
19
+
20
+ // 非认证路由:元素样式、CSS编辑、图片管理、自定义API等
21
+ export default {
22
+ setupRoutes: app => {
23
+ if (!accountRouter) {
24
+ app.get('/api/user', (req, res) => {
25
+ res.json({ message: '登录功能未启用' });
26
+ });
27
+ }
28
+ accountRouter?.(app);
29
+ app.use(express.json(), express.urlencoded({ extended: true }));
30
+
31
+ // ============ 元素样式 API ============
32
+ let data;
33
+ try {
34
+ data = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
35
+ } catch (e) {
36
+ data = {};
37
+ }
38
+
39
+ const elements = ['topImg', 'themeImg', 'longPic', 'cssEditor', 'preview'],
40
+ getElementStyle = (elementKey) => {
41
+ return (req, res) => {
42
+ try {
43
+ res.json(data[elementKey] || {});
44
+ } catch (error) {
45
+ console.error(`读取${elementKey}样式失败:`, error);
46
+ res.status(500).json({ error: '服务器错误' });
47
+ }
48
+ };
49
+ },
50
+ updateElementStyle = (elementKey) => {
51
+ return (req, res) => {
52
+ try {
53
+ const devViewSize = Object.keys(req.body)[0];
54
+ if (!devViewSize) return res.status(400).json({ error: '缺少设备标识' });
55
+ if (!data[elementKey]) data[elementKey] = {};
56
+ data[elementKey][devViewSize] = req.body[devViewSize];
57
+ fs.writeFileSync(dataFile, JSON.stringify(data, null, 2));
58
+ res.json({ success: true, message: `${elementKey}已更新`, deviceId: devViewSize });
59
+ } catch (error) {
60
+ console.error(`更新${elementKey}失败:`, error);
61
+ res.status(500).json({ error: '服务器错误' });
62
+ }
63
+ };
64
+ };
65
+
66
+ elements.forEach(element => {
67
+ app.get(`/api/${element}`, getElementStyle(element));
68
+ app.post(`/api/${element}`, updateElementStyle(element));
69
+ });
70
+ console.log('✅ 元素样式路由已加载');
71
+
72
+ // ============ CSS 文件操作 ============
73
+ app.get('/api/css', (req, res) => {
74
+ const fileDir = req.query.fileDir;
75
+ if (!fileDir) return res.status(400).json({ error: '缺少文件路径' });
76
+ if (!fileDir.endsWith('.css')) return res.status(403).json({ error: '只允许操作 CSS 文件' });
77
+
78
+ try {
79
+ const normalizedPath = fileDir.startsWith('/') ? fileDir.slice(1) : fileDir,
80
+ filePath = path.resolve(normalizedPath);
81
+ if (!fs.existsSync(filePath)) return res.status(404).json({ error: '文件不存在' });
82
+ const content = fs.readFileSync(filePath, 'utf8');
83
+ res.type('text/plain').send(content);
84
+ } catch (error) {
85
+ console.error('读取 CSS 失败:', error);
86
+ res.status(500).json({ error: '服务器错误' });
87
+ }
88
+ });
89
+
90
+ app.post('/api/css', (req, res) => {
91
+ const { fileDir, content } = req.body;
92
+ if (!fileDir || content === undefined) return res.status(400).json({ error: '缺少参数' });
93
+ if (!fileDir.endsWith('.css')) return res.status(403).json({ error: '只允许操作 CSS 文件' });
94
+
95
+ try {
96
+ const normalizedPath = fileDir.startsWith('/') ? fileDir.slice(1) : fileDir,
97
+ filePath = path.resolve(normalizedPath),
98
+ dir = path.dirname(filePath);
99
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
100
+ fs.writeFileSync(filePath, content, 'utf8');
101
+ res.json({ success: true, message: 'CSS 已保存' });
102
+ } catch (error) {
103
+ console.error('保存 CSS 失败:', error);
104
+ res.status(500).json({ error: '服务器错误' });
105
+ }
106
+ });
107
+ console.log('✅ CSS 编辑路由已加载');
108
+
109
+ // ============ 图片列表 ============
110
+ app.get('/api/images', (req, res) => {
111
+ try {
112
+ if (!fs.existsSync(imgDir)) return res.json([]);
113
+ const files = fs.readdirSync(imgDir), imgs = files.filter((f) => /\.(jpg|jpeg|png|gif|webp|svg|ico)$/i.test(f));
114
+ res.json(imgs);
115
+ } catch (error) {
116
+ console.error('获取图片列表失败:', error);
117
+ res.status(500).json({ error: '服务器错误' });
118
+ }
119
+ });
120
+ console.log('✅ 非认证路由加载完成(routes.js)');
121
+
122
+ // ============ 其它自定义API路由 ============
123
+ app.get('/api/greeting', (req, res) => {
124
+ res.json({ message: '你好!这是来自用户自定义路由的问候!' });
125
+ });
126
+
127
+ app.get('/api/hi/:name', (req, res) => {
128
+ res.json({
129
+ message: `你好, ${req.params.name}!`, timestamp: new Date().toLocaleString('zh-CN'),
130
+ });
131
+ });
132
+
133
+ app.post('/api/contact', (req, res) => {
134
+ res.json({
135
+ success: true, message: '感谢您的留言!',
136
+ });
137
+ });
138
+
139
+ console.log('✅ 自定义路由已加载!');
140
+ },
141
+ };