@vojtaholik/create-static-kit 1.0.8 → 2.1.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.
Files changed (70) hide show
  1. package/package.json +6 -34
  2. package/src/index.ts +41 -0
  3. package/template/blocks/feature-grid.block.html +28 -0
  4. package/template/blocks/feature-grid.block.ts +32 -0
  5. package/template/blocks/gen/feature-grid.render.ts +92 -0
  6. package/template/blocks/gen/hero.render.ts +79 -0
  7. package/template/blocks/gen/index.ts +4 -0
  8. package/template/blocks/gen/latest-posts.render.ts +114 -0
  9. package/template/blocks/gen/text-section.render.ts +69 -0
  10. package/template/blocks/hero.block.html +31 -0
  11. package/template/blocks/hero.block.ts +40 -0
  12. package/template/blocks/index.ts +46 -0
  13. package/template/blocks/latest-posts.block.html +38 -0
  14. package/template/blocks/latest-posts.block.ts +45 -0
  15. package/template/blocks/text-section.block.html +18 -0
  16. package/template/blocks/text-section.block.ts +25 -0
  17. package/template/package.json +21 -0
  18. package/template/public/css/styles.css +589 -0
  19. package/template/public/js/dev-overlay.js +366 -0
  20. package/template/public/js/index.js +35 -0
  21. package/template/public/sprite.svg +6 -0
  22. package/template/public/svg/magic-wand.svg +4 -0
  23. package/template/site/pages/about.page.ts +91 -0
  24. package/template/site/pages/base.html +38 -0
  25. package/template/site/pages/index.page.ts +107 -0
  26. package/template/site/pages/index.ts +16 -0
  27. package/template/static-kit.config.ts +10 -0
  28. package/template/tsconfig.json +23 -0
  29. package/bin/create-static-kit.js +0 -3
  30. package/dist/cli.d.ts +0 -3
  31. package/dist/cli.d.ts.map +0 -1
  32. package/dist/cli.js +0 -488
  33. package/templates/default/.cursor/rules/configuration.mdc +0 -20
  34. package/templates/default/.cursor/rules/figma-integration.mdc +0 -22
  35. package/templates/default/.cursor/rules/html-components.mdc +0 -24
  36. package/templates/default/.cursor/rules/html-pages.mdc +0 -22
  37. package/templates/default/.cursor/rules/inline-tailwind-to-bem-with-apply-directive.mdc +0 -218
  38. package/templates/default/.cursor/rules/project-overview.mdc +0 -30
  39. package/templates/default/.cursor/rules/public-assets.mdc +0 -22
  40. package/templates/default/.cursor/rules/scss-styles.mdc +0 -22
  41. package/templates/default/.cursor/rules/svg-icons.mdc +0 -22
  42. package/templates/default/.cursor/rules/typescript-js.mdc +0 -23
  43. package/templates/default/public/favicon.ico +0 -1
  44. package/templates/default/src/components/button.html +0 -1
  45. package/templates/default/src/components/feature-card.html +0 -8
  46. package/templates/default/src/components/footer.html +0 -5
  47. package/templates/default/src/components/navigation.html +0 -11
  48. package/templates/default/src/icons/ui/star.svg +0 -3
  49. package/templates/default/src/js/index.ts +0 -28
  50. package/templates/default/src/pages/about.html +0 -24
  51. package/templates/default/src/pages/index.html +0 -23
  52. package/templates/default/src/styles/main.scss +0 -210
  53. package/templates/default/tsconfig.json +0 -19
  54. package/templates/minimal/.cursor/rules/configuration.mdc +0 -20
  55. package/templates/minimal/.cursor/rules/figma-integration.mdc +0 -22
  56. package/templates/minimal/.cursor/rules/html-components.mdc +0 -24
  57. package/templates/minimal/.cursor/rules/html-pages.mdc +0 -22
  58. package/templates/minimal/.cursor/rules/inline-tailwind-to-bem-with-apply-directive.mdc +0 -218
  59. package/templates/minimal/.cursor/rules/project-overview.mdc +0 -30
  60. package/templates/minimal/.cursor/rules/public-assets.mdc +0 -22
  61. package/templates/minimal/.cursor/rules/scss-styles.mdc +0 -22
  62. package/templates/minimal/.cursor/rules/svg-icons.mdc +0 -22
  63. package/templates/minimal/.cursor/rules/typescript-js.mdc +0 -23
  64. package/templates/minimal/public/favicon.ico +0 -1
  65. package/templates/minimal/src/components/footer.html +0 -3
  66. package/templates/minimal/src/components/header.html +0 -6
  67. package/templates/minimal/src/js/index.ts +0 -9
  68. package/templates/minimal/src/pages/index.html +0 -15
  69. package/templates/minimal/src/styles/main.scss +0 -77
  70. package/templates/minimal/tsconfig.json +0 -19
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Static Kit - Dev Overlay
3
+ *
4
+ * - Alt+click on any block to inspect its schema address
5
+ * - Hot reload via SSE connection
6
+ */
7
+
8
+ (function () {
9
+ "use strict";
10
+
11
+ // ==========================================================================
12
+ // Hot Reload Client
13
+ // ==========================================================================
14
+
15
+ var reconnectAttempts = 0;
16
+ var maxReconnectAttempts = 20;
17
+ var wasConnected = false;
18
+ var lastServerTime = null;
19
+
20
+ function connectHMR() {
21
+ var source = new EventSource("/__hmr");
22
+
23
+ source.onopen = function () {
24
+ console.log("[HMR] Connected");
25
+
26
+ // If we were previously connected and reconnected, reload
27
+ // This handles the case where the server restarted (--watch)
28
+ if (wasConnected) {
29
+ console.log("[HMR] Server restarted, reloading...");
30
+ window.location.reload();
31
+ return;
32
+ }
33
+
34
+ wasConnected = true;
35
+ reconnectAttempts = 0;
36
+ };
37
+
38
+ source.onmessage = function (event) {
39
+ try {
40
+ var data = JSON.parse(event.data);
41
+
42
+ if (data.type === "connected") {
43
+ // Store server start time to detect restarts
44
+ if (lastServerTime && data.time && lastServerTime !== data.time) {
45
+ console.log("[HMR] Server restarted, reloading...");
46
+ window.location.reload();
47
+ }
48
+ lastServerTime = data.time;
49
+ return;
50
+ }
51
+
52
+ if (data.type === "css") {
53
+ // Hot reload CSS and SVG sprites without full page refresh
54
+ reloadCSS();
55
+ reloadSVGSprites();
56
+ } else if (data.type === "full") {
57
+ // Full page reload
58
+ console.log("[HMR] Reloading...");
59
+ window.location.reload();
60
+ }
61
+ } catch (e) {
62
+ console.error("[HMR] Failed to parse message:", e);
63
+ }
64
+ };
65
+
66
+ source.onerror = function () {
67
+ source.close();
68
+ reconnectAttempts++;
69
+
70
+ if (reconnectAttempts <= maxReconnectAttempts) {
71
+ // Quick reconnects at first, then slower
72
+ var delay =
73
+ reconnectAttempts < 3 ? 100 : Math.min(500 * reconnectAttempts, 3000);
74
+ console.log("[HMR] Disconnected, reconnecting in " + delay + "ms...");
75
+ setTimeout(connectHMR, delay);
76
+ } else {
77
+ console.log(
78
+ "[HMR] Max reconnection attempts reached. Refresh manually."
79
+ );
80
+ }
81
+ };
82
+ }
83
+
84
+ function reloadCSS() {
85
+ var links = document.querySelectorAll('link[rel="stylesheet"]');
86
+ var reloaded = 0;
87
+
88
+ links.forEach(function (link) {
89
+ var href = link.href;
90
+ if (!href) return;
91
+
92
+ // Add cache-busting query param
93
+ var url = new URL(href);
94
+ url.searchParams.set("_hmr", Date.now());
95
+
96
+ // Create new link element
97
+ var newLink = document.createElement("link");
98
+ newLink.rel = "stylesheet";
99
+ newLink.href = url.toString();
100
+
101
+ newLink.onload = function () {
102
+ link.remove();
103
+ reloaded++;
104
+ if (reloaded === links.length) {
105
+ console.log("[HMR] CSS reloaded");
106
+ }
107
+ };
108
+
109
+ newLink.onerror = function () {
110
+ console.error("[HMR] Failed to reload CSS:", href);
111
+ };
112
+
113
+ link.parentNode.insertBefore(newLink, link.nextSibling);
114
+ });
115
+ }
116
+
117
+ function reloadSVGSprites() {
118
+ // Find all <use> elements referencing sprite files
119
+ var uses = document.querySelectorAll("use[href*='sprite']");
120
+ if (uses.length === 0) return;
121
+
122
+ var timestamp = Date.now();
123
+ uses.forEach(function (use) {
124
+ var href = use.getAttribute("href");
125
+ if (!href) return;
126
+
127
+ // Parse href and add cache-busting param
128
+ var hashIndex = href.indexOf("#");
129
+ var path = hashIndex > -1 ? href.slice(0, hashIndex) : href;
130
+ var fragment = hashIndex > -1 ? href.slice(hashIndex) : "";
131
+
132
+ // Strip existing _hmr param if present
133
+ var cleanPath = path.replace(/[?&]_hmr=\d+/, "");
134
+ var separator = cleanPath.indexOf("?") > -1 ? "&" : "?";
135
+ var newHref = cleanPath + separator + "_hmr=" + timestamp + fragment;
136
+
137
+ use.setAttribute("href", newHref);
138
+ });
139
+
140
+ console.log("[HMR] SVG sprites reloaded (" + uses.length + " refs)");
141
+ }
142
+
143
+ // Start HMR connection
144
+ connectHMR();
145
+
146
+ // ==========================================================================
147
+ // Block Inspector
148
+ // ==========================================================================
149
+
150
+ var overlay = null;
151
+
152
+ function createOverlay() {
153
+ var el = document.createElement("div");
154
+ el.id = "static-kit-dev-overlay";
155
+ el.innerHTML = [
156
+ "<style>",
157
+ "#static-kit-dev-overlay {",
158
+ " position: fixed;",
159
+ " z-index: 99999;",
160
+ " background: #1a1a2e;",
161
+ " color: #fff;",
162
+ " padding: 16px;",
163
+ " border-radius: 8px;",
164
+ " font-family: ui-monospace, monospace;",
165
+ " font-size: 13px;",
166
+ " line-height: 1.5;",
167
+ " max-width: 480px;",
168
+ " box-shadow: 0 10px 40px rgba(0,0,0,0.3);",
169
+ " display: none;",
170
+ "}",
171
+ "#static-kit-dev-overlay.visible { display: block; }",
172
+ "#static-kit-dev-overlay h4 {",
173
+ " margin: 0 0 12px;",
174
+ " font-size: 14px;",
175
+ " font-weight: 600;",
176
+ " color: #6366f1;",
177
+ "}",
178
+ "#static-kit-dev-overlay dl {",
179
+ " margin: 0;",
180
+ " display: grid;",
181
+ " grid-template-columns: auto 1fr;",
182
+ " gap: 4px 12px;",
183
+ "}",
184
+ "#static-kit-dev-overlay dt {",
185
+ " color: #9ca3af;",
186
+ "}",
187
+ "#static-kit-dev-overlay dd {",
188
+ " margin: 0;",
189
+ " word-break: break-all;",
190
+ "}",
191
+ "#static-kit-dev-overlay a {",
192
+ " color: #818cf8;",
193
+ " text-decoration: none;",
194
+ " display: inline-flex;",
195
+ " align-items: center;",
196
+ " gap: 4px;",
197
+ "}",
198
+ "#static-kit-dev-overlay a:hover {",
199
+ " color: #a5b4fc;",
200
+ " text-decoration: underline;",
201
+ "}",
202
+ "#static-kit-dev-overlay .file-links {",
203
+ " margin-top: 12px;",
204
+ " padding-top: 12px;",
205
+ " border-top: 1px solid #374151;",
206
+ " display: flex;",
207
+ " flex-direction: column;",
208
+ " gap: 6px;",
209
+ "}",
210
+ "#static-kit-dev-overlay .close-btn {",
211
+ " position: absolute;",
212
+ " top: 8px;",
213
+ " right: 8px;",
214
+ " background: none;",
215
+ " border: none;",
216
+ " color: #9ca3af;",
217
+ " cursor: pointer;",
218
+ " padding: 4px;",
219
+ " font-size: 16px;",
220
+ "}",
221
+ "#static-kit-dev-overlay .close-btn:hover { color: #fff; }",
222
+ "#static-kit-dev-overlay .loading {",
223
+ " color: #9ca3af;",
224
+ " font-style: italic;",
225
+ "}",
226
+ "[data-schema-address] { position: relative; }",
227
+ "[data-schema-address].inspecting {",
228
+ " outline: 2px dashed #6366f1;",
229
+ " outline-offset: 2px;",
230
+ "}",
231
+ "</style>",
232
+ '<button class="close-btn" aria-label="Close">&times;</button>',
233
+ "<h4>Block Inspector</h4>",
234
+ "<dl></dl>",
235
+ '<div class="file-links"></div>',
236
+ ].join("\n");
237
+ document.body.appendChild(el);
238
+
239
+ el.querySelector(".close-btn").addEventListener("click", hideOverlay);
240
+
241
+ return el;
242
+ }
243
+
244
+ function makeCursorLink(filePath, label) {
245
+ if (!filePath) return '<span style="color:#6b7280">-</span>';
246
+ // cursor://file/absolute/path
247
+ var href = "cursor://file" + filePath;
248
+ var shortPath = filePath.split("/").slice(-2).join("/");
249
+ return (
250
+ '<a href="' +
251
+ href +
252
+ '" title="' +
253
+ filePath +
254
+ '">' +
255
+ (label || shortPath) +
256
+ " ↗</a>"
257
+ );
258
+ }
259
+
260
+ async function showOverlay(blockEl, x, y) {
261
+ if (!overlay) {
262
+ overlay = createOverlay();
263
+ }
264
+
265
+ var address = blockEl.getAttribute("data-schema-address");
266
+ var blockId = blockEl.getAttribute("data-block-id");
267
+ var parts = address ? address.split("::") : [];
268
+
269
+ // Remove previous inspecting class
270
+ var prev = document.querySelector(".inspecting");
271
+ if (prev) prev.classList.remove("inspecting");
272
+ blockEl.classList.add("inspecting");
273
+
274
+ // Position overlay
275
+ overlay.style.top = Math.min(y + 10, window.innerHeight - 200) + "px";
276
+ overlay.style.left = Math.min(x + 10, window.innerWidth - 500) + "px";
277
+ overlay.classList.add("visible");
278
+
279
+ var dl = overlay.querySelector("dl");
280
+ var fileLinks = overlay.querySelector(".file-links");
281
+
282
+ // Show loading state
283
+ dl.innerHTML = [
284
+ "<dt>Page</dt><dd>" + (parts[0] || "-") + "</dd>",
285
+ "<dt>Region</dt><dd>" + (parts[1] || "-") + "</dd>",
286
+ "<dt>Block ID</dt><dd>" + (blockId || "-") + "</dd>",
287
+ ].join("");
288
+ fileLinks.innerHTML = '<span class="loading">Loading...</span>';
289
+
290
+ // Fetch full info from server
291
+ try {
292
+ var res = await fetch(
293
+ "/__inspect?address=" + encodeURIComponent(address)
294
+ );
295
+ var data = await res.json();
296
+
297
+ if (data.error) {
298
+ fileLinks.innerHTML =
299
+ '<span style="color:#ef4444">' + data.error + "</span>";
300
+ return;
301
+ }
302
+
303
+ dl.innerHTML = [
304
+ "<dt>Block Type</dt><dd><strong>" +
305
+ (data.block?.type || "-") +
306
+ "</strong></dd>",
307
+ "<dt>Page</dt><dd>" + (data.page?.id || "-") + "</dd>",
308
+ "<dt>Region</dt><dd>" + (data.address?.region || "-") + "</dd>",
309
+ "<dt>Block ID</dt><dd>" + (data.block?.id || "-") + "</dd>",
310
+ ].join("");
311
+
312
+ fileLinks.innerHTML =
313
+ [
314
+ data.block?.sourceFile
315
+ ? makeCursorLink(data.block.sourceFile, "📦 Block Source")
316
+ : "",
317
+ data.block?.templateFile
318
+ ? makeCursorLink(data.block.templateFile, "📄 Template")
319
+ : "",
320
+ data.page?.sourceFile
321
+ ? makeCursorLink(data.page.sourceFile, "📄 Page Config")
322
+ : "",
323
+ ]
324
+ .filter(Boolean)
325
+ .join("") ||
326
+ '<span style="color:#6b7280">No source files found</span>';
327
+ } catch (err) {
328
+ fileLinks.innerHTML = '<span style="color:#ef4444">Failed to load</span>';
329
+ console.error("[Inspector] Failed to fetch:", err);
330
+ }
331
+ }
332
+
333
+ function hideOverlay() {
334
+ if (overlay) {
335
+ overlay.classList.remove("visible");
336
+ }
337
+ var prev = document.querySelector(".inspecting");
338
+ if (prev) prev.classList.remove("inspecting");
339
+ }
340
+
341
+ // Alt+click handler
342
+ document.addEventListener("click", function (e) {
343
+ if (!e.altKey) {
344
+ hideOverlay();
345
+ return;
346
+ }
347
+
348
+ e.preventDefault();
349
+ e.stopPropagation();
350
+
351
+ // Find closest block element
352
+ var blockEl = e.target.closest("[data-schema-address]");
353
+ if (blockEl) {
354
+ showOverlay(blockEl, e.clientX, e.clientY);
355
+ }
356
+ });
357
+
358
+ // ESC to close
359
+ document.addEventListener("keydown", function (e) {
360
+ if (e.key === "Escape") {
361
+ hideOverlay();
362
+ }
363
+ });
364
+
365
+ console.log("Static Kit Dev Overlay loaded. Alt+click on blocks to inspect.");
366
+ })();
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Static Kit - Client Runtime
3
+ *
4
+ * Minimal ES5-compatible enhancement script.
5
+ * Add interactive behaviors here as needed.
6
+ */
7
+
8
+ (function () {
9
+ "use strict";
10
+
11
+ // Smooth scroll for anchor links
12
+ document.addEventListener("click", function (e) {
13
+ var target = e.target;
14
+ if (target.tagName === "A" && target.hash) {
15
+ var element = document.querySelector(target.hash);
16
+ if (element) {
17
+ e.preventDefault();
18
+ element.scrollIntoView({ behavior: "smooth" });
19
+ history.pushState(null, null, target.hash);
20
+ }
21
+ }
22
+ });
23
+
24
+ // Mark external links
25
+ var links = document.querySelectorAll('a[href^="http"]');
26
+ for (var i = 0; i < links.length; i++) {
27
+ var link = links[i];
28
+ if (link.hostname !== window.location.hostname) {
29
+ link.setAttribute("target", "_blank");
30
+ link.setAttribute("rel", "noopener noreferrer");
31
+ }
32
+ }
33
+
34
+ console.log("Static Kit initialized");
35
+ })();
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none;">
2
+ <symbol id="magic-wand" viewBox="0 0 24 24">
3
+ <path stroke="#141B34" stroke-linejoin="round" stroke-width="1.5" d="m10.938 11.077-7.527 7.528a1.403 1.403 0 1 0 1.985 1.984l7.527-7.527m-1.985-1.985 1.985 1.985m-1.985-1.985.744-.744m1.24 2.729.745-.744m-1.985-1.985.043-.042a.992.992 0 0 1 1.403 0l.581.58a.992.992 0 0 1 0 1.404l-.042.043m-1.985-1.985 1.985 1.985m4.571-9.151a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Z"/>
4
+ <path stroke="#141B34" stroke-linejoin="round" stroke-width="1.5" d="M18.238 14.167a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Zm-11-11a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Z" opacity=".4"/>
5
+ </symbol>
6
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
2
+ <path stroke="#141B34" stroke-linejoin="round" stroke-width="1.5" d="m10.938 11.077-7.527 7.528a1.403 1.403 0 1 0 1.985 1.984l7.527-7.527m-1.985-1.985 1.985 1.985m-1.985-1.985.744-.744m1.24 2.729.745-.744m-1.985-1.985.043-.042a.992.992 0 0 1 1.403 0l.581.58a.992.992 0 0 1 0 1.404l-.042.043m-1.985-1.985 1.985 1.985m4.571-9.151a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Z"/>
3
+ <path stroke="#141B34" stroke-linejoin="round" stroke-width="1.5" d="M18.238 14.167a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Zm-11-11a.29.29 0 0 1 .524 0l.392.84c.173.37.47.666.84.839l.839.392a.29.29 0 0 1 0 .524l-.84.392c-.37.173-.666.47-.839.84l-.392.839a.29.29 0 0 1-.524 0l-.392-.84a1.737 1.737 0 0 0-.84-.839l-.839-.392a.29.29 0 0 1 0-.524l.84-.392c.37-.173.666-.47.839-.84l.392-.839Z" opacity=".4"/>
4
+ </svg>
@@ -0,0 +1,91 @@
1
+ import type { PageConfig } from "@vojtaholik/static-kit-core";
2
+
3
+ export const aboutPage: PageConfig = {
4
+ id: "about",
5
+ path: "/about",
6
+ title: "About Static Kit",
7
+ template: "base.html",
8
+ density: "comfortable",
9
+ regions: {
10
+ main: {
11
+ blocks: [
12
+ {
13
+ id: "hero-about",
14
+ type: "hero",
15
+ props: {
16
+ eyebrow: "About",
17
+ headline: "The Philosophy Behind Static Kit",
18
+ subheadline:
19
+ "We believe static sites should be fast, maintainable, and a joy to build.",
20
+ },
21
+ layout: {
22
+ tone: "surface",
23
+ contentAlign: "center",
24
+ contentWidth: "narrow",
25
+ },
26
+ },
27
+ {
28
+ id: "text-mission",
29
+ type: "textSection",
30
+ props: {
31
+ eyebrow: "Our Mission",
32
+ headline: "Simplicity Without Sacrifice",
33
+ body: `
34
+ <p>Static Kit was born from frustration with modern web development complexity. We wanted a tool that:</p>
35
+ <ul>
36
+ <li>Produces fast, accessible websites by default</li>
37
+ <li>Doesn't require a JavaScript framework for content sites</li>
38
+ <li>Makes content management intuitive for developers and content editors</li>
39
+ <li>Stays out of your way while providing powerful abstractions</li>
40
+ </ul>
41
+ <p>The result is a static site generator that embraces HTML as the output format, TypeScript for type safety, and a simple block-based architecture that scales from landing pages to large marketing sites.</p>
42
+ `,
43
+ },
44
+ layout: {
45
+ tone: "surface",
46
+ contentAlign: "left",
47
+ contentWidth: "narrow",
48
+ },
49
+ },
50
+ {
51
+ id: "features-principles",
52
+ type: "featureGrid",
53
+ props: {
54
+ headline: "Core Principles",
55
+ columns: "2",
56
+ features: [
57
+ {
58
+ icon: "📄",
59
+ title: "HTML First",
60
+ description:
61
+ "The web is built on HTML. We generate semantic, accessible markup that works everywhere.",
62
+ },
63
+ {
64
+ icon: "🔒",
65
+ title: "Type Safety",
66
+ description:
67
+ "Every block prop, every page config, every template expression is type-checked.",
68
+ },
69
+ {
70
+ icon: "🎯",
71
+ title: "Zero Runtime",
72
+ description:
73
+ "No framework JavaScript shipped to users. Add interactivity only where you need it.",
74
+ },
75
+ {
76
+ icon: "🔌",
77
+ title: "CMS Agnostic",
78
+ description:
79
+ "Your content schemas work with any headless CMS. We don't lock you in.",
80
+ },
81
+ ],
82
+ },
83
+ layout: {
84
+ tone: "raised",
85
+ contentAlign: "center",
86
+ },
87
+ },
88
+ ],
89
+ },
90
+ },
91
+ };
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>JAP</title>
7
+ <link rel="stylesheet" href="public/css/styles.css" />
8
+ </head>
9
+ <body>
10
+ <header class="site-header">
11
+ <nav class="container">
12
+ <a href="/" class="site-header__logo">
13
+ <svg width="24" height="24">
14
+ <use href="public/sprite.svg#magic-wand"></use>
15
+ </svg>
16
+ Static Kit
17
+ </a>
18
+ <div class="site-header__nav">
19
+ <a href="/">Home</a>
20
+ <a href="/about">About</a>
21
+ <a href="/blog">Blog</a>
22
+ </div>
23
+ </nav>
24
+ </header>
25
+
26
+ <main data-region="main">
27
+ <!-- Blocks render here -->
28
+ </main>
29
+
30
+ <footer class="site-footer">
31
+ <div class="container">
32
+ <p>&copy; 2024 Static Kit. Built with static-block-kit.</p>
33
+ </div>
34
+ </footer>
35
+
36
+ <script src="public/js/index.js"></script>
37
+ </body>
38
+ </html>
@@ -0,0 +1,107 @@
1
+ import type { PageConfig } from "@vojtaholik/static-kit-core";
2
+
3
+ export const indexPage: PageConfig = {
4
+ id: "home",
5
+ path: "/",
6
+ title: "JAP",
7
+ template: "base.html",
8
+ density: "comfortable",
9
+ regions: {
10
+ main: {
11
+ blocks: [
12
+ {
13
+ id: "hero-1",
14
+ type: "hero",
15
+ props: {
16
+ eyebrow: "Introducing Static Kit",
17
+ headline: "Build Beautiful Static Sites",
18
+ subheadline:
19
+ "A modern static site generator with block-based content management and a Vue-like template DSL.",
20
+ primaryCta: {
21
+ href: "/docs/getting-started",
22
+ label: "Get Started",
23
+ },
24
+ secondaryCta: {
25
+ href: "/about",
26
+ label: "Learn More",
27
+ },
28
+ },
29
+ layout: {
30
+ tone: "accent",
31
+ contentAlign: "center",
32
+ contentWidth: "narrow",
33
+ },
34
+ },
35
+ {
36
+ id: "features-1",
37
+ type: "featureGrid",
38
+ props: {
39
+ headline: "Why Static Kit?",
40
+ subheadline:
41
+ "Everything you need to build fast, maintainable static sites.",
42
+ columns: "3",
43
+ features: [
44
+ {
45
+ icon: "⚡",
46
+ title: "Lightning Fast",
47
+ description:
48
+ "Pre-rendered HTML with zero JavaScript by default. Your pages load instantly.",
49
+ },
50
+ {
51
+ icon: "🧱",
52
+ title: "Block-Based",
53
+ description:
54
+ "Compose pages from reusable blocks with type-safe props and CMS-ready schemas.",
55
+ },
56
+ {
57
+ icon: "🎨",
58
+ title: "Design System Ready",
59
+ description:
60
+ "Built-in layout primitives and design tokens. Customize everything with CSS.",
61
+ },
62
+ {
63
+ icon: "📝",
64
+ title: "CMS Compatible",
65
+ description:
66
+ "Export your content schemas for use with any headless CMS.",
67
+ },
68
+ {
69
+ icon: "🔧",
70
+ title: "Developer Experience",
71
+ description:
72
+ "Hot reload, TypeScript everywhere, and a simple mental model.",
73
+ },
74
+ {
75
+ icon: "🚀",
76
+ title: "Deploy Anywhere",
77
+ description:
78
+ "Output is plain HTML/CSS/JS. Deploy to any static host.",
79
+ },
80
+ ],
81
+ },
82
+ layout: {
83
+ tone: "surface",
84
+ contentAlign: "center",
85
+ },
86
+ },
87
+ {
88
+ id: "cta-1",
89
+ type: "textSection",
90
+ props: {
91
+ headline: "Ready to build?",
92
+ body: "<p>Get started with Static Kit in minutes. Install the CLI, create a new project, and start building beautiful static sites.</p>",
93
+ cta: {
94
+ href: "/docs/getting-started",
95
+ label: "Read the Docs",
96
+ },
97
+ },
98
+ layout: {
99
+ tone: "raised",
100
+ contentAlign: "center",
101
+ contentWidth: "narrow",
102
+ },
103
+ },
104
+ ],
105
+ },
106
+ },
107
+ };
@@ -0,0 +1,16 @@
1
+ import type { PageConfig } from "@vojtaholik/static-kit-core";
2
+ import { indexPage } from "./index.page.ts";
3
+ import { aboutPage } from "./about.page.ts";
4
+
5
+ // All pages in the site
6
+ export const pages: PageConfig[] = [indexPage, aboutPage];
7
+
8
+ // Get page by path
9
+ export function getPageByPath(path: string): PageConfig | undefined {
10
+ return pages.find((p) => p.path === path);
11
+ }
12
+
13
+ // Get page by id
14
+ export function getPageById(id: string): PageConfig | undefined {
15
+ return pages.find((p) => p.id === id);
16
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "@vojtaholik/static-kit-core";
2
+
3
+ export default defineConfig({
4
+ blocksDir: "blocks",
5
+ pagesDir: "site/pages",
6
+ publicDir: "public",
7
+ outDir: "dist",
8
+ publicPath: "/public",
9
+ devPort: 3000,
10
+ });