@vojtaholik/create-static-kit 1.0.7 → 2.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/package.json +6 -37
- package/src/index.ts +41 -0
- package/template/blocks/feature-grid.block.html +28 -0
- package/template/blocks/feature-grid.block.ts +32 -0
- package/template/blocks/gen/feature-grid.render.ts +92 -0
- package/template/blocks/gen/hero.render.ts +79 -0
- package/template/blocks/gen/index.ts +4 -0
- package/template/blocks/gen/latest-posts.render.ts +114 -0
- package/template/blocks/gen/text-section.render.ts +69 -0
- package/template/blocks/hero.block.html +31 -0
- package/template/blocks/hero.block.ts +40 -0
- package/template/blocks/index.ts +31 -0
- package/template/blocks/latest-posts.block.html +38 -0
- package/template/blocks/latest-posts.block.ts +45 -0
- package/template/blocks/text-section.block.html +18 -0
- package/template/blocks/text-section.block.ts +25 -0
- package/template/cms-blocks.ts +197 -0
- package/template/package.json +21 -0
- package/template/public/css/styles.css +589 -0
- package/template/public/js/dev-overlay.js +366 -0
- package/template/public/js/index.js +35 -0
- package/template/public/sprite.svg +6 -0
- package/template/public/svg/magic-wand.svg +4 -0
- package/template/site/pages/about.page.ts +91 -0
- package/template/site/pages/base.html +38 -0
- package/template/site/pages/index.page.ts +107 -0
- package/template/site/pages/index.ts +16 -0
- package/template/static-kit.config.ts +10 -0
- package/template/tsconfig.json +23 -0
- package/bin/create-static-kit.js +0 -3
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -488
- package/templates/default/.cursor/rules/configuration.mdc +0 -20
- package/templates/default/.cursor/rules/figma-integration.mdc +0 -22
- package/templates/default/.cursor/rules/html-components.mdc +0 -24
- package/templates/default/.cursor/rules/html-pages.mdc +0 -22
- package/templates/default/.cursor/rules/inline-tailwind-to-bem-with-apply-directive.mdc +0 -218
- package/templates/default/.cursor/rules/project-overview.mdc +0 -30
- package/templates/default/.cursor/rules/public-assets.mdc +0 -22
- package/templates/default/.cursor/rules/scss-styles.mdc +0 -22
- package/templates/default/.cursor/rules/svg-icons.mdc +0 -22
- package/templates/default/.cursor/rules/typescript-js.mdc +0 -23
- package/templates/default/public/favicon.ico +0 -1
- package/templates/default/src/components/button.html +0 -1
- package/templates/default/src/components/feature-card.html +0 -8
- package/templates/default/src/components/footer.html +0 -5
- package/templates/default/src/components/navigation.html +0 -11
- package/templates/default/src/icons/ui/star.svg +0 -3
- package/templates/default/src/js/index.ts +0 -28
- package/templates/default/src/pages/about.html +0 -24
- package/templates/default/src/pages/index.html +0 -23
- package/templates/default/src/styles/main.scss +0 -210
- package/templates/default/tsconfig.json +0 -19
- package/templates/minimal/.cursor/rules/configuration.mdc +0 -20
- package/templates/minimal/.cursor/rules/figma-integration.mdc +0 -22
- package/templates/minimal/.cursor/rules/html-components.mdc +0 -24
- package/templates/minimal/.cursor/rules/html-pages.mdc +0 -22
- package/templates/minimal/.cursor/rules/inline-tailwind-to-bem-with-apply-directive.mdc +0 -218
- package/templates/minimal/.cursor/rules/project-overview.mdc +0 -30
- package/templates/minimal/.cursor/rules/public-assets.mdc +0 -22
- package/templates/minimal/.cursor/rules/scss-styles.mdc +0 -22
- package/templates/minimal/.cursor/rules/svg-icons.mdc +0 -22
- package/templates/minimal/.cursor/rules/typescript-js.mdc +0 -23
- package/templates/minimal/public/favicon.ico +0 -1
- package/templates/minimal/src/components/footer.html +0 -3
- package/templates/minimal/src/components/header.html +0 -6
- package/templates/minimal/src/js/index.ts +0 -9
- package/templates/minimal/src/pages/index.html +0 -15
- package/templates/minimal/src/styles/main.scss +0 -77
- package/templates/minimal/tsconfig.json +0 -19
package/package.json
CHANGED
|
@@ -1,48 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vojtaholik/create-static-kit",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "CLI tool to create new Static Kit projects",
|
|
3
|
+
"version": "2.0.0",
|
|
5
4
|
"type": "module",
|
|
6
5
|
"bin": {
|
|
7
|
-
"create-static-kit": "./
|
|
6
|
+
"create-static-kit": "./src/index.ts"
|
|
8
7
|
},
|
|
9
|
-
"files": [
|
|
10
|
-
"bin/",
|
|
11
|
-
"dist/",
|
|
12
|
-
"templates/"
|
|
13
|
-
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsc",
|
|
16
|
-
"dev": "tsc --watch",
|
|
17
|
-
"clean": "rm -rf dist"
|
|
18
|
-
},
|
|
19
|
-
"dependencies": {
|
|
20
|
-
"@vojtaholik/static-kit-core": "^1.0.0",
|
|
21
|
-
"prompts": "^2.4.2",
|
|
22
|
-
"kleur": "^4.1.5",
|
|
23
|
-
"fast-glob": "^3.3.3"
|
|
24
|
-
},
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"@types/node": "^24.2.1",
|
|
27
|
-
"@types/prompts": "^2.4.9",
|
|
28
|
-
"typescript": "~5.9.2"
|
|
29
|
-
},
|
|
30
|
-
"keywords": [
|
|
31
|
-
"create",
|
|
32
|
-
"static-kit",
|
|
33
|
-
"cli",
|
|
34
|
-
"scaffold",
|
|
35
|
-
"template"
|
|
36
|
-
],
|
|
37
|
-
"author": "Vojta Holik <vojta@holik.dev>",
|
|
38
|
-
"license": "MIT",
|
|
8
|
+
"files": ["src", "template"],
|
|
39
9
|
"repository": {
|
|
40
10
|
"type": "git",
|
|
41
|
-
"url": "https://github.com/vojtaholik/
|
|
11
|
+
"url": "https://github.com/vojtaholik/module-kit",
|
|
42
12
|
"directory": "packages/create-static-kit"
|
|
43
13
|
},
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"url": "https://github.com/vojtaholik/static-kit/issues"
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
47
16
|
}
|
|
48
17
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Create Static Kit - Project Scaffolder
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bun create @vojtaholik/static-kit my-site
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { cp, mkdir } from "node:fs/promises";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
const templateDir = join(__dirname, "..", "template");
|
|
16
|
+
|
|
17
|
+
const targetDir = process.argv[2] || ".";
|
|
18
|
+
const targetPath = join(process.cwd(), targetDir);
|
|
19
|
+
|
|
20
|
+
console.log(`\n🚀 Creating Static Kit project in ${targetPath}\n`);
|
|
21
|
+
|
|
22
|
+
await mkdir(targetPath, { recursive: true });
|
|
23
|
+
await cp(templateDir, targetPath, { recursive: true });
|
|
24
|
+
|
|
25
|
+
if (targetDir !== ".") {
|
|
26
|
+
const packageJsonPath = join(targetPath, "package.json");
|
|
27
|
+
const packageJson = await Bun.file(packageJsonPath).json();
|
|
28
|
+
packageJson.name = targetDir.split("/").pop();
|
|
29
|
+
await Bun.write(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(`✅ Done!
|
|
33
|
+
|
|
34
|
+
Next steps:
|
|
35
|
+
${targetDir !== "." ? `cd ${targetDir}` : ""}
|
|
36
|
+
bun install
|
|
37
|
+
bun run gen
|
|
38
|
+
bun run dev
|
|
39
|
+
|
|
40
|
+
Happy building! 🎉
|
|
41
|
+
`);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<section class="section section--feature-grid section--tone-{{ ctx.layout.tone }}" data-block-id="{{ addr.blockId }}" data-schema-address="{{ encodeSchemaAddress(addr) }}">
|
|
2
|
+
<div class="container container--{{ ctx.layout.contentWidth }}">
|
|
3
|
+
<template v-if="props.headline || props.subheadline">
|
|
4
|
+
<div class="section__header section__header--{{ ctx.layout.contentAlign }}">
|
|
5
|
+
<template v-if="props.headline">
|
|
6
|
+
<h2 class="h2">{{ props.headline }}</h2>
|
|
7
|
+
</template>
|
|
8
|
+
<template v-if="props.subheadline">
|
|
9
|
+
<p class="text-body">{{ props.subheadline }}</p>
|
|
10
|
+
</template>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
<div class="grid grid--{{ props.columns || '3' }}">
|
|
14
|
+
<template v-for="feature, i in props.features">
|
|
15
|
+
<div class="card">
|
|
16
|
+
<template v-if="feature.icon">
|
|
17
|
+
<span class="card__icon">{{ feature.icon }}</span>
|
|
18
|
+
</template>
|
|
19
|
+
<h3 class="h3 card__title">{{ feature.title }}</h3>
|
|
20
|
+
<p class="text-body card__description">{{ feature.description }}</p>
|
|
21
|
+
<template v-if="feature.link">
|
|
22
|
+
<a class="card__link" :href="feature.link.href">{{ feature.link.label }}</a>
|
|
23
|
+
</template>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</section>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { defineBlock } from "@vojtaholik/static-kit-core";
|
|
3
|
+
import { renderFeatureGrid } from "./gen/feature-grid.render.ts";
|
|
4
|
+
|
|
5
|
+
export const featureGridPropsSchema = z.object({
|
|
6
|
+
headline: z.string().optional(),
|
|
7
|
+
subheadline: z.string().optional(),
|
|
8
|
+
columns: z.enum(["2", "3", "4"]).default("3"),
|
|
9
|
+
features: z.array(
|
|
10
|
+
z.object({
|
|
11
|
+
icon: z.string().optional(),
|
|
12
|
+
title: z.string(),
|
|
13
|
+
description: z.string(),
|
|
14
|
+
link: z
|
|
15
|
+
.object({
|
|
16
|
+
href: z.string(),
|
|
17
|
+
label: z.string(),
|
|
18
|
+
external: z.boolean().optional(),
|
|
19
|
+
})
|
|
20
|
+
.optional(),
|
|
21
|
+
})
|
|
22
|
+
),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type FeatureGridProps = z.infer<typeof featureGridPropsSchema>;
|
|
26
|
+
|
|
27
|
+
export const featureGridBlock = defineBlock({
|
|
28
|
+
type: "featureGrid",
|
|
29
|
+
propsSchema: featureGridPropsSchema,
|
|
30
|
+
renderHtml: renderFeatureGrid,
|
|
31
|
+
sourceFile: import.meta.url,
|
|
32
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Auto-generated - DO NOT EDIT
|
|
2
|
+
import { escapeHtml, escapeAttr, type RenderBlockInput } from "@static-block-kit/core";
|
|
3
|
+
import { encodeSchemaAddress } from "@static-block-kit/core";
|
|
4
|
+
|
|
5
|
+
export function renderFeatureGrid(input: RenderBlockInput): string {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
const { props, ctx, addr } = input as { props: any; ctx: typeof input.ctx; addr: typeof input.addr };
|
|
8
|
+
let out = "";
|
|
9
|
+
out += "<section";
|
|
10
|
+
out += " class=\"";
|
|
11
|
+
out += "section section--feature-grid section--tone-";
|
|
12
|
+
out += escapeAttr(ctx.layout.tone);
|
|
13
|
+
out += "\"";
|
|
14
|
+
out += " data-block-id=\"";
|
|
15
|
+
out += escapeAttr(addr.blockId);
|
|
16
|
+
out += "\"";
|
|
17
|
+
out += " data-schema-address=\"";
|
|
18
|
+
out += escapeAttr(encodeSchemaAddress(addr));
|
|
19
|
+
out += "\"";
|
|
20
|
+
out += ">";
|
|
21
|
+
out += "<div";
|
|
22
|
+
out += " class=\"";
|
|
23
|
+
out += "container container--";
|
|
24
|
+
out += escapeAttr(ctx.layout.contentWidth);
|
|
25
|
+
out += "\"";
|
|
26
|
+
out += ">";
|
|
27
|
+
if (props.headline || props.subheadline) {
|
|
28
|
+
out += "<div";
|
|
29
|
+
out += " class=\"";
|
|
30
|
+
out += "section__header section__header--";
|
|
31
|
+
out += escapeAttr(ctx.layout.contentAlign);
|
|
32
|
+
out += "\"";
|
|
33
|
+
out += ">";
|
|
34
|
+
if (props.headline) {
|
|
35
|
+
out += "<h2";
|
|
36
|
+
out += " class=\"h2\"";
|
|
37
|
+
out += ">";
|
|
38
|
+
out += escapeHtml(props.headline);
|
|
39
|
+
out += "</h2>";
|
|
40
|
+
}
|
|
41
|
+
if (props.subheadline) {
|
|
42
|
+
out += "<p";
|
|
43
|
+
out += " class=\"text-body\"";
|
|
44
|
+
out += ">";
|
|
45
|
+
out += escapeHtml(props.subheadline);
|
|
46
|
+
out += "</p>";
|
|
47
|
+
}
|
|
48
|
+
out += "</div>";
|
|
49
|
+
}
|
|
50
|
+
out += "<div";
|
|
51
|
+
out += " class=\"";
|
|
52
|
+
out += "grid grid--";
|
|
53
|
+
out += escapeAttr(props.columns || '3');
|
|
54
|
+
out += "\"";
|
|
55
|
+
out += ">";
|
|
56
|
+
for (const [i, feature] of (props.features).entries()) {
|
|
57
|
+
out += "<div";
|
|
58
|
+
out += " class=\"card\"";
|
|
59
|
+
out += ">";
|
|
60
|
+
if (feature.icon) {
|
|
61
|
+
out += "<span";
|
|
62
|
+
out += " class=\"card__icon\"";
|
|
63
|
+
out += ">";
|
|
64
|
+
out += escapeHtml(feature.icon);
|
|
65
|
+
out += "</span>";
|
|
66
|
+
}
|
|
67
|
+
out += "<h3";
|
|
68
|
+
out += " class=\"h3 card__title\"";
|
|
69
|
+
out += ">";
|
|
70
|
+
out += escapeHtml(feature.title);
|
|
71
|
+
out += "</h3>";
|
|
72
|
+
out += "<p";
|
|
73
|
+
out += " class=\"text-body card__description\"";
|
|
74
|
+
out += ">";
|
|
75
|
+
out += escapeHtml(feature.description);
|
|
76
|
+
out += "</p>";
|
|
77
|
+
if (feature.link) {
|
|
78
|
+
out += "<a";
|
|
79
|
+
out += " class=\"card__link\"";
|
|
80
|
+
out += " href=\"" + escapeAttr(feature.link.href) + "\"";
|
|
81
|
+
out += ">";
|
|
82
|
+
out += escapeHtml(feature.link.label);
|
|
83
|
+
out += "</a>";
|
|
84
|
+
}
|
|
85
|
+
out += "</div>";
|
|
86
|
+
}
|
|
87
|
+
out += "</div>";
|
|
88
|
+
out += "</div>";
|
|
89
|
+
out += "</section>";
|
|
90
|
+
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Auto-generated - DO NOT EDIT
|
|
2
|
+
import { escapeHtml, escapeAttr, type RenderBlockInput } from "@static-block-kit/core";
|
|
3
|
+
import { encodeSchemaAddress } from "@static-block-kit/core";
|
|
4
|
+
|
|
5
|
+
export function renderHero(input: RenderBlockInput): string {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
const { props, ctx, addr } = input as { props: any; ctx: typeof input.ctx; addr: typeof input.addr };
|
|
8
|
+
let out = "";
|
|
9
|
+
out += "<section";
|
|
10
|
+
out += " class=\"";
|
|
11
|
+
out += "section section--hero section--tone-";
|
|
12
|
+
out += escapeAttr(ctx.layout.tone);
|
|
13
|
+
out += "\"";
|
|
14
|
+
out += " data-block-id=\"";
|
|
15
|
+
out += escapeAttr(addr.blockId);
|
|
16
|
+
out += "\"";
|
|
17
|
+
out += " data-schema-address=\"";
|
|
18
|
+
out += escapeAttr(encodeSchemaAddress(addr));
|
|
19
|
+
out += "\"";
|
|
20
|
+
out += ">";
|
|
21
|
+
out += "<div";
|
|
22
|
+
out += " class=\"";
|
|
23
|
+
out += "container container--";
|
|
24
|
+
out += escapeAttr(ctx.layout.contentWidth);
|
|
25
|
+
out += "\"";
|
|
26
|
+
out += ">";
|
|
27
|
+
out += "<div";
|
|
28
|
+
out += " class=\"";
|
|
29
|
+
out += "hero__content hero__content--";
|
|
30
|
+
out += escapeAttr(ctx.layout.contentAlign);
|
|
31
|
+
out += "\"";
|
|
32
|
+
out += ">";
|
|
33
|
+
if (props.eyebrow) {
|
|
34
|
+
out += "<span";
|
|
35
|
+
out += " class=\"eyebrow\"";
|
|
36
|
+
out += ">";
|
|
37
|
+
out += escapeHtml(props.eyebrow);
|
|
38
|
+
out += "</span>";
|
|
39
|
+
}
|
|
40
|
+
out += "<h1";
|
|
41
|
+
out += " class=\"h1 hero__headline\"";
|
|
42
|
+
out += ">";
|
|
43
|
+
out += escapeHtml(props.headline);
|
|
44
|
+
out += "</h1>";
|
|
45
|
+
if (props.subheadline) {
|
|
46
|
+
out += "<p";
|
|
47
|
+
out += " class=\"text-body hero__subheadline\"";
|
|
48
|
+
out += ">";
|
|
49
|
+
out += escapeHtml(props.subheadline);
|
|
50
|
+
out += "</p>";
|
|
51
|
+
}
|
|
52
|
+
if (props.primaryCta || props.secondaryCta) {
|
|
53
|
+
out += "<div";
|
|
54
|
+
out += " class=\"hero__actions\"";
|
|
55
|
+
out += ">";
|
|
56
|
+
if (props.primaryCta) {
|
|
57
|
+
out += "<a";
|
|
58
|
+
out += " class=\"btn btn--primary\"";
|
|
59
|
+
out += " href=\"" + escapeAttr(props.primaryCta.href) + "\"";
|
|
60
|
+
out += ">";
|
|
61
|
+
out += escapeHtml(props.primaryCta.label);
|
|
62
|
+
out += "</a>";
|
|
63
|
+
}
|
|
64
|
+
if (props.secondaryCta) {
|
|
65
|
+
out += "<a";
|
|
66
|
+
out += " class=\"btn btn--secondary\"";
|
|
67
|
+
out += " href=\"" + escapeAttr(props.secondaryCta.href) + "\"";
|
|
68
|
+
out += ">";
|
|
69
|
+
out += escapeHtml(props.secondaryCta.label);
|
|
70
|
+
out += "</a>";
|
|
71
|
+
}
|
|
72
|
+
out += "</div>";
|
|
73
|
+
}
|
|
74
|
+
out += "</div>";
|
|
75
|
+
out += "</div>";
|
|
76
|
+
out += "</section>";
|
|
77
|
+
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Auto-generated - DO NOT EDIT
|
|
2
|
+
import { escapeHtml, escapeAttr, type RenderBlockInput } from "@static-block-kit/core";
|
|
3
|
+
import { encodeSchemaAddress } from "@static-block-kit/core";
|
|
4
|
+
|
|
5
|
+
export function renderLatestPosts(input: RenderBlockInput): string {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
const { props, ctx, addr } = input as { props: any; ctx: typeof input.ctx; addr: typeof input.addr };
|
|
8
|
+
let out = "";
|
|
9
|
+
out += "<section";
|
|
10
|
+
out += " class=\"";
|
|
11
|
+
out += "section section--latest-posts section--tone-";
|
|
12
|
+
out += escapeAttr(ctx.layout.tone);
|
|
13
|
+
out += "\"";
|
|
14
|
+
out += " data-block-id=\"";
|
|
15
|
+
out += escapeAttr(addr.blockId);
|
|
16
|
+
out += "\"";
|
|
17
|
+
out += " data-schema-address=\"";
|
|
18
|
+
out += escapeAttr(encodeSchemaAddress(addr));
|
|
19
|
+
out += "\"";
|
|
20
|
+
out += ">";
|
|
21
|
+
out += "<div";
|
|
22
|
+
out += " class=\"";
|
|
23
|
+
out += "container container--";
|
|
24
|
+
out += escapeAttr(ctx.layout.contentWidth);
|
|
25
|
+
out += "\"";
|
|
26
|
+
out += ">";
|
|
27
|
+
out += "<div";
|
|
28
|
+
out += " class=\"";
|
|
29
|
+
out += "section__header section__header--";
|
|
30
|
+
out += escapeAttr(ctx.layout.contentAlign);
|
|
31
|
+
out += "\"";
|
|
32
|
+
out += ">";
|
|
33
|
+
if (props.headline) {
|
|
34
|
+
out += "<h2";
|
|
35
|
+
out += " class=\"h2\"";
|
|
36
|
+
out += ">";
|
|
37
|
+
out += escapeHtml(props.headline);
|
|
38
|
+
out += "</h2>";
|
|
39
|
+
}
|
|
40
|
+
if (props.subheadline) {
|
|
41
|
+
out += "<p";
|
|
42
|
+
out += " class=\"text-body\"";
|
|
43
|
+
out += ">";
|
|
44
|
+
out += escapeHtml(props.subheadline);
|
|
45
|
+
out += "</p>";
|
|
46
|
+
}
|
|
47
|
+
out += "</div>";
|
|
48
|
+
out += "<div";
|
|
49
|
+
out += " class=\"grid grid--3\"";
|
|
50
|
+
out += ">";
|
|
51
|
+
for (const [i, post] of (props.posts).entries()) {
|
|
52
|
+
out += "<article";
|
|
53
|
+
out += " class=\"card card--post\"";
|
|
54
|
+
out += ">";
|
|
55
|
+
if (post.image) {
|
|
56
|
+
out += "<div";
|
|
57
|
+
out += " class=\"card__image\"";
|
|
58
|
+
out += ">";
|
|
59
|
+
out += "<img";
|
|
60
|
+
out += " loading=\"lazy\"";
|
|
61
|
+
out += " src=\"" + escapeAttr(post.image.src) + "\"";
|
|
62
|
+
out += " alt=\"" + escapeAttr(post.image.alt) + "\"";
|
|
63
|
+
out += ">";
|
|
64
|
+
out += "</div>";
|
|
65
|
+
}
|
|
66
|
+
out += "<div";
|
|
67
|
+
out += " class=\"card__body\"";
|
|
68
|
+
out += ">";
|
|
69
|
+
if (post.date) {
|
|
70
|
+
out += "<time";
|
|
71
|
+
out += " class=\"card__date\"";
|
|
72
|
+
out += ">";
|
|
73
|
+
out += escapeHtml(post.date);
|
|
74
|
+
out += "</time>";
|
|
75
|
+
}
|
|
76
|
+
out += "<h3";
|
|
77
|
+
out += " class=\"h3 card__title\"";
|
|
78
|
+
out += ">";
|
|
79
|
+
out += escapeHtml(post.title);
|
|
80
|
+
out += "</h3>";
|
|
81
|
+
if (post.excerpt) {
|
|
82
|
+
out += "<p";
|
|
83
|
+
out += " class=\"text-body card__excerpt\"";
|
|
84
|
+
out += ">";
|
|
85
|
+
out += escapeHtml(post.excerpt);
|
|
86
|
+
out += "</p>";
|
|
87
|
+
}
|
|
88
|
+
out += "<a";
|
|
89
|
+
out += " class=\"card__link\"";
|
|
90
|
+
out += " href=\"" + escapeAttr(post.link.href) + "\"";
|
|
91
|
+
out += ">";
|
|
92
|
+
out += escapeHtml(post.link.label);
|
|
93
|
+
out += "</a>";
|
|
94
|
+
out += "</div>";
|
|
95
|
+
out += "</article>";
|
|
96
|
+
}
|
|
97
|
+
out += "</div>";
|
|
98
|
+
if (props.viewAllLink) {
|
|
99
|
+
out += "<div";
|
|
100
|
+
out += " class=\"section__footer\"";
|
|
101
|
+
out += ">";
|
|
102
|
+
out += "<a";
|
|
103
|
+
out += " class=\"btn btn--secondary\"";
|
|
104
|
+
out += " href=\"" + escapeAttr(props.viewAllLink.href) + "\"";
|
|
105
|
+
out += ">";
|
|
106
|
+
out += escapeHtml(props.viewAllLink.label);
|
|
107
|
+
out += "</a>";
|
|
108
|
+
out += "</div>";
|
|
109
|
+
}
|
|
110
|
+
out += "</div>";
|
|
111
|
+
out += "</section>";
|
|
112
|
+
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Auto-generated - DO NOT EDIT
|
|
2
|
+
import { escapeHtml, escapeAttr, type RenderBlockInput } from "@static-block-kit/core";
|
|
3
|
+
import { encodeSchemaAddress } from "@static-block-kit/core";
|
|
4
|
+
|
|
5
|
+
export function renderTextSection(input: RenderBlockInput): string {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
const { props, ctx, addr } = input as { props: any; ctx: typeof input.ctx; addr: typeof input.addr };
|
|
8
|
+
let out = "";
|
|
9
|
+
out += "<section";
|
|
10
|
+
out += " class=\"";
|
|
11
|
+
out += "section section--text section--tone-";
|
|
12
|
+
out += escapeAttr(ctx.layout.tone);
|
|
13
|
+
out += "\"";
|
|
14
|
+
out += " data-block-id=\"";
|
|
15
|
+
out += escapeAttr(addr.blockId);
|
|
16
|
+
out += "\"";
|
|
17
|
+
out += " data-schema-address=\"";
|
|
18
|
+
out += escapeAttr(encodeSchemaAddress(addr));
|
|
19
|
+
out += "\"";
|
|
20
|
+
out += ">";
|
|
21
|
+
out += "<div";
|
|
22
|
+
out += " class=\"";
|
|
23
|
+
out += "container container--";
|
|
24
|
+
out += escapeAttr(ctx.layout.contentWidth);
|
|
25
|
+
out += "\"";
|
|
26
|
+
out += ">";
|
|
27
|
+
out += "<div";
|
|
28
|
+
out += " class=\"";
|
|
29
|
+
out += "text-section text-section--";
|
|
30
|
+
out += escapeAttr(ctx.layout.contentAlign);
|
|
31
|
+
out += "\"";
|
|
32
|
+
out += ">";
|
|
33
|
+
if (props.eyebrow) {
|
|
34
|
+
out += "<span";
|
|
35
|
+
out += " class=\"eyebrow\"";
|
|
36
|
+
out += ">";
|
|
37
|
+
out += escapeHtml(props.eyebrow);
|
|
38
|
+
out += "</span>";
|
|
39
|
+
}
|
|
40
|
+
if (props.headline) {
|
|
41
|
+
out += "<h2";
|
|
42
|
+
out += " class=\"h2\"";
|
|
43
|
+
out += ">";
|
|
44
|
+
out += escapeHtml(props.headline);
|
|
45
|
+
out += "</h2>";
|
|
46
|
+
}
|
|
47
|
+
out += "<div";
|
|
48
|
+
out += " class=\"prose\"";
|
|
49
|
+
out += ">";
|
|
50
|
+
out += props.body;
|
|
51
|
+
out += "</div>";
|
|
52
|
+
if (props.cta) {
|
|
53
|
+
out += "<div";
|
|
54
|
+
out += " class=\"text-section__cta\"";
|
|
55
|
+
out += ">";
|
|
56
|
+
out += "<a";
|
|
57
|
+
out += " class=\"btn btn--primary\"";
|
|
58
|
+
out += " href=\"" + escapeAttr(props.cta.href) + "\"";
|
|
59
|
+
out += ">";
|
|
60
|
+
out += escapeHtml(props.cta.label);
|
|
61
|
+
out += "</a>";
|
|
62
|
+
out += "</div>";
|
|
63
|
+
}
|
|
64
|
+
out += "</div>";
|
|
65
|
+
out += "</div>";
|
|
66
|
+
out += "</section>";
|
|
67
|
+
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<section
|
|
2
|
+
class="section section--hero section--tone-{{ ctx.layout.tone }}"
|
|
3
|
+
data-block-id="{{ addr.blockId }}"
|
|
4
|
+
data-schema-address="{{ encodeSchemaAddress(addr) }}"
|
|
5
|
+
>
|
|
6
|
+
<div class="container container--{{ ctx.layout.contentWidth }}">
|
|
7
|
+
<div class="hero__content hero__content--{{ ctx.layout.contentAlign }}">
|
|
8
|
+
<template v-if="props.eyebrow">
|
|
9
|
+
<span class="eyebrow">{{ props.eyebrow }}</span>
|
|
10
|
+
</template>
|
|
11
|
+
<h1 class="h1 hero__headline">{{ props.headline }}</h1>
|
|
12
|
+
<template v-if="props.subheadline">
|
|
13
|
+
<p class="text-body hero__subheadline">{{ props.subheadline }}</p>
|
|
14
|
+
</template>
|
|
15
|
+
<template v-if="props.primaryCta || props.secondaryCta">
|
|
16
|
+
<div class="hero__actions">
|
|
17
|
+
<template v-if="props.primaryCta">
|
|
18
|
+
<a class="btn btn--primary" :href="props.primaryCta.href">
|
|
19
|
+
{{ props.primaryCta.label }}
|
|
20
|
+
</a>
|
|
21
|
+
</template>
|
|
22
|
+
<template v-if="props.secondaryCta">
|
|
23
|
+
<a class="btn btn--secondary" :href="props.secondaryCta.href">
|
|
24
|
+
{{ props.secondaryCta.label }}
|
|
25
|
+
</a>
|
|
26
|
+
</template>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { defineBlock } from "@vojtaholik/static-kit-core";
|
|
3
|
+
import { renderHero } from "./gen/hero.render.ts";
|
|
4
|
+
|
|
5
|
+
export const heroPropsSchema = z.object({
|
|
6
|
+
eyebrow: z.string().optional(),
|
|
7
|
+
headline: z.string(),
|
|
8
|
+
subheadline: z.string().optional(),
|
|
9
|
+
primaryCta: z
|
|
10
|
+
.object({
|
|
11
|
+
href: z.string(),
|
|
12
|
+
label: z.string(),
|
|
13
|
+
external: z.boolean().optional(),
|
|
14
|
+
})
|
|
15
|
+
.optional(),
|
|
16
|
+
secondaryCta: z
|
|
17
|
+
.object({
|
|
18
|
+
href: z.string(),
|
|
19
|
+
label: z.string(),
|
|
20
|
+
external: z.boolean().optional(),
|
|
21
|
+
})
|
|
22
|
+
.optional(),
|
|
23
|
+
backgroundImage: z
|
|
24
|
+
.object({
|
|
25
|
+
src: z.string(),
|
|
26
|
+
alt: z.string(),
|
|
27
|
+
width: z.number().optional(),
|
|
28
|
+
height: z.number().optional(),
|
|
29
|
+
})
|
|
30
|
+
.optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export type HeroProps = z.infer<typeof heroPropsSchema>;
|
|
34
|
+
|
|
35
|
+
export const heroBlock = defineBlock({
|
|
36
|
+
type: "hero",
|
|
37
|
+
propsSchema: heroPropsSchema,
|
|
38
|
+
renderHtml: renderHero,
|
|
39
|
+
sourceFile: import.meta.url,
|
|
40
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Block exports
|
|
2
|
+
export { heroBlock, heroPropsSchema, type HeroProps } from "./hero.block.ts";
|
|
3
|
+
export {
|
|
4
|
+
featureGridBlock,
|
|
5
|
+
featureGridPropsSchema,
|
|
6
|
+
type FeatureGridProps,
|
|
7
|
+
} from "./feature-grid.block.ts";
|
|
8
|
+
export {
|
|
9
|
+
latestPostsBlock,
|
|
10
|
+
latestPostsPropsSchema,
|
|
11
|
+
type LatestPostsProps,
|
|
12
|
+
} from "./latest-posts.block.ts";
|
|
13
|
+
export {
|
|
14
|
+
textSectionBlock,
|
|
15
|
+
textSectionPropsSchema,
|
|
16
|
+
type TextSectionProps,
|
|
17
|
+
} from "./text-section.block.ts";
|
|
18
|
+
|
|
19
|
+
// Register all blocks
|
|
20
|
+
import { blockRegistry } from "@vojtaholik/static-kit-core";
|
|
21
|
+
import { heroBlock } from "./hero.block.ts";
|
|
22
|
+
import { featureGridBlock } from "./feature-grid.block.ts";
|
|
23
|
+
import { latestPostsBlock } from "./latest-posts.block.ts";
|
|
24
|
+
import { textSectionBlock } from "./text-section.block.ts";
|
|
25
|
+
|
|
26
|
+
export function registerAllBlocks() {
|
|
27
|
+
blockRegistry.register(heroBlock);
|
|
28
|
+
blockRegistry.register(featureGridBlock);
|
|
29
|
+
blockRegistry.register(latestPostsBlock);
|
|
30
|
+
blockRegistry.register(textSectionBlock);
|
|
31
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<section class="section section--latest-posts section--tone-{{ ctx.layout.tone }}" data-block-id="{{ addr.blockId }}" data-schema-address="{{ encodeSchemaAddress(addr) }}">
|
|
2
|
+
<div class="container container--{{ ctx.layout.contentWidth }}">
|
|
3
|
+
<div class="section__header section__header--{{ ctx.layout.contentAlign }}">
|
|
4
|
+
<template v-if="props.headline">
|
|
5
|
+
<h2 class="h2">{{ props.headline }}</h2>
|
|
6
|
+
</template>
|
|
7
|
+
<template v-if="props.subheadline">
|
|
8
|
+
<p class="text-body">{{ props.subheadline }}</p>
|
|
9
|
+
</template>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="grid grid--3">
|
|
12
|
+
<template v-for="post, i in props.posts">
|
|
13
|
+
<article class="card card--post">
|
|
14
|
+
<template v-if="post.image">
|
|
15
|
+
<div class="card__image">
|
|
16
|
+
<img :src="post.image.src" :alt="post.image.alt" loading="lazy">
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
<div class="card__body">
|
|
20
|
+
<template v-if="post.date">
|
|
21
|
+
<time class="card__date">{{ post.date }}</time>
|
|
22
|
+
</template>
|
|
23
|
+
<h3 class="h3 card__title">{{ post.title }}</h3>
|
|
24
|
+
<template v-if="post.excerpt">
|
|
25
|
+
<p class="text-body card__excerpt">{{ post.excerpt }}</p>
|
|
26
|
+
</template>
|
|
27
|
+
<a class="card__link" :href="post.link.href">{{ post.link.label }}</a>
|
|
28
|
+
</div>
|
|
29
|
+
</article>
|
|
30
|
+
</template>
|
|
31
|
+
</div>
|
|
32
|
+
<template v-if="props.viewAllLink">
|
|
33
|
+
<div class="section__footer">
|
|
34
|
+
<a class="btn btn--secondary" :href="props.viewAllLink.href">{{ props.viewAllLink.label }}</a>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|