generator-white-label 5.0.1 → 8.0.0
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/.editorconfig +15 -0
- package/.yarnrc.yml +6 -0
- package/CLI.md +82 -0
- package/LICENSE +9 -0
- package/PACKAGE_MANAGERS.md +35 -0
- package/README.md +204 -124
- package/app/404.tsx +28 -0
- package/app/README.md +66 -8
- package/app/assets/data/view/global.json +7 -47
- package/app/assets/data/view/index.json +9 -1
- package/app/assets/script/index.tsx +13 -0
- package/app/assets/script/tasks/TaskApplication.ts +77 -0
- package/app/assets/script/tasks/TaskMediator.ts +20 -0
- package/app/assets/script/tasks/TaskModel.ts +32 -0
- package/app/assets/script/tasks/TaskRouter.ts +30 -0
- package/app/assets/script/tasks/TaskView.tsx +24 -0
- package/app/assets/style/global.css +111 -0
- package/app/assets/style/print.css +8 -0
- package/app/assets/view/CodeBlock.tsx +17 -0
- package/app/assets/view/examples/tasks/TaskExample.tsx +63 -0
- package/app/assets/view/examples/tasks/task-state.ts +46 -0
- package/app/assets/view/layout/SiteFooter.tsx +11 -0
- package/app/assets/view/layout/SiteHeader.tsx +23 -0
- package/app/assets/view/page-data.ts +14 -0
- package/app/assets/view/sections/GettingStartedSection.tsx +27 -0
- package/app/assets/view/sections/HeroSection.tsx +21 -0
- package/app/assets/view/sections/LiveExampleSection.tsx +29 -0
- package/app/assets/view/sections/PackageDocsSection.tsx +69 -0
- package/app/assets/view/sections/SourceGuideSection.tsx +28 -0
- package/app/index.tsx +54 -0
- package/cli/index.ts +117 -0
- package/dist/app/404.d.ts +1 -0
- package/dist/app/404.js +6 -0
- package/dist/app/404.js.map +1 -0
- package/dist/app/assets/script/index.d.ts +8 -2
- package/dist/app/assets/script/index.js +11 -1
- package/dist/app/assets/script/index.js.map +1 -1
- package/dist/app/assets/script/tasks/TaskApplication.d.ts +20 -0
- package/dist/app/assets/script/tasks/TaskApplication.js +63 -0
- package/dist/app/assets/script/tasks/TaskApplication.js.map +1 -0
- package/dist/app/assets/script/tasks/TaskMediator.d.ts +15 -0
- package/dist/app/assets/script/tasks/TaskMediator.js +5 -0
- package/dist/app/assets/script/tasks/TaskMediator.js.map +1 -0
- package/dist/app/assets/script/tasks/TaskModel.d.ts +13 -0
- package/dist/app/assets/script/tasks/TaskModel.js +33 -0
- package/dist/app/assets/script/tasks/TaskModel.js.map +1 -0
- package/dist/app/assets/script/tasks/TaskRouter.d.ts +12 -0
- package/dist/app/assets/script/tasks/TaskRouter.js +28 -0
- package/dist/app/assets/script/tasks/TaskRouter.js.map +1 -0
- package/dist/app/assets/script/tasks/TaskView.d.ts +9 -0
- package/dist/app/assets/script/tasks/TaskView.js +24 -0
- package/dist/app/assets/script/tasks/TaskView.js.map +1 -0
- package/dist/app/assets/view/CodeBlock.d.ts +11 -0
- package/dist/app/assets/view/CodeBlock.js +12 -0
- package/dist/app/assets/view/CodeBlock.js.map +1 -0
- package/dist/app/assets/view/examples/tasks/TaskExample.d.ts +11 -0
- package/dist/app/assets/view/examples/tasks/TaskExample.js +16 -0
- package/dist/app/assets/view/examples/tasks/TaskExample.js.map +1 -0
- package/dist/app/assets/view/examples/tasks/task-state.d.ts +22 -0
- package/dist/app/assets/view/examples/tasks/task-state.js +30 -0
- package/dist/app/assets/view/examples/tasks/task-state.js.map +1 -0
- package/dist/app/assets/view/layout/SiteFooter.d.ts +2 -0
- package/dist/app/assets/view/layout/SiteFooter.js +6 -0
- package/dist/app/assets/view/layout/SiteFooter.js.map +1 -0
- package/dist/app/assets/view/layout/SiteHeader.d.ts +8 -0
- package/dist/app/assets/view/layout/SiteHeader.js +12 -0
- package/dist/app/assets/view/layout/SiteHeader.js.map +1 -0
- package/dist/app/assets/view/page-data.d.ts +16 -0
- package/dist/app/assets/view/page-data.js +2 -0
- package/dist/app/assets/view/page-data.js.map +1 -0
- package/dist/app/assets/view/sections/GettingStartedSection.d.ts +2 -0
- package/dist/app/assets/view/sections/GettingStartedSection.js +11 -0
- package/dist/app/assets/view/sections/GettingStartedSection.js.map +1 -0
- package/dist/app/assets/view/sections/HeroSection.d.ts +8 -0
- package/dist/app/assets/view/sections/HeroSection.js +12 -0
- package/dist/app/assets/view/sections/HeroSection.js.map +1 -0
- package/dist/app/assets/view/sections/LiveExampleSection.d.ts +6 -0
- package/dist/app/assets/view/sections/LiveExampleSection.js +13 -0
- package/dist/app/assets/view/sections/LiveExampleSection.js.map +1 -0
- package/dist/app/assets/view/sections/PackageDocsSection.d.ts +2 -0
- package/dist/app/assets/view/sections/PackageDocsSection.js +31 -0
- package/dist/app/assets/view/sections/PackageDocsSection.js.map +1 -0
- package/dist/app/assets/view/sections/SourceGuideSection.d.ts +7 -0
- package/dist/app/assets/view/sections/SourceGuideSection.js +11 -0
- package/dist/app/assets/view/sections/SourceGuideSection.js.map +1 -0
- package/dist/app/index.d.ts +8 -0
- package/dist/app/index.js +22 -0
- package/dist/app/index.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.js +97 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/scaffold/index.d.ts +64 -0
- package/dist/scaffold/index.js +109 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scripts/build.d.ts +5 -13
- package/dist/scripts/build.js +48 -79
- package/dist/scripts/build.js.map +1 -1
- package/package.json +77 -40
- package/pnpm-workspace.yaml +4 -0
- package/scaffold/index.ts +127 -0
- package/scaffold/no-jsx/README.md +47 -0
- package/scaffold/no-jsx/app/404.ts +10 -0
- package/scaffold/no-jsx/app/assets/script/index.ts +7 -0
- package/scaffold/no-jsx/app/assets/script/tasks/TaskView.ts +19 -0
- package/scaffold/no-jsx/app/assets/view/examples/tasks/TaskExample.ts +39 -0
- package/scaffold/no-jsx/app/index.ts +58 -0
- package/scripts/build.ts +55 -86
- package/server/handler.ts +75 -0
- package/template-test/site.test.js +233 -0
- package/tsconfig.site.json +6 -5
- package/tsconfig.site.no-jsx.json +24 -0
- package/app/404.hbs +0 -20
- package/app/assets/data/coutries.json +0 -992
- package/app/assets/data/states.json +0 -204
- package/app/assets/data/view/toolkit/colors.json +0 -17
- package/app/assets/data/view/toolkit/components.json +0 -39
- package/app/assets/data/view/toolkit/elements.json +0 -119
- package/app/assets/data/view/toolkit/grids.json +0 -17
- package/app/assets/data/view/toolkit/icons.json +0 -17
- package/app/assets/data/view/toolkit/index.json +0 -17
- package/app/assets/data/view/toolkit/type.json +0 -17
- package/app/assets/font/opensans/LICENSE.txt +0 -202
- package/app/assets/font/opensans/opensans-bold-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-bolditalic-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-extrabold-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-extrabolditalic-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-italic-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-light-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-lightitalic-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-regular-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-semibold-webfont.woff2 +0 -0
- package/app/assets/font/opensans/opensans-semibolditalic-webfont.woff2 +0 -0
- package/app/assets/font/opensans/stylesheet.css +0 -120
- package/app/assets/image/apple-touch-icon.png +0 -0
- package/app/assets/image/demo/fallback.avif +0 -0
- package/app/assets/image/demo/fallback.jpg +0 -0
- package/app/assets/image/demo/fallback.webp +0 -0
- package/app/assets/image/demo/large.avif +0 -0
- package/app/assets/image/demo/large.webp +0 -0
- package/app/assets/image/demo/small.avif +0 -0
- package/app/assets/image/demo/small.webp +0 -0
- package/app/assets/image/favicon.png +0 -0
- package/app/assets/image/graphic-css3.svg +0 -30
- package/app/assets/image/graphic-html5.svg +0 -29
- package/app/assets/markup/element/a.hbs +0 -29
- package/app/assets/markup/element/button.hbs +0 -30
- package/app/assets/markup/element/div.hbs +0 -11
- package/app/assets/markup/element/head.hbs +0 -78
- package/app/assets/markup/element/iframe.hbs +0 -20
- package/app/assets/markup/element/img.hbs +0 -30
- package/app/assets/markup/element/input.hbs +0 -43
- package/app/assets/markup/element/label.hbs +0 -14
- package/app/assets/markup/element/legend.hbs +0 -5
- package/app/assets/markup/element/meta.hbs +0 -11
- package/app/assets/markup/element/nav.hbs +0 -13
- package/app/assets/markup/element/p.hbs +0 -8
- package/app/assets/markup/element/picture.hbs +0 -58
- package/app/assets/markup/element/script.hbs +0 -3
- package/app/assets/markup/element/select.hbs +0 -35
- package/app/assets/markup/element/span.hbs +0 -8
- package/app/assets/markup/element/svg.hbs +0 -11
- package/app/assets/markup/element/table.hbs +0 -50
- package/app/assets/markup/element/textarea.hbs +0 -24
- package/app/assets/markup/element/ul.hbs +0 -13
- package/app/assets/markup/modal/modal-example-1.handlebars +0 -8
- package/app/assets/markup/toolkit/accessibility-skip-to-element-1.handlebars +0 -1
- package/app/assets/markup/toolkit/accessibility-speaker-1.handlebars +0 -1
- package/app/assets/markup/toolkit/anchor-1.handlebars +0 -1
- package/app/assets/markup/toolkit/button-1.handlebars +0 -1
- package/app/assets/markup/toolkit/footer-1.handlebars +0 -3
- package/app/assets/markup/toolkit/header-1.handlebars +0 -1
- package/app/assets/markup/toolkit/heading-1.handlebars +0 -1
- package/app/assets/markup/toolkit/heading-2.handlebars +0 -1
- package/app/assets/markup/toolkit/heading-3.handlebars +0 -1
- package/app/assets/markup/toolkit/heading-4.handlebars +0 -1
- package/app/assets/markup/toolkit/image-1.handlebars +0 -1
- package/app/assets/markup/toolkit/input-checkbox-1.handlebars +0 -1
- package/app/assets/markup/toolkit/input-error-1.handlebars +0 -8
- package/app/assets/markup/toolkit/input-radio-1.handlebars +0 -1
- package/app/assets/markup/toolkit/input-text-1.handlebars +0 -1
- package/app/assets/markup/toolkit/label-1.handlebars +0 -1
- package/app/assets/markup/toolkit/legend-1.handlebars +0 -1
- package/app/assets/markup/toolkit/list-1.handlebars +0 -1
- package/app/assets/markup/toolkit/modal-1.handlebars +0 -4
- package/app/assets/markup/toolkit/nav-1.handlebars +0 -1
- package/app/assets/markup/toolkit/picture-1.handlebars +0 -1
- package/app/assets/markup/toolkit/select-1.handlebars +0 -1
- package/app/assets/markup/toolkit/table-1.handlebars +0 -1
- package/app/assets/markup/toolkit/text-1.handlebars +0 -1
- package/app/assets/markup/toolkit/textarea-1.handlebars +0 -1
- package/app/assets/markup/toolkit/youtube-player-1.handlebars +0 -1
- package/app/assets/script/api/facebook.ts +0 -41
- package/app/assets/script/api/youtube.ts +0 -22
- package/app/assets/script/index.ts +0 -2
- package/app/assets/script/mediator/global.ts +0 -4
- package/app/assets/script/model/singletons/countries.ts +0 -5
- package/app/assets/script/model/singletons/global.ts +0 -5
- package/app/assets/script/model/singletons/states.ts +0 -5
- package/app/assets/script/model/user.ts +0 -4
- package/app/assets/script/toolkit.ts +0 -11
- package/app/assets/script/types.d.ts +0 -6
- package/app/assets/script/utility/ajax.ts +0 -15
- package/app/assets/script/utility/form.ts +0 -119
- package/app/assets/script/utility/regex.ts +0 -26
- package/app/assets/script/utility/share.ts +0 -77
- package/app/assets/script/utility/string.ts +0 -148
- package/app/assets/script/view/default.tsx +0 -14
- package/app/assets/script/view/toolkit/youtube-player-1.ts +0 -33
- package/app/assets/style/base/_toolkit.scss +0 -39
- package/app/assets/style/base/colors/_colors.scss +0 -18
- package/app/assets/style/base/components/_modal-1.scss +0 -80
- package/app/assets/style/base/components/_sticky-1.scss +0 -19
- package/app/assets/style/base/components/_tabpanel-1.scss +0 -115
- package/app/assets/style/base/components/_tabpanel-2.scss +0 -64
- package/app/assets/style/base/components/_tabpanel-base-1.scss +0 -13
- package/app/assets/style/base/components/_youtube-player-1.scss +0 -16
- package/app/assets/style/base/elements/_anchors.scss +0 -27
- package/app/assets/style/base/elements/_buttons.scss +0 -25
- package/app/assets/style/base/elements/_fieldsets.scss +0 -9
- package/app/assets/style/base/elements/_images.scss +0 -8
- package/app/assets/style/base/elements/_inputs.scss +0 -78
- package/app/assets/style/base/elements/_labels.scss +0 -16
- package/app/assets/style/base/elements/_landmarks.scss +0 -3
- package/app/assets/style/base/elements/_legends.scss +0 -11
- package/app/assets/style/base/elements/_lists.scss +0 -15
- package/app/assets/style/base/elements/_pictures.scss +0 -4
- package/app/assets/style/base/elements/_tables.scss +0 -39
- package/app/assets/style/base/layouts/_staggered-1.scss +0 -29
- package/app/assets/style/base/type/_fonts.scss +0 -125
- package/app/assets/style/base/type/_headings.scss +0 -36
- package/app/assets/style/base/type/_text.scss +0 -9
- package/app/assets/style/base/utilities/_accessibility.scss +0 -55
- package/app/assets/style/base/utilities/_functions.scss +0 -98
- package/app/assets/style/base/utilities/_scroll.scss +0 -11
- package/app/assets/style/base/utilities/_type.scss +0 -13
- package/app/assets/style/global.scss +0 -123
- package/app/assets/style/print.scss +0 -6
- package/app/assets/style/toolkit.scss +0 -387
- package/app/index.hbs +0 -21
- package/app/robots.txt +0 -1
- package/app/toolkit/colors.hbs +0 -102
- package/app/toolkit/components.hbs +0 -261
- package/app/toolkit/elements.hbs +0 -497
- package/app/toolkit/grids.hbs +0 -413
- package/app/toolkit/icons.hbs +0 -87
- package/app/toolkit/index.hbs +0 -144
- package/app/toolkit/type.hbs +0 -120
- package/dist/app/assets/data/coutries.json +0 -992
- package/dist/app/assets/data/states.json +0 -204
- package/dist/app/assets/script/api/facebook.d.ts +0 -8
- package/dist/app/assets/script/api/facebook.js +0 -42
- package/dist/app/assets/script/api/facebook.js.map +0 -1
- package/dist/app/assets/script/api/youtube.d.ts +0 -8
- package/dist/app/assets/script/api/youtube.js +0 -22
- package/dist/app/assets/script/api/youtube.js.map +0 -1
- package/dist/app/assets/script/mediator/global.d.ts +0 -4
- package/dist/app/assets/script/mediator/global.js +0 -4
- package/dist/app/assets/script/mediator/global.js.map +0 -1
- package/dist/app/assets/script/model/singletons/countries.d.ts +0 -4
- package/dist/app/assets/script/model/singletons/countries.js +0 -5
- package/dist/app/assets/script/model/singletons/countries.js.map +0 -1
- package/dist/app/assets/script/model/singletons/global.d.ts +0 -4
- package/dist/app/assets/script/model/singletons/global.js +0 -5
- package/dist/app/assets/script/model/singletons/global.js.map +0 -1
- package/dist/app/assets/script/model/singletons/states.d.ts +0 -4
- package/dist/app/assets/script/model/singletons/states.js +0 -5
- package/dist/app/assets/script/model/singletons/states.js.map +0 -1
- package/dist/app/assets/script/model/user.d.ts +0 -4
- package/dist/app/assets/script/model/user.js +0 -6
- package/dist/app/assets/script/model/user.js.map +0 -1
- package/dist/app/assets/script/toolkit.d.ts +0 -1
- package/dist/app/assets/script/toolkit.js +0 -7
- package/dist/app/assets/script/toolkit.js.map +0 -1
- package/dist/app/assets/script/utility/ajax.d.ts +0 -8
- package/dist/app/assets/script/utility/ajax.js +0 -17
- package/dist/app/assets/script/utility/ajax.js.map +0 -1
- package/dist/app/assets/script/utility/form.d.ts +0 -64
- package/dist/app/assets/script/utility/form.js +0 -111
- package/dist/app/assets/script/utility/form.js.map +0 -1
- package/dist/app/assets/script/utility/regex.d.ts +0 -14
- package/dist/app/assets/script/utility/regex.js +0 -27
- package/dist/app/assets/script/utility/regex.js.map +0 -1
- package/dist/app/assets/script/utility/share.d.ts +0 -68
- package/dist/app/assets/script/utility/share.js +0 -81
- package/dist/app/assets/script/utility/share.js.map +0 -1
- package/dist/app/assets/script/utility/string.d.ts +0 -64
- package/dist/app/assets/script/utility/string.js +0 -135
- package/dist/app/assets/script/utility/string.js.map +0 -1
- package/dist/app/assets/script/view/default.d.ts +0 -11
- package/dist/app/assets/script/view/default.js +0 -15
- package/dist/app/assets/script/view/default.js.map +0 -1
- package/dist/app/assets/script/view/toolkit/youtube-player-1.d.ts +0 -23
- package/dist/app/assets/script/view/toolkit/youtube-player-1.js +0 -34
- package/dist/app/assets/script/view/toolkit/youtube-player-1.js.map +0 -1
- package/dist/generators/app/index.d.ts +0 -18
- package/dist/generators/app/index.js +0 -59
- package/dist/generators/app/index.js.map +0 -1
- package/generators/app/index.js +0 -2
- package/generators/app/index.ts +0 -61
package/package.json
CHANGED
|
@@ -1,37 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "generator-white-label",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Framework-independent TypeScript project generator for accessible, SEO-friendly sites with progressive enhancement, optional JSX, and a provider-neutral serverless handler example.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "dist/
|
|
6
|
+
"main": "dist/scaffold/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"generator-white-label": "dist/cli/index.js",
|
|
9
|
+
"white-label": "dist/cli/index.js"
|
|
10
|
+
},
|
|
7
11
|
"engines": {
|
|
8
|
-
"node": "^22.18.0 || >=24.11.0"
|
|
9
|
-
"npm": ">=10.0"
|
|
12
|
+
"node": "^22.18.0 || >=24.11.0"
|
|
10
13
|
},
|
|
11
14
|
"scripts": {
|
|
12
15
|
"build": "tsc -p tsconfig.json && node dist/scripts/build.js",
|
|
13
|
-
"test": "
|
|
16
|
+
"test": "node --run compile && node --run test:types && node --run test:unit",
|
|
14
17
|
"audit": "npm audit --audit-level=low",
|
|
15
18
|
"compile": "tsc -p tsconfig.json",
|
|
16
19
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
17
20
|
"test:unit": "node --test test/*.test.js",
|
|
18
|
-
"coverage": "
|
|
19
|
-
"prepack": "
|
|
20
|
-
"test:types": "tsc -p tsconfig.consumer.json"
|
|
21
|
+
"coverage": "node --run compile && node --run test:types && c8 node --run test:unit",
|
|
22
|
+
"prepack": "node --run compile",
|
|
23
|
+
"test:types": "tsc -p tsconfig.consumer.json",
|
|
24
|
+
"lint": "eslint \"cli/**/*.ts\" \"scripts/**/*.ts\" \"scaffold/**/*.ts\" \"server/**/*.ts\" \"app/**/*.{ts,tsx}\" --max-warnings=0",
|
|
25
|
+
"lint:fix": "node --run lint -- --fix"
|
|
21
26
|
},
|
|
22
27
|
"files": [
|
|
28
|
+
".editorconfig",
|
|
29
|
+
".yarnrc.yml",
|
|
30
|
+
"pnpm-workspace.yaml",
|
|
23
31
|
"app",
|
|
24
|
-
"
|
|
32
|
+
"cli",
|
|
33
|
+
"scaffold",
|
|
34
|
+
"server",
|
|
25
35
|
"scripts",
|
|
36
|
+
"template-test",
|
|
26
37
|
"README.md",
|
|
38
|
+
"CLI.md",
|
|
39
|
+
"PACKAGE_MANAGERS.md",
|
|
27
40
|
"dist",
|
|
28
|
-
"tsconfig.site.json"
|
|
41
|
+
"tsconfig.site.json",
|
|
42
|
+
"tsconfig.site.no-jsx.json"
|
|
29
43
|
],
|
|
30
44
|
"keywords": [
|
|
31
|
-
"
|
|
32
|
-
"
|
|
45
|
+
"typescript",
|
|
46
|
+
"project-generator",
|
|
47
|
+
"static-site-generator",
|
|
48
|
+
"web-development",
|
|
49
|
+
"framework-independent",
|
|
50
|
+
"accessibility",
|
|
51
|
+
"seo",
|
|
52
|
+
"progressive-enhancement",
|
|
53
|
+
"serverless",
|
|
33
54
|
"esbuild",
|
|
34
|
-
"
|
|
55
|
+
"tailwindcss",
|
|
56
|
+
"jsx",
|
|
57
|
+
"cli",
|
|
58
|
+
"scaffolding",
|
|
59
|
+
"white-label"
|
|
35
60
|
],
|
|
36
61
|
"author": "Bill Shackelford",
|
|
37
62
|
"license": "MIT",
|
|
@@ -42,40 +67,38 @@
|
|
|
42
67
|
"bugs": {
|
|
43
68
|
"url": "https://github.com/bshack/white-label/issues"
|
|
44
69
|
},
|
|
45
|
-
"homepage": "https://
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@types/node": "24.13.3",
|
|
48
|
-
"@yeoman/adapter": "5.0.0",
|
|
49
|
-
"bootstrap": "5.3.8",
|
|
50
|
-
"chalk": "6.0.0",
|
|
51
|
-
"esbuild": "0.28.2",
|
|
52
|
-
"events": "3.3.0",
|
|
53
|
-
"handlebars": "4.7.9",
|
|
54
|
-
"react": "19.2.8",
|
|
55
|
-
"react-dom": "19.2.8",
|
|
56
|
-
"sass": "1.104.0",
|
|
57
|
-
"white-label-model": "3.0.0",
|
|
58
|
-
"white-label-view": "4.0.0",
|
|
59
|
-
"yeoman-generator": "8.3.1",
|
|
60
|
-
"yosay": "3.0.0"
|
|
61
|
-
},
|
|
70
|
+
"homepage": "https://whitelabeljs.org/docs/generator/",
|
|
71
|
+
"dependencies": {},
|
|
62
72
|
"devDependencies": {
|
|
63
|
-
"@
|
|
64
|
-
"@types/
|
|
65
|
-
"
|
|
73
|
+
"@tailwindcss/cli": "4.3.3",
|
|
74
|
+
"@types/node": "24.13.3",
|
|
75
|
+
"axe-core": "4.13.0",
|
|
66
76
|
"c8": "12.0.0",
|
|
77
|
+
"esbuild": "0.28.2",
|
|
78
|
+
"html-validate": "11.15.0",
|
|
67
79
|
"jsdom": "30.0.1",
|
|
80
|
+
"tailwindcss": "4.3.3",
|
|
68
81
|
"typescript": "7.0.2",
|
|
69
|
-
"
|
|
82
|
+
"white-label-mediator": "4.0.0",
|
|
83
|
+
"white-label-model": "6.0.0",
|
|
84
|
+
"white-label-router": "5.0.0",
|
|
85
|
+
"white-label-view": "5.1.0",
|
|
86
|
+
"@babel/core": "8.0.5",
|
|
87
|
+
"@babel/eslint-parser": "8.0.5",
|
|
88
|
+
"@babel/plugin-syntax-jsx": "8.0.1",
|
|
89
|
+
"@babel/preset-typescript": "8.0.1",
|
|
90
|
+
"@eslint/js": "10.0.1",
|
|
91
|
+
"eslint": "10.10.0"
|
|
70
92
|
},
|
|
71
|
-
"types": "dist/
|
|
93
|
+
"types": "dist/scaffold/index.d.ts",
|
|
72
94
|
"c8": {
|
|
73
95
|
"all": true,
|
|
74
96
|
"include": [
|
|
97
|
+
"cli/**/*.ts",
|
|
75
98
|
"scripts/**/*.ts",
|
|
76
|
-
"
|
|
77
|
-
"app
|
|
78
|
-
"app
|
|
99
|
+
"scaffold/**/*.ts",
|
|
100
|
+
"app/**/*.ts",
|
|
101
|
+
"app/**/*.tsx"
|
|
79
102
|
],
|
|
80
103
|
"reporter": [
|
|
81
104
|
"text",
|
|
@@ -91,7 +114,21 @@
|
|
|
91
114
|
"statements": 100,
|
|
92
115
|
"perFile": true,
|
|
93
116
|
"exclude": [
|
|
94
|
-
"**/*.d.ts"
|
|
117
|
+
"**/*.d.ts",
|
|
118
|
+
"app/assets/view/page-data.ts",
|
|
119
|
+
"scaffold/no-jsx/app/**"
|
|
95
120
|
]
|
|
121
|
+
},
|
|
122
|
+
"exports": {
|
|
123
|
+
".": {
|
|
124
|
+
"types": "./dist/scaffold/index.d.ts",
|
|
125
|
+
"import": "./dist/scaffold/index.js",
|
|
126
|
+
"default": "./dist/scaffold/index.js"
|
|
127
|
+
},
|
|
128
|
+
"./scaffold": {
|
|
129
|
+
"types": "./dist/scaffold/index.d.ts",
|
|
130
|
+
"import": "./dist/scaffold/index.js",
|
|
131
|
+
"default": "./dist/scaffold/index.js"
|
|
132
|
+
}
|
|
96
133
|
}
|
|
97
134
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/** @module scaffold */
|
|
2
|
+
import {cp, mkdir, writeFile} from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
|
|
6
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
7
|
+
|
|
8
|
+
export interface ScaffoldFileSystem {
|
|
9
|
+
copy(source: string, destination: string): void | Promise<void>;
|
|
10
|
+
writeJSON(destination: string, value: unknown): void | Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CreateProjectOptions {
|
|
14
|
+
destination: string;
|
|
15
|
+
fileSystem?: ScaffoldFileSystem;
|
|
16
|
+
jsx?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const nodeFileSystem: ScaffoldFileSystem = {
|
|
20
|
+
async copy(source, destination) {
|
|
21
|
+
await mkdir(path.dirname(destination), {recursive: true});
|
|
22
|
+
await cp(source, destination, {recursive: true});
|
|
23
|
+
},
|
|
24
|
+
async writeJSON(destination, value) {
|
|
25
|
+
await mkdir(path.dirname(destination), {recursive: true});
|
|
26
|
+
await writeFile(destination, `${JSON.stringify(value, null, 2)}\n`);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Return the package manifest used by generated White Label projects. */
|
|
31
|
+
export function createSiteManifest() {
|
|
32
|
+
return {
|
|
33
|
+
name: 'white-label-site',
|
|
34
|
+
version: '1.0.0',
|
|
35
|
+
private: true,
|
|
36
|
+
type: 'module',
|
|
37
|
+
engines: {node: '^22.18.0 || >=24.11.0'},
|
|
38
|
+
scripts: {
|
|
39
|
+
build: 'tsc -p tsconfig.json && node dist/scripts/build.js',
|
|
40
|
+
typecheck: 'tsc -p tsconfig.json --noEmit',
|
|
41
|
+
test: 'node --run typecheck && node --run build -- --version=test --production=true --site-url=https://example.com && node --test --experimental-test-coverage --test-coverage-include=dist/app/assets/script/index.js --test-coverage-lines=100 --test-coverage-functions=100 --test-coverage-branches=100 test/*.test.js'
|
|
42
|
+
},
|
|
43
|
+
allowScripts: {
|
|
44
|
+
'@parcel/watcher@2.5.1': true,
|
|
45
|
+
'esbuild@0.28.2': true,
|
|
46
|
+
'white-label-view@5.1.0': true
|
|
47
|
+
},
|
|
48
|
+
dependenciesMeta: {
|
|
49
|
+
'@parcel/watcher@2.5.1': {built: true},
|
|
50
|
+
'esbuild@0.28.2': {built: true},
|
|
51
|
+
'white-label-view@5.1.0': {built: true}
|
|
52
|
+
},
|
|
53
|
+
devDependencies: {
|
|
54
|
+
'@tailwindcss/cli': '4.3.3',
|
|
55
|
+
'@types/node': '24.13.3',
|
|
56
|
+
'axe-core': '4.13.0',
|
|
57
|
+
'esbuild': '0.28.2',
|
|
58
|
+
'html-validate': '11.15.0',
|
|
59
|
+
'jsdom': '30.0.1',
|
|
60
|
+
'tailwindcss': '4.3.3',
|
|
61
|
+
'typescript': '7.0.2'
|
|
62
|
+
},
|
|
63
|
+
dependencies: {
|
|
64
|
+
'white-label-mediator': '4.0.0',
|
|
65
|
+
'white-label-model': '6.0.0',
|
|
66
|
+
'white-label-router': '5.0.0',
|
|
67
|
+
'white-label-view': '5.1.0'
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const commonNoJsxCopies = [
|
|
73
|
+
['app/assets/data', 'app/assets/data'],
|
|
74
|
+
['app/assets/style', 'app/assets/style'],
|
|
75
|
+
['app/assets/script/tasks/TaskApplication.ts', 'app/assets/script/tasks/TaskApplication.ts'],
|
|
76
|
+
['app/assets/script/tasks/TaskMediator.ts', 'app/assets/script/tasks/TaskMediator.ts'],
|
|
77
|
+
['app/assets/script/tasks/TaskModel.ts', 'app/assets/script/tasks/TaskModel.ts'],
|
|
78
|
+
['app/assets/script/tasks/TaskRouter.ts', 'app/assets/script/tasks/TaskRouter.ts'],
|
|
79
|
+
['app/assets/view/examples/tasks/task-state.ts', 'app/assets/view/examples/tasks/task-state.ts'],
|
|
80
|
+
['app/package.json', 'app/package.json']
|
|
81
|
+
] as const;
|
|
82
|
+
|
|
83
|
+
const noJsxTemplateCopies = [
|
|
84
|
+
['scaffold/no-jsx/app/index.ts', 'app/index.ts'],
|
|
85
|
+
['scaffold/no-jsx/app/404.ts', 'app/404.ts'],
|
|
86
|
+
['scaffold/no-jsx/app/assets/script/index.ts', 'app/assets/script/index.ts'],
|
|
87
|
+
['scaffold/no-jsx/app/assets/script/tasks/TaskView.ts', 'app/assets/script/tasks/TaskView.ts'],
|
|
88
|
+
['scaffold/no-jsx/app/assets/view/examples/tasks/TaskExample.ts', 'app/assets/view/examples/tasks/TaskExample.ts'],
|
|
89
|
+
['scaffold/no-jsx/README.md', 'README.md'],
|
|
90
|
+
['tsconfig.site.no-jsx.json', 'tsconfig.json']
|
|
91
|
+
] as const;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a White Label project.
|
|
95
|
+
*
|
|
96
|
+
* This is the shared implementation behind every creation interface. Adapters
|
|
97
|
+
* translate their environment into these options instead of owning templates or
|
|
98
|
+
* project-generation behavior themselves.
|
|
99
|
+
*/
|
|
100
|
+
export async function createProject({destination, fileSystem = nodeFileSystem, jsx = true}: CreateProjectOptions) {
|
|
101
|
+
const copies = jsx ? [
|
|
102
|
+
['.editorconfig', '.editorconfig'],
|
|
103
|
+
['.yarnrc.yml', '.yarnrc.yml'],
|
|
104
|
+
['pnpm-workspace.yaml', 'pnpm-workspace.yaml'],
|
|
105
|
+
['app', 'app'],
|
|
106
|
+
['app/README.md', 'README.md'],
|
|
107
|
+
['server', 'server'],
|
|
108
|
+
['scripts', 'scripts'],
|
|
109
|
+
['template-test', 'test'],
|
|
110
|
+
['tsconfig.site.json', 'tsconfig.json']
|
|
111
|
+
] as const : [
|
|
112
|
+
['.editorconfig', '.editorconfig'],
|
|
113
|
+
['.yarnrc.yml', '.yarnrc.yml'],
|
|
114
|
+
['pnpm-workspace.yaml', 'pnpm-workspace.yaml'],
|
|
115
|
+
...commonNoJsxCopies,
|
|
116
|
+
...noJsxTemplateCopies,
|
|
117
|
+
['server', 'server'],
|
|
118
|
+
['scripts', 'scripts'],
|
|
119
|
+
['template-test', 'test']
|
|
120
|
+
] as const;
|
|
121
|
+
|
|
122
|
+
for (const [source, target] of copies) {
|
|
123
|
+
await fileSystem.copy(path.join(packageRoot, source), path.join(destination, target));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await fileSystem.writeJSON(path.join(destination, 'package.json'), createSiteManifest());
|
|
127
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# White Label generated site
|
|
2
|
+
|
|
3
|
+
This project was generated with the **plain TypeScript / no-JSX** template option.
|
|
4
|
+
|
|
5
|
+
- Pages and views are `.ts` files.
|
|
6
|
+
- Templates return HTML strings instead of using JSX/TSX syntax.
|
|
7
|
+
- React is not required.
|
|
8
|
+
- White Label Model, View, Router, and Mediator are used the same way as in the JSX template.
|
|
9
|
+
- npm, Yarn, and pnpm are supported.
|
|
10
|
+
|
|
11
|
+
This scaffold is also the right starting point when you want a third-party template engine. Install the renderer your application uses, then call it from the View `template` function instead of returning a hand-built string. White Label does not require a renderer adapter or change the rest of the application architecture.
|
|
12
|
+
|
|
13
|
+
See [Template engines and JSX options](https://whitelabeljs.org/docs/view/#template-engines) for the tested third-party engines, examples, rendering contract, and escaping/security guidance.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
Use the package manager you prefer:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install
|
|
21
|
+
npm run build
|
|
22
|
+
npm test
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
yarn install
|
|
27
|
+
yarn build
|
|
28
|
+
yarn test
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pnpm install
|
|
33
|
+
pnpm build
|
|
34
|
+
pnpm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Serverless / function runtimes
|
|
38
|
+
|
|
39
|
+
`server/handler.ts` is the same provider-neutral serverless example included in the JSX scaffold. It uses Web `Request` and `Response`, request-scoped Model/View/Router/Mediator instances, and the server View entrypoint; it does not require JSX or a provider SDK.
|
|
40
|
+
|
|
41
|
+
Keep immutable configuration at module scope when useful, but create mutable White Label instances per request unless shared state is explicitly intended. Warm serverless processes may handle many requests, so module-level mutable application state can leak data between invocations.
|
|
42
|
+
|
|
43
|
+
Use a thin cloud adapter around the handler when a platform does not expose Web `Request`/`Response` directly. The generated tests exercise repeated and concurrent requests, browser-global absence, Web-target bundling, and serverless bundle/startup budgets.
|
|
44
|
+
|
|
45
|
+
The Web-target bundle check is a portability smoke test, not a blanket claim of compatibility with every edge runtime. Verify the provider runtime you deploy to.
|
|
46
|
+
|
|
47
|
+
If you prefer JSX syntax for templates, generate a new project with `--jsx` or answer **Yes** to the generator's JSX question. JSX and no-JSX projects provide equivalent White Label functionality; the choice is about template syntax and renderer ownership.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface PageData {cdn: string; siteUrl: string; title: string; version: string}
|
|
2
|
+
|
|
3
|
+
function escapeHtml(value: unknown): string {
|
|
4
|
+
return String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default function NotFoundPage(data: Record<string, unknown>): string {
|
|
8
|
+
const page = data as unknown as PageData;
|
|
9
|
+
return `<html lang="en-US"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Page not found | ${escapeHtml(page.title)}</title><meta name="robots" content="noindex,follow"><link rel="stylesheet" href="${escapeHtml(page.cdn)}release/${escapeHtml(page.version)}/assets/style/global.css"></head><body><a class="skip-link" href="#main">Skip to the message</a><main id="main" tabindex="-1"><h1>Page not found</h1><p>The requested page could not be found.</p><p><a href="${escapeHtml(page.siteUrl)}/">Return home</a></p></main></body></html>`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @module app/assets/script/index */
|
|
2
|
+
import {initializeTaskApplication} from './tasks/TaskApplication.js';
|
|
3
|
+
|
|
4
|
+
export {initializeTaskApplication} from './tasks/TaskApplication.js';
|
|
5
|
+
export {normalizeTaskFilter} from './tasks/TaskRouter.js';
|
|
6
|
+
|
|
7
|
+
initializeTaskApplication(document);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import View from 'white-label-view';
|
|
2
|
+
import TaskExample from '../../view/examples/tasks/TaskExample.js';
|
|
3
|
+
import type {TaskState} from '../../view/examples/tasks/task-state.js';
|
|
4
|
+
import type TaskModel from './TaskModel.js';
|
|
5
|
+
|
|
6
|
+
/** Create the task view without JSX/TSX syntax. */
|
|
7
|
+
export function createTaskView(parentElement: HTMLElement, model: TaskModel): View {
|
|
8
|
+
const element = parentElement.querySelector<HTMLElement>('[data-task-app]');
|
|
9
|
+
if (!element) {throw new TypeError('Task example requires its static task-app root');}
|
|
10
|
+
|
|
11
|
+
return new View({
|
|
12
|
+
element,
|
|
13
|
+
model,
|
|
14
|
+
parentElement,
|
|
15
|
+
template(data) {
|
|
16
|
+
return TaskExample({state: data as TaskState});
|
|
17
|
+
}
|
|
18
|
+
}).initialize();
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {getVisibleTasks, type TaskFilter, type TaskState} from './task-state.js';
|
|
2
|
+
|
|
3
|
+
const filters: TaskFilter[] = ['all', 'active', 'completed'];
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value: unknown): string {
|
|
6
|
+
return String(value)
|
|
7
|
+
.replaceAll('&', '&')
|
|
8
|
+
.replaceAll('<', '<')
|
|
9
|
+
.replaceAll('>', '>')
|
|
10
|
+
.replaceAll('"', '"')
|
|
11
|
+
.replaceAll("'", ''');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Render the task example with plain TypeScript and HTML strings. */
|
|
15
|
+
export default function TaskExample({state}: {state: TaskState}): string {
|
|
16
|
+
const visibleTasks = getVisibleTasks(state);
|
|
17
|
+
const completed = state.tasks.filter(task => task.complete).length;
|
|
18
|
+
const filterLinks = filters.map(filter => `
|
|
19
|
+
<a href="/?tasks=${filter}#example" data-task-filter="${filter}" data-pushstate aria-current="${state.filter === filter ? 'page' : 'false'}">${filter.charAt(0).toUpperCase()}${filter.slice(1)}</a>
|
|
20
|
+
`).join('');
|
|
21
|
+
const tasks = visibleTasks.map(task => `
|
|
22
|
+
<li><label><input type="checkbox" ${task.complete ? 'checked ' : ''}data-task-toggle data-task-id="${task.id}"><span>${escapeHtml(task.title)}</span></label></li>
|
|
23
|
+
`).join('');
|
|
24
|
+
|
|
25
|
+
return `<section class="task-app" data-task-app aria-label="Interactive task example">
|
|
26
|
+
<form class="task-form" data-task-form action="#example" method="get">
|
|
27
|
+
<label for="task-title">New task</label>
|
|
28
|
+
<div class="task-form__controls"><input id="task-title" name="task" type="text" autocomplete="off" required><button type="submit">Add task</button></div>
|
|
29
|
+
</form>
|
|
30
|
+
<nav class="task-filters" aria-label="Filter tasks">${filterLinks}</nav>
|
|
31
|
+
<ul class="task-list">${tasks}</ul>
|
|
32
|
+
<dl class="demo__trace">
|
|
33
|
+
<div><dt>Router</dt><dd>/?tasks=${state.filter}</dd></div>
|
|
34
|
+
<div><dt>Mediator</dt><dd>task:* application events</dd></div>
|
|
35
|
+
<div><dt>Model</dt><dd>${state.tasks.length} tasks · ${completed} complete</dd></div>
|
|
36
|
+
<div><dt>View</dt><dd>${visibleTasks.length} tasks rendered</dd></div>
|
|
37
|
+
</dl>
|
|
38
|
+
</section>`;
|
|
39
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import TaskExample from './assets/view/examples/tasks/TaskExample.js';
|
|
2
|
+
import {createInitialTaskState, describeTaskStatus} from './assets/view/examples/tasks/task-state.js';
|
|
3
|
+
|
|
4
|
+
interface PageData {
|
|
5
|
+
cdn: string;
|
|
6
|
+
meta: {description: string};
|
|
7
|
+
siteUrl: string;
|
|
8
|
+
structuredData: Record<string, unknown>;
|
|
9
|
+
title: string;
|
|
10
|
+
version: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function escapeHtml(value: unknown): string {
|
|
14
|
+
return String(value)
|
|
15
|
+
.replaceAll('&', '&')
|
|
16
|
+
.replaceAll('<', '<')
|
|
17
|
+
.replaceAll('>', '>')
|
|
18
|
+
.replaceAll('"', '"')
|
|
19
|
+
.replaceAll("'", ''');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Render the generated starter using plain TypeScript and HTML strings. */
|
|
23
|
+
export default function IndexPage(data: Record<string, unknown>): string {
|
|
24
|
+
const page = data as unknown as PageData;
|
|
25
|
+
const taskState = createInitialTaskState();
|
|
26
|
+
const taskExample = TaskExample({state: taskState});
|
|
27
|
+
const taskStatus = describeTaskStatus(taskState);
|
|
28
|
+
const structuredData = JSON.stringify(page.structuredData).replaceAll('<', '\\u003c');
|
|
29
|
+
|
|
30
|
+
return `<html id="index" lang="en-US" dir="ltr">
|
|
31
|
+
<head>
|
|
32
|
+
<meta charset="utf-8">
|
|
33
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
34
|
+
<title>${escapeHtml(page.title)}</title>
|
|
35
|
+
<meta name="description" content="${escapeHtml(page.meta.description)}">
|
|
36
|
+
<meta name="robots" content="index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1">
|
|
37
|
+
<link rel="canonical" href="${escapeHtml(page.siteUrl)}/">
|
|
38
|
+
<meta property="og:title" content="${escapeHtml(page.title)}">
|
|
39
|
+
<meta property="og:description" content="${escapeHtml(page.meta.description)}">
|
|
40
|
+
<meta property="og:type" content="website">
|
|
41
|
+
<meta property="og:url" content="${escapeHtml(page.siteUrl)}/">
|
|
42
|
+
<link rel="stylesheet" href="${escapeHtml(page.cdn)}release/${escapeHtml(page.version)}/assets/style/global.css" media="all">
|
|
43
|
+
<link rel="stylesheet" href="${escapeHtml(page.cdn)}release/${escapeHtml(page.version)}/assets/style/print.css" media="print">
|
|
44
|
+
<script type="application/ld+json">${structuredData}</script>
|
|
45
|
+
</head>
|
|
46
|
+
<body itemscope itemtype="https://schema.org/WebPage">
|
|
47
|
+
<a class="skip-link" href="#main">Skip to content</a>
|
|
48
|
+
<header><nav aria-label="Primary"><a href="/">White Label</a></nav></header>
|
|
49
|
+
<main id="main" tabindex="-1">
|
|
50
|
+
<section class="hero"><p class="eyebrow">White Label starter</p><h1>Composable web primitives without a framework lock-in.</h1><p>State, rendering, routing, and application events stay small, explicit, and independently understandable.</p></section>
|
|
51
|
+
<section id="example" data-task-example><h2>Interactive task example</h2>${taskExample}<p class="visually-hidden" role="status" aria-live="polite" aria-atomic="true" data-task-status>${escapeHtml(taskStatus)}</p></section>
|
|
52
|
+
<section><h2>Plain TypeScript templates</h2><p>This project was generated without JSX. Pages and views return HTML strings from ordinary TypeScript functions.</p></section>
|
|
53
|
+
</main>
|
|
54
|
+
<footer><p>Built with White Label.</p></footer>
|
|
55
|
+
<script src="${escapeHtml(page.cdn)}release/${escapeHtml(page.version)}/assets/script/index.compiled.js" defer></script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>`;
|
|
58
|
+
}
|