edgepress 2026.10.13 → 2026.10.14
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 +22 -3
- package/package.json +11 -8
- package/src/cli.js +39 -4
- package/src/page-block-catalog.json +345 -0
- package/src/page-editor-client.js +396 -0
- package/src/page-editor-extension.js +86 -0
- package/src/page-editor.css +1 -0
- package/src/page-editor.html +40 -0
- package/src/page-editor.js +178 -0
- package/src/page-scaffold.js +70 -0
- package/tests/document-package.test.mjs +4 -9
- package/tests/oembed-layout.test.mjs +7 -3
- package/tests/page-editor.test.mjs +106 -0
- package/tests/page-scaffold.test.mjs +125 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ EdgePress automatically registers page-specific native WebMCP tools for reading
|
|
|
8
8
|
|
|
9
9
|
Document previews use the browser-only `document-viewer` package: PDF, DOC/DOCX, PPT/PPTX and XLS/XLSX render inside the page automatically without moving keyboard focus. Articles accept `!document[Report](/documents/report.docx)`; Pages support `type: document`. Remote direct-file URLs require a configured consent service and CORS. See the theme-development guide.
|
|
10
10
|
|
|
11
|
-
The dependency is pinned to a full commit in the public [document-viewer repository](https://github.com/jsw-teams/document-viewer). Cloud `npm
|
|
11
|
+
The dependency is pinned to a full commit in the public [document-viewer repository](https://github.com/jsw-teams/document-viewer). Cloud `npm install` needs no sibling checkout, bundled source snapshot or Office conversion software. Publish and validate document-viewer first, then update the dependency URL and lockfile here. Sites can consume the resulting pinned EdgePress commit without copying either implementation.
|
|
12
12
|
|
|
13
13
|
[](https://deploy.workers.cloudflare.com/?url=https://github.com/jsw-teams/edgepress)
|
|
14
14
|
[](https://edgeone.ai/pages/new?repository-url=https%3A%2F%2Fgithub.com%2Fjsw-teams%2Fedgepress&build-command=npm%20run%20build&install-command=npm%20ci&output-directory=dist)
|
|
@@ -36,7 +36,7 @@ Buttons open repository setup. Cloudflare, Vercel, Netlify and EdgeOne support r
|
|
|
36
36
|
|
|
37
37
|
## Quick start
|
|
38
38
|
|
|
39
|
-
The commands below install the published npm release and initialize a new project directory. For the latest GitHub changes, use the deployment buttons or clone this repository, then run `npm
|
|
39
|
+
The commands below install the published npm release and initialize a new project directory. For the latest GitHub changes, use the deployment buttons or clone this repository, then run `npm install` and `npm run dev` from its root:
|
|
40
40
|
|
|
41
41
|
mkdir my-edgepress-site
|
|
42
42
|
cd my-edgepress-site
|
|
@@ -45,7 +45,7 @@ The commands below install the published npm release and initialize a new projec
|
|
|
45
45
|
npm install
|
|
46
46
|
npm run dev
|
|
47
47
|
|
|
48
|
-
Use Node.js 22.12 or newer. Set the real site URL and operator contact in config.yml before publishing. Deploy with edgepress deploy. When developing EdgePress itself, use `npm
|
|
48
|
+
Use Node.js 22.12 or newer. Set the real site URL and operator contact in config.yml before publishing. Deploy with edgepress deploy. When developing EdgePress itself, use `npm install`, then `npm link` to expose the local CLI.
|
|
49
49
|
|
|
50
50
|
Run `edgepress init` in a new project directory to scaffold a site pinned to the installed EdgePress release. The initializer keeps the existing package name and scripts.
|
|
51
51
|
|
|
@@ -59,6 +59,23 @@ To publish new source, a repository maintainer opens **Actions → Publish npm a
|
|
|
59
59
|
|
|
60
60
|
**Recovery:** If a run fails *after* pushing its version tag, do not launch a new release blindly: check whether the tag, npm version or GitHub Release already exists and reconcile the incomplete publish first. npm versions cannot be overwritten. Protected branches must explicitly permit the GitHub Actions bot to create the release commit/tag or use a maintainer-approved release branch process.
|
|
61
61
|
|
|
62
|
+
## Visual Pages editor / 可视化页面编辑器
|
|
63
|
+
|
|
64
|
+
Run `npm run editor` (or `npx edgepress editor` in an initialized site), then open **http://127.0.0.1:4178/**. The editor now supports **+ 新建页面**: choose a title, optional URL slug and configured language; the new JSON Page opens immediately in the visual canvas. Existing Pages can still be selected, arranged into 1–4 columns and edited without touching JSON.
|
|
65
|
+
|
|
66
|
+
从命令行也可以新建页面:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
edgepress new pages "About our project" --lang en --slug about
|
|
70
|
+
edgepress new pages "关于我们" --lang zh-cn --slug about
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The shortcut `edgepress new page` is also accepted. By default, the CLI creates `content/pages/<slug>/<locale>.json` in the site's default language. Existing pages, legacy `.md` equivalents, and symlinked directories cannot be overwritten. The generated `$schema` reference points to the installed framework (or the local development schema). Run `npm run editor` to continue editing, and `npm run build` to validate the actual generated site.
|
|
74
|
+
|
|
75
|
+
**Shared block catalog:** `src/page-block-catalog.json` ships with the npm package and defines starter templates for **all 30 supported Pages block types**. This includes site-reusable `link-directory`, `media-text`, `feature-grid`, `privacy-controller`, `document`, `media-viewer` and consent-controlled integrations used by other frontends. Reuse the public EdgePress catalog from site projects (including private ones); do not copy private pages or integrate site-specific services into the framework. Third-party service, CAPTCHA, ad and local-tool blocks are available as templates but **require site configuration and valid resource URLs** before a build; inserting the template does not activate a service.
|
|
76
|
+
|
|
77
|
+
The editor runs **only on 127.0.0.1**, never on deployed static sites. It enforces origin checks, path restrictions, revision-conflict detection and atomic saves. Unrecognized block properties are kept; complex nested fields can still be edited in the inspector's advanced JSON input. The canvas previews structure, not theme-perfect output. Articles remain Markdown.
|
|
78
|
+
|
|
62
79
|
## External link prompts
|
|
63
80
|
|
|
64
81
|
The optional local prompt shows the complete destination URL (including path, query and fragment) once, with no duplicate hostname, and lets the visitor return or continue. It makes no request to the destination before confirmation. Configure exact origins, not wildcard domains:
|
|
@@ -271,3 +288,5 @@ Real static website output demonstrates what the builder produces. Product recor
|
|
|
271
288
|
Project recordings use manual play/pause and a seekable progress bar, with theme colors and keyboard support. The reproducible CLI/editor workbench lives in [tools/recordings/demo-workbench.mjs](tools/recordings/demo-workbench.mjs); see [the recording guide](content/guides/product-demos.md). Built-in navigation and page icons come from the pinned Lucide 1.52 library, bundled locally with its license.
|
|
272
289
|
|
|
273
290
|
Development files: tests/ contains regression tests and fixtures; tools/assets/ maintains source assets; tools/recordings/ contains desktop capture workflows; tools/verification/ contains browser audits; tools/reports/ holds generated evidence. Run npm test and npm run check after changes.
|
|
291
|
+
|
|
292
|
+
Dependency maintenance uses compatible release ranges without retained lockfiles. The media and document viewers follow Git semver release ranges; audits resolve fresh dependency snapshots outside the checkout and remove them after use. Dependabot checks daily, including security updates; changed dependencies must pass the full browser suite before release.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edgepress",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "2026.10.
|
|
4
|
+
"version": "2026.10.14",
|
|
5
5
|
"description": "Static websites from Markdown and editable pages, with themes, consent-controlled embeds and readable article updates.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -63,11 +63,13 @@
|
|
|
63
63
|
"deploy:edgeone": "node src/cli.js deploy edgeone",
|
|
64
64
|
"deploy:esa": "node src/cli.js deploy esa",
|
|
65
65
|
"deploy:netlify": "node src/cli.js deploy netlify",
|
|
66
|
-
"fonts:sync": "node tools/assets/sync-fonts.mjs"
|
|
66
|
+
"fonts:sync": "node tools/assets/sync-fonts.mjs",
|
|
67
|
+
"editor": "node src/cli.js editor",
|
|
68
|
+
"audit": "node tools/maintenance/audit-dependencies.mjs low"
|
|
67
69
|
},
|
|
68
70
|
"dependencies": {
|
|
69
|
-
"@jsw-teams/document-viewer": "https://
|
|
70
|
-
"@jsw-teams/media-viewer": "https://
|
|
71
|
+
"@jsw-teams/document-viewer": "git+https://github.com/jsw-teams/document-viewer.git#semver:^2026.10.1",
|
|
72
|
+
"@jsw-teams/media-viewer": "git+https://github.com/jsw-teams/media-viewer.git#semver:^2026.10.1",
|
|
71
73
|
"esbuild": "^0.28.2",
|
|
72
74
|
"htmlparser2": "^12.0.0",
|
|
73
75
|
"image-size": "^2.0.4",
|
|
@@ -78,13 +80,14 @@
|
|
|
78
80
|
},
|
|
79
81
|
"overrides": {
|
|
80
82
|
"@file-viewer/doc": {
|
|
81
|
-
"dompurify": "3.4.17"
|
|
82
|
-
}
|
|
83
|
+
"dompurify": "^3.4.17"
|
|
84
|
+
},
|
|
85
|
+
"undici": "^7.30.1"
|
|
83
86
|
},
|
|
84
87
|
"devDependencies": {
|
|
85
|
-
"lucide-static": "1.55.0",
|
|
88
|
+
"lucide-static": "^1.55.0",
|
|
86
89
|
"playwright": "^1.63.0",
|
|
87
90
|
"vscode-json-languageservice": "^6.0.0-next.3",
|
|
88
|
-
"wrangler": "^4.
|
|
91
|
+
"wrangler": "^4.152.0"
|
|
89
92
|
}
|
|
90
93
|
}
|
package/src/cli.js
CHANGED
|
@@ -9,12 +9,14 @@ import { spawn } from 'node:child_process';
|
|
|
9
9
|
import { acquireBuildLock, buildSite } from './build.js';
|
|
10
10
|
import { loadConfig } from './config.js';
|
|
11
11
|
import { slugify } from './content.js';
|
|
12
|
+
import { createPage } from './page-scaffold.js';
|
|
12
13
|
import { checkPages } from './page-check.js';
|
|
13
14
|
import { checkCompatibility, writeIterationPlan } from './maintenance.js';
|
|
14
15
|
import { loadLanguagePacks, translate } from './i18n.js';
|
|
15
16
|
import { postTemplate } from './post-template.js';
|
|
16
17
|
import {deploySite} from './deploy.js';
|
|
17
18
|
import {formatPages} from '../tools/assets/format-pages.mjs';
|
|
19
|
+
import {startPageEditor} from './page-editor.js';
|
|
18
20
|
|
|
19
21
|
const siteGitignore = ['node_modules/', 'dist/', '.edgepress/', '.wrangler/', '.dev.vars', '.vercel/', '.netlify/', '.edgeone/', '.esa/', '.env', '.env.*', '!.env.example', '*.tgz', ''].join('\n');
|
|
20
22
|
const siteReadme = [
|
|
@@ -29,7 +31,7 @@ const siteReadme = [
|
|
|
29
31
|
'',
|
|
30
32
|
'Create an article with `npm run new -- post "My first article"`. Open the printed file path and write Markdown below the second `---` line. The command fills the title, date, and language. Run `npm run dev` to preview and `npm run build` before publishing.',
|
|
31
33
|
'',
|
|
32
|
-
'
|
|
34
|
+
'Run `npm run editor` to create and edit Pages visually at http://127.0.0.1:4178/. Or run `npx edgepress new pages "About us" --lang en` to create a JSON Page from the CLI. All Page blocks use shared framework templates; articles remain Markdown.',
|
|
33
35
|
'',
|
|
34
36
|
'## Deploy a static website',
|
|
35
37
|
'',
|
|
@@ -81,6 +83,7 @@ async function initializeProject() {
|
|
|
81
83
|
generate: 'edgepress generate',
|
|
82
84
|
build: 'edgepress build',
|
|
83
85
|
dev: 'edgepress server',
|
|
86
|
+
editor: 'edgepress editor',
|
|
84
87
|
preview: 'edgepress server',
|
|
85
88
|
check: 'edgepress check',
|
|
86
89
|
doctor: 'edgepress doctor',
|
|
@@ -248,6 +251,27 @@ async function manageTheme(args, config) {
|
|
|
248
251
|
console.log('Selected theme ' + selected.id + '.');
|
|
249
252
|
}
|
|
250
253
|
|
|
254
|
+
async function newPage(args, config) {
|
|
255
|
+
let lang, slug;
|
|
256
|
+
const words = [];
|
|
257
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
258
|
+
const arg = args[i];
|
|
259
|
+
if (arg === '--lang' || arg === '--slug') {
|
|
260
|
+
if (!args[i + 1] || args[i + 1].startsWith('--')) throw new Error('Missing value for ' + arg);
|
|
261
|
+
if (arg === '--lang') lang = args[++i];
|
|
262
|
+
else slug = args[++i];
|
|
263
|
+
} else if (arg.startsWith('--')) throw new Error('Unknown new pages option: ' + arg);
|
|
264
|
+
else words.push(arg);
|
|
265
|
+
}
|
|
266
|
+
const title = words.join(' ').trim();
|
|
267
|
+
if (!title) throw new Error('Usage: edgepress new pages "Page title" [--lang en] [--slug page-slug]');
|
|
268
|
+
const page = await createPage(config.root, {
|
|
269
|
+
title, lang, slug, locales: config.i18n.locales, defaultLocale: config.i18n.defaultLocale
|
|
270
|
+
});
|
|
271
|
+
console.log('Created Page: ' + relative(config.root, page.file));
|
|
272
|
+
console.log('Open the local editor with: npm run editor');
|
|
273
|
+
}
|
|
274
|
+
|
|
251
275
|
async function createPost(title, config) {
|
|
252
276
|
if (!title) throw new Error('Usage: edgepress new post "Post title"');
|
|
253
277
|
const releaseLock = await acquireBuildLock(config.resolvedPaths.cache);
|
|
@@ -331,11 +355,19 @@ try {
|
|
|
331
355
|
? await loadConfig()
|
|
332
356
|
: null;
|
|
333
357
|
if (command === '--help' || command === '-h' || command === 'help') {
|
|
334
|
-
console.log('EdgePress commands: init, new, build, generate, server, check, doctor, iterate, theme, security, deploy, clean');
|
|
358
|
+
console.log('EdgePress commands: init, new, build, generate, server, editor, check, doctor, iterate, theme, security, deploy, clean');
|
|
359
|
+
console.log('Create a Page: edgepress new pages "Page title" [--lang en] [--slug page-slug]');
|
|
335
360
|
}
|
|
336
361
|
else if (command === 'build' || command === 'generate') await buildSite();
|
|
337
362
|
else if (command === 'init') await initializeProject();
|
|
338
363
|
else if (command === 'preview' || command === 'dev' || command === 'server') await import('./preview.js');
|
|
364
|
+
else if (command === 'editor') {
|
|
365
|
+
const portText = args[0] === '--port' ? args[1] : args[0]?.startsWith('--port=') ? args[0].slice(7) : args.length ? null : '4178';
|
|
366
|
+
if (!/^\d{1,5}$/.test(portText || '') || Number(portText) < 1 || Number(portText) > 65535) throw new Error('Usage: edgepress editor [--port 4178]');
|
|
367
|
+
const editorConfig = await loadConfig();
|
|
368
|
+
const editor = await startPageEditor({ port: Number(portText), root: editorConfig.root, locales: editorConfig.i18n.locales, defaultLocale: editorConfig.i18n.defaultLocale });
|
|
369
|
+
console.log('Local Pages editor: ' + editor.url + ' (Ctrl+C to stop)');
|
|
370
|
+
}
|
|
339
371
|
else if (command === 'deploy') {
|
|
340
372
|
const platform = args[0] && !args[0].startsWith('-') ? args.shift() : 'cloudflare';
|
|
341
373
|
const built = process.env.WORKERS_CI === '1' ? {output:(await loadConfig()).resolvedPaths.output} : await buildSite();
|
|
@@ -343,7 +375,10 @@ try {
|
|
|
343
375
|
}
|
|
344
376
|
else if (command === 'theme') await manageTheme(args, await loadConfig());
|
|
345
377
|
else if (command === 'security') await runSecurityAudit();
|
|
346
|
-
else if (command === 'new')
|
|
378
|
+
else if (command === 'new') {
|
|
379
|
+
if (args[0] === 'pages' || args[0] === 'page') await newPage(args.slice(1), config);
|
|
380
|
+
else await createPost((args[0] === 'post' ? args.slice(1) : args).join(' ').trim(), config);
|
|
381
|
+
}
|
|
347
382
|
else if (command === 'clean') await clean(config);
|
|
348
383
|
else if (command === 'check') {
|
|
349
384
|
await buildSite(config.root);
|
|
@@ -362,7 +397,7 @@ try {
|
|
|
362
397
|
const compatibilityReport = await checkCompatibility(config);
|
|
363
398
|
const plan = await writeIterationPlan(config, pageReport, compatibilityReport);
|
|
364
399
|
await showReport('Safe iteration plan', plan, resolve(config.resolvedPaths.cache, 'reports/iteration-plan.md'));
|
|
365
|
-
} else throw new Error('Commands: init, build|generate, server, deploy, new, clean, check, doctor, iterate, theme list|create|install|use, security');
|
|
400
|
+
} else throw new Error('Commands: init, build|generate, server, editor [--port 4178], deploy, new, clean, check, doctor, iterate, theme list|create|install|use, security');
|
|
366
401
|
} catch (error) {
|
|
367
402
|
console.error(error?.stack || error);
|
|
368
403
|
process.exitCode = 1;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Shared, public EdgePress page-block presets. Templates are examples, not configuration-specific integrations.",
|
|
4
|
+
"blocks": {
|
|
5
|
+
"hero": {
|
|
6
|
+
"label": "横幅 Hero",
|
|
7
|
+
"category": "layout",
|
|
8
|
+
"template": {
|
|
9
|
+
"type": "hero",
|
|
10
|
+
"title": "页面横幅",
|
|
11
|
+
"text": "介绍页面内容"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"section": {
|
|
15
|
+
"label": "分区 Section",
|
|
16
|
+
"category": "layout",
|
|
17
|
+
"template": {
|
|
18
|
+
"type": "section",
|
|
19
|
+
"title": "新分区",
|
|
20
|
+
"blocks": [
|
|
21
|
+
{
|
|
22
|
+
"type": "text",
|
|
23
|
+
"text": "分区内容"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"heading": {
|
|
29
|
+
"label": "标题 Heading",
|
|
30
|
+
"category": "text",
|
|
31
|
+
"template": {
|
|
32
|
+
"type": "heading",
|
|
33
|
+
"level": 2,
|
|
34
|
+
"text": "新的标题"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"text": {
|
|
38
|
+
"label": "文字 Text",
|
|
39
|
+
"category": "text",
|
|
40
|
+
"template": {
|
|
41
|
+
"type": "text",
|
|
42
|
+
"text": "在此编辑文字"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"media-text": {
|
|
46
|
+
"label": "图文 Media + Text",
|
|
47
|
+
"category": "media",
|
|
48
|
+
"template": {
|
|
49
|
+
"type": "media-text",
|
|
50
|
+
"mediaType": "image",
|
|
51
|
+
"src": "/images/example.png",
|
|
52
|
+
"alt": "图片说明",
|
|
53
|
+
"title": "图文标题",
|
|
54
|
+
"text": "图文描述",
|
|
55
|
+
"placement": "left"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"display-text": {
|
|
59
|
+
"label": "展示文字 Display Text",
|
|
60
|
+
"category": "text",
|
|
61
|
+
"template": {
|
|
62
|
+
"type": "display-text",
|
|
63
|
+
"level": 2,
|
|
64
|
+
"style": "editorial",
|
|
65
|
+
"text": "强调文字"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"link-list": {
|
|
69
|
+
"label": "链接列表 Link List",
|
|
70
|
+
"category": "links",
|
|
71
|
+
"template": {
|
|
72
|
+
"type": "link-list",
|
|
73
|
+
"title": "链接列表",
|
|
74
|
+
"items": [
|
|
75
|
+
{
|
|
76
|
+
"label": "链接",
|
|
77
|
+
"url": "/"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"steps": {
|
|
83
|
+
"label": "步骤 Steps",
|
|
84
|
+
"category": "lists",
|
|
85
|
+
"template": {
|
|
86
|
+
"type": "steps",
|
|
87
|
+
"title": "操作步骤",
|
|
88
|
+
"items": [
|
|
89
|
+
{
|
|
90
|
+
"title": "第一步",
|
|
91
|
+
"text": "操作说明"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"code": {
|
|
97
|
+
"label": "代码 Code",
|
|
98
|
+
"category": "text",
|
|
99
|
+
"template": {
|
|
100
|
+
"type": "code",
|
|
101
|
+
"language": "text",
|
|
102
|
+
"code": "示例代码"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"data-table": {
|
|
106
|
+
"label": "数据表 Data Table",
|
|
107
|
+
"category": "lists",
|
|
108
|
+
"template": {
|
|
109
|
+
"type": "data-table",
|
|
110
|
+
"title": "表格标题",
|
|
111
|
+
"headers": [
|
|
112
|
+
"字段",
|
|
113
|
+
"内容"
|
|
114
|
+
],
|
|
115
|
+
"rows": [
|
|
116
|
+
[
|
|
117
|
+
"示例",
|
|
118
|
+
"填写内容"
|
|
119
|
+
]
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"list": {
|
|
124
|
+
"label": "列表 List",
|
|
125
|
+
"category": "lists",
|
|
126
|
+
"template": {
|
|
127
|
+
"type": "list",
|
|
128
|
+
"title": "列表标题",
|
|
129
|
+
"items": [
|
|
130
|
+
"项目一",
|
|
131
|
+
"项目二"
|
|
132
|
+
],
|
|
133
|
+
"ordered": false
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"notice": {
|
|
137
|
+
"label": "提示 Notice",
|
|
138
|
+
"category": "text",
|
|
139
|
+
"template": {
|
|
140
|
+
"type": "notice",
|
|
141
|
+
"title": "提示",
|
|
142
|
+
"text": "提示信息",
|
|
143
|
+
"tone": "info"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"privacy-services": {
|
|
147
|
+
"label": "隐私服务清单",
|
|
148
|
+
"category": "privacy",
|
|
149
|
+
"template": {
|
|
150
|
+
"type": "privacy-services",
|
|
151
|
+
"emptyText": "暂无已配置的服务"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"privacy-consent": {
|
|
155
|
+
"label": "隐私同意信息",
|
|
156
|
+
"category": "privacy",
|
|
157
|
+
"template": {
|
|
158
|
+
"type": "privacy-consent",
|
|
159
|
+
"storageLabel": "存储位置",
|
|
160
|
+
"expiryLabel": "保留期限",
|
|
161
|
+
"proposedDateLabel": "建议日期",
|
|
162
|
+
"effectiveDateLabel": "生效日期",
|
|
163
|
+
"expiryText": "{days} 天"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"privacy-controller": {
|
|
167
|
+
"label": "隐私管理者信息",
|
|
168
|
+
"category": "privacy",
|
|
169
|
+
"template": {
|
|
170
|
+
"type": "privacy-controller",
|
|
171
|
+
"missingTitle": "管理者信息未配置",
|
|
172
|
+
"missingText": "请在站点配置中填写管理者信息",
|
|
173
|
+
"nameLabel": "管理者",
|
|
174
|
+
"contactLabel": "联系方式"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"link-directory": {
|
|
178
|
+
"label": "链接目录 Link Directory",
|
|
179
|
+
"category": "links",
|
|
180
|
+
"template": {
|
|
181
|
+
"type": "link-directory",
|
|
182
|
+
"title": "站点目录",
|
|
183
|
+
"items": [
|
|
184
|
+
{
|
|
185
|
+
"title": "参考网站",
|
|
186
|
+
"text": "站点简介",
|
|
187
|
+
"url": "https://example.com"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"feature-grid": {
|
|
193
|
+
"label": "功能卡片 Feature Grid",
|
|
194
|
+
"category": "layout",
|
|
195
|
+
"template": {
|
|
196
|
+
"type": "feature-grid",
|
|
197
|
+
"title": "功能特点",
|
|
198
|
+
"items": [
|
|
199
|
+
{
|
|
200
|
+
"title": "功能名称",
|
|
201
|
+
"text": "功能说明"
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"image": {
|
|
207
|
+
"label": "图片 Image",
|
|
208
|
+
"category": "media",
|
|
209
|
+
"template": {
|
|
210
|
+
"type": "image",
|
|
211
|
+
"src": "/images/example.png",
|
|
212
|
+
"alt": "替换为图片文字描述"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"quote": {
|
|
216
|
+
"label": "引用 Quote",
|
|
217
|
+
"category": "text",
|
|
218
|
+
"template": {
|
|
219
|
+
"type": "quote",
|
|
220
|
+
"text": "引用内容",
|
|
221
|
+
"attribution": "来源"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
"cta": {
|
|
225
|
+
"label": "行动按钮 CTA",
|
|
226
|
+
"category": "links",
|
|
227
|
+
"template": {
|
|
228
|
+
"type": "cta",
|
|
229
|
+
"title": "开始使用",
|
|
230
|
+
"text": "行动说明",
|
|
231
|
+
"label": "查看详情",
|
|
232
|
+
"url": "/"
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"faq": {
|
|
236
|
+
"label": "常见问题 FAQ",
|
|
237
|
+
"category": "lists",
|
|
238
|
+
"template": {
|
|
239
|
+
"type": "faq",
|
|
240
|
+
"title": "常见问题",
|
|
241
|
+
"items": [
|
|
242
|
+
{
|
|
243
|
+
"question": "这里写问题",
|
|
244
|
+
"answer": "这里写回答"
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
"oembed": {
|
|
250
|
+
"label": "外部嵌入 oEmbed",
|
|
251
|
+
"category": "integrations",
|
|
252
|
+
"requiresSetup": true,
|
|
253
|
+
"template": {
|
|
254
|
+
"type": "oembed",
|
|
255
|
+
"integration": "configure-service-id",
|
|
256
|
+
"url": "https://example.com/",
|
|
257
|
+
"title": "第三方嵌入"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"service": {
|
|
261
|
+
"label": "第三方服务 Service",
|
|
262
|
+
"category": "integrations",
|
|
263
|
+
"requiresSetup": true,
|
|
264
|
+
"template": {
|
|
265
|
+
"type": "service",
|
|
266
|
+
"integration": "configure-service-id"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"post-list": {
|
|
270
|
+
"label": "文章列表 Post List",
|
|
271
|
+
"category": "content",
|
|
272
|
+
"template": {
|
|
273
|
+
"type": "post-list",
|
|
274
|
+
"title": "文章列表",
|
|
275
|
+
"count": 3
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
"latest-posts": {
|
|
279
|
+
"label": "最新文章 Latest Posts",
|
|
280
|
+
"category": "content",
|
|
281
|
+
"template": {
|
|
282
|
+
"type": "latest-posts",
|
|
283
|
+
"title": "最新文章",
|
|
284
|
+
"count": 3,
|
|
285
|
+
"paginate": false
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
"ad-slot": {
|
|
289
|
+
"label": "广告位置 Ad Slot",
|
|
290
|
+
"category": "integrations",
|
|
291
|
+
"requiresSetup": true,
|
|
292
|
+
"template": {
|
|
293
|
+
"type": "ad-slot",
|
|
294
|
+
"integration": "configure-service-id",
|
|
295
|
+
"label": "广告"
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
"captcha": {
|
|
299
|
+
"label": "验证码 CAPTCHA",
|
|
300
|
+
"category": "integrations",
|
|
301
|
+
"requiresSetup": true,
|
|
302
|
+
"template": {
|
|
303
|
+
"type": "captcha",
|
|
304
|
+
"provider": "cloudflare-turnstile",
|
|
305
|
+
"label": "人机验证"
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"document": {
|
|
309
|
+
"label": "文档预览 Document",
|
|
310
|
+
"category": "media",
|
|
311
|
+
"template": {
|
|
312
|
+
"type": "document",
|
|
313
|
+
"title": "文档预览",
|
|
314
|
+
"src": "/documents/sample.pdf"
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"media-viewer": {
|
|
318
|
+
"label": "媒体浏览器 Media Viewer",
|
|
319
|
+
"category": "media",
|
|
320
|
+
"template": {
|
|
321
|
+
"type": "media-viewer",
|
|
322
|
+
"title": "图片集",
|
|
323
|
+
"items": [
|
|
324
|
+
{
|
|
325
|
+
"type": "image",
|
|
326
|
+
"src": "/images/example.png",
|
|
327
|
+
"alt": "图片说明"
|
|
328
|
+
}
|
|
329
|
+
]
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
"local-tool": {
|
|
333
|
+
"label": "本地工具 Local Tool",
|
|
334
|
+
"category": "integrations",
|
|
335
|
+
"requiresSetup": true,
|
|
336
|
+
"template": {
|
|
337
|
+
"type": "local-tool",
|
|
338
|
+
"id": "my-local-tool",
|
|
339
|
+
"title": "本地工具",
|
|
340
|
+
"script": "/assets/tool.js",
|
|
341
|
+
"fallback": "JavaScript 未启用时的提示文字"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|