@homepages/template-kit 0.8.1-dev-20260718224903 → 0.9.0-dev-20260719224319
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/CHANGELOG.md +61 -1
- package/README.md +2 -2
- package/dist/canvas-core/chrome-css.d.ts +24 -0
- package/dist/canvas-core/chrome-css.js +403 -0
- package/dist/canvas-core/chrome.d.ts +49 -0
- package/dist/canvas-core/chrome.js +147 -0
- package/dist/canvas-core/frame.d.ts +20 -0
- package/dist/canvas-core/frame.js +23 -0
- package/dist/canvas-core/hidden-tabs.d.ts +16 -0
- package/dist/canvas-core/hidden-tabs.js +84 -0
- package/dist/canvas-core/resolve-target.js +55 -0
- package/dist/canvas-core/scroll.d.ts +10 -0
- package/dist/canvas-core/scroll.js +15 -0
- package/dist/canvas-core/section-dom.d.ts +6 -0
- package/dist/canvas-core/section-dom.js +43 -0
- package/dist/canvas-core/srcdoc.d.ts +8 -0
- package/dist/canvas-core/srcdoc.js +77 -0
- package/dist/canvas-core/types.d.ts +76 -0
- package/dist/canvas-core.d.ts +9 -0
- package/dist/canvas-core.js +9 -0
- package/dist/cli/check/css.js +2 -2
- package/dist/cli/check/loader.js +1 -1
- package/dist/cli/check/stages/deps.js +1 -1
- package/dist/cli/check/stages/render.js +3 -2
- package/dist/cli/check/stages/size.js +2 -2
- package/dist/cli/check/stages/tree.js +1 -1
- package/dist/cli/check/stages/validate/index.js +1 -1
- package/dist/cli/check/stages/validate/nav-contract.js +4 -3
- package/dist/cli/check/stages/validate/orchestrator.js +1 -1
- package/dist/cli/check/workspace.js +2 -2
- package/dist/cli/dev/build-css.js +1 -1
- package/dist/cli/dev/discover.js +2 -2
- package/dist/cli/dev/inspect.js +1 -1
- package/dist/cli/dev/island-bootstrap.js +1 -1
- package/dist/cli/dev/island-canvas-bootstrap.js +37 -5
- package/dist/cli/dev/section-page.js +1 -1
- package/dist/cli/dev/server.js +12 -5
- package/dist/cli/dev/tailwind.js +1 -1
- package/dist/cli/dev/tsconfig-paths-plugin.js +1 -1
- package/dist/cli/dev/workspace.js +2 -2
- package/dist/cli/link/index.js +1 -1
- package/dist/cli/link/overlay.js +1 -1
- package/dist/cli/new/emit.js +1 -1
- package/dist/cli/new/index.js +1 -1
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +4 -4
- package/dist/cli/new/scaffold-assets.js +2 -2
- package/dist/cli/pack/collect.js +1 -1
- package/dist/cli/pack/guards.js +1 -1
- package/dist/cli/pack/index.js +1 -1
- package/dist/cli/theme/generate.js +1 -1
- package/dist/cli/theme/load-theme.js +1 -1
- package/dist/dev-client/assets/index-CJa9G1Na.css +1 -0
- package/dist/dev-client/assets/index-C_1atZs4.js +450 -0
- package/dist/dev-client/index.html +2 -2
- package/dist/fixtures/sample-property.d.ts +4 -7
- package/dist/fixtures/sample-property.js +41 -97
- package/dist/fixtures/scenario.d.ts +1 -1
- package/dist/fixtures/scenarios/for-rent-condo.js +24 -44
- package/dist/fixtures/scenarios/luxury-multi-unit.js +1 -1
- package/dist/fixtures/scenarios/sparse-single-family.js +14 -26
- package/dist/fixtures.d.ts +2 -2
- package/dist/fixtures.js +1 -2
- package/dist/islands/client-directive.d.ts +7 -0
- package/dist/{eslint/is-client-file.js → islands/client-directive.js} +6 -3
- package/dist/islands/detect.d.ts +1 -1
- package/dist/islands/detect.js +1 -1
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.js +1 -1
- package/dist/manifest.json +940 -0
- package/dist/media/pack.d.ts +49 -0
- package/dist/media/pack.js +69 -0
- package/dist/media/resolve-fixture-media.js +73 -0
- package/dist/media/resolve-media.js +195 -0
- package/dist/package.js +1 -1
- package/dist/rules.d.ts +176 -0
- package/dist/rules.js +209 -0
- package/dist/schema/property-facts.d.ts +2 -2
- package/dist/ssr.d.ts +14 -2
- package/dist/ssr.js +28 -13
- package/dist/tokens.css +21 -0
- package/guide/INDEX.md +2 -2
- package/guide/check.md +5 -5
- package/guide/dev.md +39 -30
- package/guide/eslint.md +13 -10
- package/guide/llms.txt +4 -3
- package/guide/quickstart.md +1 -1
- package/guide/recipes/image-slot-crop.md +6 -6
- package/guide/recipes/pick-a-scenario.md +13 -5
- package/guide/rules/INDEX.md +3 -2
- package/guide/schema-system.md +36 -12
- package/guide/upgrading.md +18 -2
- package/package.json +8 -4
- package/tsconfig.json +1 -1
- package/dist/dev-client/assets/index-3Gn34X_P.js +0 -50
- package/dist/dev-client/assets/index-DxQeiHfu.css +0 -1
- package/dist/eslint/is-client-file.d.ts +0 -4
- package/dist/eslint/rules/image-bare-needs-reason.js +0 -43
- package/dist/eslint/rules/no-client-directive-in-contract.js +0 -31
- package/dist/eslint/rules/no-client-runtime-in-server.js +0 -103
- package/dist/eslint/rules/no-css-import-from-render-path.js +0 -29
- package/dist/eslint/rules/no-hex.js +0 -188
- package/dist/eslint/rules/no-inline-style.js +0 -27
- package/dist/eslint/rules/no-nondeterminism.js +0 -48
- package/dist/eslint/rules/no-raw-element.js +0 -38
- package/dist/eslint/rules/props-from-schema.js +0 -37
- package/dist/eslint/rules/require-island-editor.js +0 -74
- package/dist/eslint/rules/serializable-island-props.js +0 -112
- package/dist/eslint/rules/slot-marker-literal.js +0 -38
- package/dist/eslint.d.ts +0 -6
- package/dist/eslint.js +0 -80
- package/dist/rules/registry.js +0 -16
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FixtureModuleShape, buildInvariantFixtures } from "../../../schema/fixture-schema.js";
|
|
2
2
|
import { loadSection } from "../loader.js";
|
|
3
|
+
import { resolveFixtureSetMedia } from "../../../media/resolve-fixture-media.js";
|
|
3
4
|
import { flattenLayout } from "../../../schema/rows.js";
|
|
4
5
|
import { renderSectionHtml } from "../../../ssr.js";
|
|
5
6
|
import { checkRenderInvariants } from "../render-invariants.js";
|
|
@@ -50,11 +51,11 @@ async function renderStage(workspaceRoot, template) {
|
|
|
50
51
|
let fixtures;
|
|
51
52
|
try {
|
|
52
53
|
loaded = await loadSection(workspaceRoot, section);
|
|
53
|
-
fixtures = buildInvariantFixtures({
|
|
54
|
+
fixtures = resolveFixtureSetMedia(buildInvariantFixtures({
|
|
54
55
|
schema: loaded.schema,
|
|
55
56
|
module: FixtureModuleShape.parse(loaded.fixtures),
|
|
56
57
|
selfAnchor: section.name
|
|
57
|
-
});
|
|
58
|
+
}));
|
|
58
59
|
} catch {
|
|
59
60
|
continue;
|
|
60
61
|
}
|
|
@@ -2,9 +2,9 @@ import { loadEsbuild } from "../resolve-tool.js";
|
|
|
2
2
|
import { ASSET_LOADERS, ASSET_NAMES, ASSET_PUBLIC_PATH, compileSectionPackageCss, sectionCssFiles } from "../css.js";
|
|
3
3
|
import { CHECK_CONFIG } from "../config.js";
|
|
4
4
|
import { findSectionIslands } from "../../../islands/discover.js";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { basename, join, relative } from "node:path";
|
|
7
5
|
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { basename, join, relative } from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
8
|
import { gzipSync } from "node:zlib";
|
|
9
9
|
|
|
10
10
|
//#region src/cli/check/stages/size.ts
|
|
@@ -2,8 +2,8 @@ import { ASSET_LOADERS, findImportLine, sectionCssFiles } from "../css.js";
|
|
|
2
2
|
import { CONTRACT_FILES, loadSection } from "../loader.js";
|
|
3
3
|
import { flattenLayout } from "../../../schema/rows.js";
|
|
4
4
|
import { referencedSectionAssets } from "../section-assets.js";
|
|
5
|
-
import { extname, join, relative } from "node:path";
|
|
6
5
|
import { readFile, readdir } from "node:fs/promises";
|
|
6
|
+
import { extname, join, relative } from "node:path";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/check/stages/tree.ts
|
|
9
9
|
const ASSET_EXTENSIONS = new Set(Object.keys(ASSET_LOADERS));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MissingContractFile, MissingSectionExport, loadSection } from "../../loader.js";
|
|
2
2
|
import { relativizePaths } from "../../relativize.js";
|
|
3
3
|
import { validateFixtureModule, validateOneSection, validateTemplateManifest } from "./orchestrator.js";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
6
|
|
|
7
7
|
//#region src/cli/check/stages/validate/index.ts
|
|
8
8
|
async function validateStage(workspaceRoot, template) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { FixtureModuleShape, buildFixtureSet } from "../../../../schema/fixture-schema.js";
|
|
2
2
|
import { TemplateManifest } from "../../../../schema/manifest.js";
|
|
3
3
|
import { loadSection } from "../../loader.js";
|
|
4
|
+
import { resolveFixtureSetMedia } from "../../../../media/resolve-fixture-media.js";
|
|
4
5
|
import { renderSectionHtml } from "../../../../ssr.js";
|
|
5
6
|
import { resolveSectionRef } from "../../../../schema/resolve-section-ref.js";
|
|
6
7
|
import { materializeSection } from "./orchestrator.js";
|
|
7
8
|
import { resolveAnchorMap } from "../../../../schema/section-nav.js";
|
|
8
|
-
import { join } from "node:path";
|
|
9
9
|
import { readFile } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
10
11
|
|
|
11
12
|
//#region src/cli/check/stages/validate/nav-contract.ts
|
|
12
13
|
const ALLOWED_EXTERNAL_ANCHORS = ["#privacy-policy"];
|
|
@@ -68,11 +69,11 @@ async function assertNavContract(workspaceRoot, template) {
|
|
|
68
69
|
let html = "";
|
|
69
70
|
for (const section of composed) {
|
|
70
71
|
const { anchor, schema } = materializedByName.get(section.name);
|
|
71
|
-
const base = buildFixtureSet({
|
|
72
|
+
const base = resolveFixtureSetMedia(buildFixtureSet({
|
|
72
73
|
schema,
|
|
73
74
|
module: FixtureModuleShape.parse(fixturesByName.get(section.name)),
|
|
74
75
|
selfAnchor: anchor
|
|
75
|
-
}).find((f) => f.id === "typical");
|
|
76
|
+
})).find((f) => f.id === "typical");
|
|
76
77
|
if (!base) throw new Error(`Template "${template.key}": section "${section.name}" has no "typical" base fixture.`);
|
|
77
78
|
html += renderSectionHtml(rendererByName.get(section.name), {
|
|
78
79
|
slots: base.props.slots,
|
|
@@ -18,9 +18,9 @@ import { assertRowContract } from "./row-contract.js";
|
|
|
18
18
|
import { assertSelectContract } from "./select-contract.js";
|
|
19
19
|
import { assertSourceContract } from "./source-contract.js";
|
|
20
20
|
import { assertVariantContract } from "./variant-contract.js";
|
|
21
|
-
import { join } from "node:path";
|
|
22
21
|
import { isDeepStrictEqual } from "node:util";
|
|
23
22
|
import { readFile } from "node:fs/promises";
|
|
23
|
+
import { join } from "node:path";
|
|
24
24
|
|
|
25
25
|
//#region src/cli/check/stages/validate/orchestrator.ts
|
|
26
26
|
function serializeVariants(variants) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
1
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
//#region src/cli/check/workspace.ts
|
|
5
5
|
const isDir = async (p) => {
|
|
@@ -22,7 +22,7 @@ async function findWorkspaceRoot(from) {
|
|
|
22
22
|
for (;;) {
|
|
23
23
|
if (await isFile(join(dir, "package.json")) && await isDir(join(dir, "templates"))) return dir;
|
|
24
24
|
const parent = dirname(dir);
|
|
25
|
-
if (parent === dir) throw new Error("not inside a workspace — no parent directory has both a package.json and a templates/ folder.\nRun this from your workspace root, or create one with `npm create homepages
|
|
25
|
+
if (parent === dir) throw new Error("not inside a workspace — no parent directory has both a package.json and a templates/ folder.\nRun this from your workspace root, or create one with `npm create @homepages/workspace`.");
|
|
26
26
|
dir = parent;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -2,8 +2,8 @@ import { compileThemeToCss } from "../../design-system/theme.js";
|
|
|
2
2
|
import { loadEsbuild } from "../check/resolve-tool.js";
|
|
3
3
|
import { ASSET_LOADERS, ASSET_NAMES, ASSET_PUBLIC_PATH, sectionCssFiles } from "../check/css.js";
|
|
4
4
|
import { runTailwind } from "./tailwind.js";
|
|
5
|
-
import { basename, join, relative } from "node:path";
|
|
6
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { basename, join, relative } from "node:path";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/dev/build-css.ts
|
|
9
9
|
/**
|
package/dist/cli/dev/discover.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/dev/discover.ts
|
|
6
6
|
const REQUIRED_SECTION_FILES = [
|
package/dist/cli/dev/inspect.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { renderSection } from "./render-section.js";
|
|
2
2
|
import { collectRenderedSlotIds, computeSlotFills, schemaSlotLines } from "./fill-state.js";
|
|
3
3
|
import { summarizeHtml } from "./structure-summary.js";
|
|
4
|
-
import { join } from "node:path";
|
|
5
4
|
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
6
|
|
|
7
7
|
//#region src/cli/dev/inspect.ts
|
|
8
8
|
async function inspectSection(vite, args) {
|
|
@@ -1,12 +1,35 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
//#region src/cli/dev/island-canvas-bootstrap.ts
|
|
5
5
|
const CACHE_DIR = ".tk-dev-cache";
|
|
6
6
|
const BOOTSTRAP_FILE = "island-canvas-bootstrap.js";
|
|
7
|
-
const BOOTSTRAP_SOURCE = `import
|
|
7
|
+
const BOOTSTRAP_SOURCE = `import RefreshRuntime from "/@react-refresh";
|
|
8
|
+
import { hydrateIslands, unmountIslands } from "@homepages/template-kit/island-runtime";
|
|
8
9
|
import { createElement, useLayoutEffect } from "react";
|
|
9
10
|
|
|
11
|
+
// React Refresh preamble. @vitejs/plugin-react compiles every client component
|
|
12
|
+
// to assert this ran and throws "can't detect preamble" otherwise, so any page
|
|
13
|
+
// that was not built by Vite's own index-html transform must supply it.
|
|
14
|
+
//
|
|
15
|
+
// It lives HERE, in the bootstrap, rather than in the page that loads the
|
|
16
|
+
// bootstrap, because the two canvas surfaces reach islands by different routes:
|
|
17
|
+
// the server-rendered ?canvas=1 page emits the preamble itself (section-page.ts)
|
|
18
|
+
// before this script, but the shared-kernel srcdoc canvas is assembled by
|
|
19
|
+
// canvas-core, whose CanvasAssets port carries stylesheets, an island map and
|
|
20
|
+
// ONE host script — it has no channel for a dev-only inline prelude, and adding
|
|
21
|
+
// one would push a Vite-specific concern into a kernel the app also ships.
|
|
22
|
+
// Emitting it from the one module both surfaces already load covers both.
|
|
23
|
+
//
|
|
24
|
+
// Guarded so the server-rendered page, which already installed it, does not
|
|
25
|
+
// re-enter injectIntoGlobalHook.
|
|
26
|
+
if (!window.__vite_plugin_react_preamble_installed__) {
|
|
27
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
28
|
+
window.$RefreshReg$ = () => {};
|
|
29
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
30
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
31
|
+
}
|
|
32
|
+
|
|
10
33
|
const SHIELD_CLASS = "tr-canvas-shield";
|
|
11
34
|
const LIVE_ATTR = "data-tr-live";
|
|
12
35
|
|
|
@@ -53,17 +76,26 @@ function makeShield(doc) {
|
|
|
53
76
|
}
|
|
54
77
|
|
|
55
78
|
// "fill-self": surface made position:relative, shield appended as its last
|
|
56
|
-
// child (unit cards). "fill-parent"
|
|
57
|
-
//
|
|
79
|
+
// child (unit cards). "fill-parent" (map canvas, slider viewport): the
|
|
80
|
+
// shield is an inset:0 sibling after the surface, so the surface's PARENT is
|
|
81
|
+
// made position:relative instead — otherwise the shield escapes to the
|
|
82
|
+
// initial containing block and covers the whole canvas. Idempotent in both
|
|
83
|
+
// modes.
|
|
58
84
|
function installShield(surface, mode) {
|
|
59
85
|
const doc = surface.ownerDocument;
|
|
86
|
+
const win = doc.defaultView;
|
|
60
87
|
if (mode === "fill-self") {
|
|
61
|
-
const pos =
|
|
88
|
+
const pos = win ? win.getComputedStyle(surface).position : "";
|
|
62
89
|
if (!pos || pos === "static") surface.style.position = "relative";
|
|
63
90
|
if (Array.from(surface.children).some((c) => c.classList.contains(SHIELD_CLASS))) return;
|
|
64
91
|
surface.appendChild(makeShield(doc));
|
|
65
92
|
return;
|
|
66
93
|
}
|
|
94
|
+
const parent = surface.parentElement;
|
|
95
|
+
if (parent) {
|
|
96
|
+
const pos = win ? win.getComputedStyle(parent).position : "";
|
|
97
|
+
if (!pos || pos === "static") parent.style.position = "relative";
|
|
98
|
+
}
|
|
67
99
|
const next = surface.nextElementSibling;
|
|
68
100
|
if (next && next.classList.contains(SHIELD_CLASS)) return;
|
|
69
101
|
surface.insertAdjacentElement("afterend", makeShield(doc));
|
|
@@ -26,7 +26,7 @@ function diagnosticsBanner(section, template, encodedSection) {
|
|
|
26
26
|
}
|
|
27
27
|
function islandBootstrap(islands, bootstrapUrl) {
|
|
28
28
|
if (Object.keys(islands).length === 0) return "";
|
|
29
|
-
const mapJson = JSON.stringify(islands).replace(/</g, "\\u003c");
|
|
29
|
+
const mapJson = JSON.stringify(islands).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
30
30
|
return `
|
|
31
31
|
${REACT_REFRESH_PREAMBLE}
|
|
32
32
|
<script>window.__TR_ISLAND_MAP = ${mapJson};<\/script>
|
package/dist/cli/dev/server.js
CHANGED
|
@@ -20,10 +20,10 @@ import { writeIslandCanvasBootstrap } from "./island-canvas-bootstrap.js";
|
|
|
20
20
|
import { resolveScreenshotPath } from "./screenshot-target.js";
|
|
21
21
|
import { createDevViteServer } from "./vite-server.js";
|
|
22
22
|
import { resolveWorkspace } from "./workspace.js";
|
|
23
|
-
import { existsSync } from "node:fs";
|
|
24
|
-
import { dirname, extname, join, resolve, sep } from "node:path";
|
|
25
23
|
import { readFile } from "node:fs/promises";
|
|
24
|
+
import { dirname, extname, join, resolve, sep } from "node:path";
|
|
26
25
|
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { existsSync } from "node:fs";
|
|
27
27
|
import { createServer } from "node:http";
|
|
28
28
|
|
|
29
29
|
//#region src/cli/dev/server.ts
|
|
@@ -69,11 +69,12 @@ async function startDevServer(opts) {
|
|
|
69
69
|
const sectionAssets = /* @__PURE__ */ new Map();
|
|
70
70
|
const islandBootstrapUrl = await writeIslandBootstrap(workspace.root);
|
|
71
71
|
const canvasIslandBootstrapUrl = await writeIslandCanvasBootstrap(workspace.root);
|
|
72
|
-
vite.watcher.on("change", () => {
|
|
72
|
+
vite.watcher.on("change", (path) => {
|
|
73
73
|
vite.moduleGraph.invalidateAll();
|
|
74
74
|
cssCache.clear();
|
|
75
75
|
sectionAssets.clear();
|
|
76
|
-
hmr.broadcast("
|
|
76
|
+
if (path.endsWith(".css")) hmr.broadcast("tailwind:changed", "{}");
|
|
77
|
+
else hmr.broadcast("section:changed", "{}");
|
|
77
78
|
});
|
|
78
79
|
const ctx = {
|
|
79
80
|
workspace,
|
|
@@ -166,6 +167,7 @@ async function sendTemplatePage(ctx, templateKey, canvas, res) {
|
|
|
166
167
|
canvas
|
|
167
168
|
}));
|
|
168
169
|
}
|
|
170
|
+
const INITIAL_CSS_REV = "0";
|
|
169
171
|
async function sendTemplateSchema(ctx, url, res) {
|
|
170
172
|
const templateKey = url.searchParams.get("template");
|
|
171
173
|
if (!templateKey) {
|
|
@@ -184,6 +186,7 @@ async function sendTemplateSchema(ctx, url, res) {
|
|
|
184
186
|
const load = (dir, file) => ctx.vite.ssrLoadModule(join(dir, file));
|
|
185
187
|
const instances = await resolveManifestInstances(template);
|
|
186
188
|
const out = [];
|
|
189
|
+
const islands = {};
|
|
187
190
|
for (const inst of instances) {
|
|
188
191
|
const { schemaSlots } = await loadSectionBundle(inst.sectionDir, load);
|
|
189
192
|
out.push({
|
|
@@ -192,10 +195,14 @@ async function sendTemplateSchema(ctx, url, res) {
|
|
|
192
195
|
fixture: inst.fixture,
|
|
193
196
|
slotSchema: projectSlotSchema(schemaSlots)
|
|
194
197
|
});
|
|
198
|
+
Object.assign(islands, await buildSectionIslandMap(ctx.workspace.root, ctx.workspace.templatesDir, inst.sectionDir));
|
|
195
199
|
}
|
|
196
200
|
sendJson(res, {
|
|
197
201
|
template: templateKey,
|
|
198
|
-
instances: out
|
|
202
|
+
instances: out,
|
|
203
|
+
islands,
|
|
204
|
+
bootstrapUrl: ctx.canvasIslandBootstrapUrl,
|
|
205
|
+
cssRev: INITIAL_CSS_REV
|
|
199
206
|
});
|
|
200
207
|
}
|
|
201
208
|
async function findSection(ctx, match) {
|
package/dist/cli/dev/tailwind.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveFromWorkspace } from "../check/resolve-tool.js";
|
|
2
|
-
import { existsSync, statSync } from "node:fs";
|
|
3
2
|
import { isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/dev/tsconfig-paths-plugin.ts
|
|
6
6
|
const RESOLVE_EXTENSIONS = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/dev/workspace.ts
|
|
6
6
|
/** Walk up from `cwd` to the nearest ancestor that contains a `templates/` dir. */
|
package/dist/cli/link/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { KIT_PKG_SUBPATH, findKitRoot, overlayKit, readLinkMarker } from "./overlay.js";
|
|
2
2
|
import { findWorkspaceRoot } from "../check/workspace.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { parseArgs, promisify } from "node:util";
|
|
5
4
|
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/link/index.ts
|
package/dist/cli/link/overlay.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KIT_VERSION } from "../../index.js";
|
|
2
|
-
import { dirname, join, resolve } from "node:path";
|
|
3
2
|
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/link/overlay.ts
|
|
6
6
|
const KIT_PKG_SUBPATH = join("node_modules", "@homepages", "template-kit");
|
package/dist/cli/new/emit.js
CHANGED
package/dist/cli/new/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { findWorkspaceRoot } from "../check/workspace.js";
|
|
2
2
|
import { emitTree } from "./emit.js";
|
|
3
3
|
import { sectionAssetsDir, templateAssetsDir } from "./scaffold-assets.js";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
6
|
|
|
7
7
|
//#region src/cli/new/index.ts
|
|
8
8
|
const KEY_RE = /^[a-z][a-z0-9-]*$/;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FixtureModule } from "@homepages/template-kit";
|
|
2
|
-
import { luxuryMultiUnit
|
|
2
|
+
import { luxuryMultiUnit } from "@homepages/template-kit/fixtures";
|
|
3
3
|
|
|
4
4
|
// Base content the section is designed for. Nullability coverage (each optional
|
|
5
5
|
// slot rendered empty) is derived automatically from schema.ts — no fixture
|
|
@@ -12,12 +12,12 @@ const fixtures: FixtureModule = {
|
|
|
12
12
|
base: {
|
|
13
13
|
slots: {
|
|
14
14
|
headline: luxuryMultiUnit.facts.address.display,
|
|
15
|
+
// State the asset id, exactly as a saved page does — the preview server
|
|
16
|
+
// resolves it to a URL and a responsive ladder, the same way the API does
|
|
17
|
+
// when the page is published. A fixture never states a URL.
|
|
15
18
|
hero_image: {
|
|
16
19
|
photo_id: heroImage.id,
|
|
17
|
-
url: heroImage.url,
|
|
18
20
|
alt: heroImage.alt,
|
|
19
|
-
// Height set to a 16:9 ratio to match the slot's locked crop.
|
|
20
|
-
responsive: mkResponsive(heroImage.url, 2048, 1152),
|
|
21
21
|
},
|
|
22
22
|
blurb: "A 12-unit mansard Victorian in Jamaica Plain, moments from the Emerald Necklace.",
|
|
23
23
|
},
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import { dirname, join } from "node:path";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/new/scaffold-assets.ts
|
|
6
6
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
function assetsRoot() {
|
|
8
8
|
const dist = join(here, "scaffold");
|
|
9
9
|
if (existsSync(dist)) return dist;
|
|
10
|
-
return join(here, "..", "..", "..", "..", "create-
|
|
10
|
+
return join(here, "..", "..", "..", "..", "create-workspace", "scaffold");
|
|
11
11
|
}
|
|
12
12
|
function templateAssetsDir() {
|
|
13
13
|
return join(assetsRoot(), "template");
|
package/dist/cli/pack/collect.js
CHANGED
package/dist/cli/pack/guards.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readLinkMarker } from "../link/overlay.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
//#region src/cli/pack/guards.ts
|
|
7
7
|
const depsSchema = z.object({
|
package/dist/cli/pack/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { collectTemplateFiles, contentHash } from "./collect.js";
|
|
|
4
4
|
import { preflightGuards } from "./guards.js";
|
|
5
5
|
import { buildPackManifest } from "./manifest.js";
|
|
6
6
|
import { buildZip } from "./zip.js";
|
|
7
|
-
import { join } from "node:path";
|
|
8
7
|
import { parseArgs } from "node:util";
|
|
9
8
|
import { readFile, writeFile } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
10
|
|
|
11
11
|
//#region src/cli/pack/index.ts
|
|
12
12
|
function refusal(lines) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TokenThemeSchema, compileThemeToCss } from "../../design-system/theme.js";
|
|
2
2
|
import { loadTheme } from "./load-theme.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
//#region src/cli/theme/generate.ts
|
|
7
7
|
const OUT_FILE = "theme.css";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadEsbuild } from "../check/resolve-tool.js";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { mkdir, readFile, rm, stat } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@theme inline{ --color-canvas: #ffffff; --color-line: #ebebe6; }:root{--frame: clamp(1px, calc(1px + (100vw - 1536px) * .0006076), 1.41667px);--content-follow: .25;--content: calc(1px + (var(--frame) - 1px) * var(--content-follow))}*{box-sizing:border-box}html,body,#root{margin:0;padding:0;height:100%;background:#0f1115;color:#e6e7eb;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,Segoe UI,Helvetica,Arial,sans-serif}a{color:inherit;text-decoration:none}button,select,input,textarea{font:inherit;color:inherit;background:#1a1d24;border:1px solid #2c313a;border-radius:4px;padding:6px 10px}button{cursor:pointer}button:hover{background:#232831}button:disabled{opacity:.4;cursor:default}.empty{padding:40px;color:#9ca0a8;text-align:center}.boot-error{padding:24px;color:#ff8b8b;font:13px/1.5 ui-monospace,Menlo,monospace;white-space:pre-wrap}.canvas-mirror{display:flex;flex-direction:column;height:100%;min-height:0}.canvas-iframe{width:100%;height:100%;border:0;background:#fff}.home{max-width:880px;margin:0 auto;padding:40px 24px}.home-header{margin-bottom:28px}.home-title{font-size:15px;font-weight:600}.home-tagline{font-size:13px;color:#9ca0a8;margin-top:4px}.home-template{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:#9ca0a8;margin-bottom:24px}.home-template select{min-width:160px}.home-tools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.tool-card{display:flex;flex-direction:column;gap:12px;background:#14171c;border:1px solid #21252d;border-radius:8px;padding:20px}.tool-card h2{font-size:14px;font-weight:600;margin:0}.tool-card p{font-size:13px;color:#9ca0a8;margin:0;line-height:1.5}.tool-card .controls{display:flex;flex-direction:column;gap:8px}.tool-card label{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:#9ca0a8}.tool-card label select{min-width:140px}.open-btn{margin-top:auto;text-align:center;padding:8px 12px;border:1px solid #2c313a;border-radius:6px;background:#1a1d24;color:inherit;cursor:pointer}.open-btn:hover{background:#232831}.open-btn:disabled{opacity:.4;cursor:default}.home-hint{font-size:12px;color:#6b7280}.canvas-mirror__stage{position:relative;min-height:0;flex:1;overflow:hidden}.canvas-mirror__stage .canvas-iframe{position:absolute;top:0;right:0;bottom:0;left:0}.canvas-mirror__sidebar{position:absolute;top:20px;right:20px;bottom:20px;z-index:20;width:calc(400 * var(--frame));display:flex;flex-direction:column;min-height:0}@media(max-width:1100px){.canvas-mirror__sidebar{width:388px}}.instance-panel{flex:1 1 auto;min-height:0;overflow-y:auto;border-left:1px solid #e5e7eb;padding:12px;background:#fff;font:13px system-ui,sans-serif;display:flex;flex-direction:column;gap:10px}.instance-panel__head{display:flex;align-items:flex-end;justify-content:space-between;gap:8px;padding-bottom:10px;border-bottom:1px solid #e5e7eb}.instance-panel__slot{display:flex;align-items:center;gap:8px}.instance-panel__type{color:#6b7280}.instance-panel__fill{margin-left:auto;padding:1px 7px;border-radius:999px;font-size:11px}.instance-panel__fill--filled{background:#dcfce7;color:#166534}.instance-panel__fill--empty{background:#f3f4f6;color:#6b7280}.instance-panel__fill--missing{background:#fee2e2;color:#991b1b}.instance-panel__fixture{display:flex;flex-direction:column;gap:3px;color:#6b7280}.instance-panel__json{width:100%;min-height:180px;font:12px ui-monospace,monospace;resize:vertical}.instance-panel__error{color:#b91c1c;white-space:pre-wrap}.instance-panel__actions{display:flex;gap:8px}.instance-panel__slot-editor{display:flex;flex-direction:column;gap:8px;padding:10px 0;border-top:1px solid #f0f1f3}.instance-panel__slot-editor:first-of-type{border-top:0;padding-top:0}.instance-panel__slot-editor--selected{border-left:3px solid #b8860b;padding-left:9px;margin-left:-12px}
|