@homepages/template-kit 0.9.0-dev-20260719205406 → 0.9.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/CHANGELOG.md +60 -59
- package/README.md +14 -4
- package/dist/contracts/fill-treatments.d.ts +23 -0
- 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/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.d.ts +9 -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.d.ts +22 -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/schema/property-facts.d.ts +2 -2
- package/dist/schema/resolve-section-ref.d.ts +4 -0
- package/dist/schema/rows.d.ts +9 -0
- package/dist/schema/section-nav.d.ts +5 -1
- package/dist/schema/slot-types.d.ts +1 -1
- package/dist/ssr.d.ts +19 -2
- package/dist/ssr.js +32 -13
- package/guide/INDEX.md +5 -0
- package/guide/check.md +1 -0
- package/guide/dev.md +1 -0
- package/guide/llms.txt +11 -3
- package/guide/recipes/image-slot-crop.md +6 -6
- package/guide/recipes/pick-a-scenario.md +13 -5
- package/guide/schema-system.md +36 -12
- package/guide/upgrading.md +12 -8
- package/package.json +4 -16
- package/dist/canvas-core/chrome-css.d.ts +0 -24
- package/dist/canvas-core/chrome-css.js +0 -403
- package/dist/canvas-core/chrome.d.ts +0 -49
- package/dist/canvas-core/chrome.js +0 -147
- package/dist/canvas-core/frame.d.ts +0 -20
- package/dist/canvas-core/frame.js +0 -23
- package/dist/canvas-core/hidden-tabs.d.ts +0 -16
- package/dist/canvas-core/hidden-tabs.js +0 -84
- package/dist/canvas-core/resolve-target.js +0 -55
- package/dist/canvas-core/scroll.d.ts +0 -10
- package/dist/canvas-core/scroll.js +0 -15
- package/dist/canvas-core/section-dom.d.ts +0 -6
- package/dist/canvas-core/section-dom.js +0 -43
- package/dist/canvas-core/srcdoc.d.ts +0 -8
- package/dist/canvas-core/srcdoc.js +0 -77
- package/dist/canvas-core/types.d.ts +0 -76
- package/dist/canvas-core.d.ts +0 -9
- package/dist/canvas-core.js +0 -9
- package/dist/cli/check/config.js +0 -41
- package/dist/cli/check/css.js +0 -131
- package/dist/cli/check/diagnostics.js +0 -37
- package/dist/cli/check/index.js +0 -94
- package/dist/cli/check/loader.js +0 -149
- package/dist/cli/check/paths.js +0 -15
- package/dist/cli/check/relativize.js +0 -18
- package/dist/cli/check/render-invariants.js +0 -24
- package/dist/cli/check/resolve-tool.js +0 -38
- package/dist/cli/check/section-assets.js +0 -58
- package/dist/cli/check/stages/deps.js +0 -337
- package/dist/cli/check/stages/lint.js +0 -46
- package/dist/cli/check/stages/render.js +0 -97
- package/dist/cli/check/stages/size.js +0 -274
- package/dist/cli/check/stages/tree.js +0 -206
- package/dist/cli/check/stages/typecheck.js +0 -46
- package/dist/cli/check/stages/validate/catalog-exhaustiveness.js +0 -18
- package/dist/cli/check/stages/validate/facts.js +0 -19
- package/dist/cli/check/stages/validate/formatter-contract.js +0 -14
- package/dist/cli/check/stages/validate/group-contract.js +0 -21
- package/dist/cli/check/stages/validate/index.js +0 -66
- package/dist/cli/check/stages/validate/list-scalar-contract.js +0 -22
- package/dist/cli/check/stages/validate/nav-contract.js +0 -92
- package/dist/cli/check/stages/validate/nested-slot-contract.js +0 -12
- package/dist/cli/check/stages/validate/object-list-contract.js +0 -31
- package/dist/cli/check/stages/validate/orchestrator.js +0 -241
- package/dist/cli/check/stages/validate/produced-by-contract.js +0 -18
- package/dist/cli/check/stages/validate/row-contract.js +0 -31
- package/dist/cli/check/stages/validate/select-contract.js +0 -13
- package/dist/cli/check/stages/validate/source-contract.js +0 -21
- package/dist/cli/check/stages/validate/variant-contract.js +0 -15
- package/dist/cli/check/workspace.js +0 -99
- package/dist/cli/dev/build-css.js +0 -97
- package/dist/cli/dev/catalog.js +0 -35
- package/dist/cli/dev/compose-template.js +0 -39
- package/dist/cli/dev/content-override.js +0 -58
- package/dist/cli/dev/diagnostics.js +0 -68
- package/dist/cli/dev/discover.js +0 -35
- package/dist/cli/dev/fill-state.js +0 -77
- package/dist/cli/dev/index.js +0 -42
- package/dist/cli/dev/inspect.js +0 -38
- package/dist/cli/dev/island-bootstrap.js +0 -38
- package/dist/cli/dev/island-canvas-bootstrap.js +0 -204
- package/dist/cli/dev/island-map.js +0 -35
- package/dist/cli/dev/island-transform.js +0 -31
- package/dist/cli/dev/manifest-instances.js +0 -31
- package/dist/cli/dev/render-section.js +0 -24
- package/dist/cli/dev/screenshot-target.js +0 -24
- package/dist/cli/dev/section-page.js +0 -91
- package/dist/cli/dev/server.js +0 -510
- package/dist/cli/dev/slot-schema.js +0 -12
- package/dist/cli/dev/structure-summary.js +0 -119
- package/dist/cli/dev/tailwind.js +0 -32
- package/dist/cli/dev/tsconfig-paths-plugin.js +0 -90
- package/dist/cli/dev/vite-server.js +0 -39
- package/dist/cli/dev/workspace.js +0 -63
- package/dist/cli/link/index.js +0 -74
- package/dist/cli/link/overlay.js +0 -59
- package/dist/cli/link/watch.js +0 -25
- package/dist/cli/new/emit.js +0 -48
- package/dist/cli/new/index.js +0 -69
- package/dist/cli/new/scaffold/section/_Renderer.tsx +0 -20
- package/dist/cli/new/scaffold/section/_fill-spec.ts +0 -18
- package/dist/cli/new/scaffold/section/_fixtures.ts +0 -13
- package/dist/cli/new/scaffold/section/_schema.ts +0 -24
- package/dist/cli/new/scaffold/template/_manifest.json +0 -9
- package/dist/cli/new/scaffold/template/sections/hero/ExpandableText.tsx +0 -45
- package/dist/cli/new/scaffold/template/sections/hero/Renderer.tsx +0 -40
- package/dist/cli/new/scaffold/template/sections/hero/components/Feature.tsx +0 -14
- package/dist/cli/new/scaffold/template/sections/hero/fill-spec.ts +0 -29
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +0 -41
- package/dist/cli/new/scaffold/template/sections/hero/schema.ts +0 -60
- package/dist/cli/new/scaffold/template/theme.css +0 -24
- package/dist/cli/new/scaffold/template/theme.ts +0 -27
- package/dist/cli/new/scaffold-assets.js +0 -20
- package/dist/cli/pack/collect.js +0 -44
- package/dist/cli/pack/guards.js +0 -57
- package/dist/cli/pack/index.js +0 -66
- package/dist/cli/pack/manifest.js +0 -15
- package/dist/cli/pack/zip.js +0 -86
- package/dist/cli/theme/generate.js +0 -43
- package/dist/cli/theme/index.js +0 -33
- package/dist/cli/theme/load-theme.js +0 -69
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -138
- package/dist/dev-client/assets/index-CJa9G1Na.css +0 -1
- package/dist/dev-client/assets/index-C_1atZs4.js +0 -450
- package/dist/dev-client/index.html +0 -13
- package/dist/tokens.css +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @homepages/template-kit
|
|
2
2
|
|
|
3
|
-
## 0.9.0
|
|
3
|
+
## 0.9.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -24,71 +24,72 @@
|
|
|
24
24
|
`resolveImportedFile`, `resetClientFileCache`) that the plugin's rules consume
|
|
25
25
|
over the peer edge.
|
|
26
26
|
|
|
27
|
+
- f868a43: **Breaking:** the CLI has moved to its own package, `@homepages/template-cli`.
|
|
28
|
+
Installing the kit no longer installs the `template-kit` command, and the
|
|
29
|
+
`./canvas-core` subpath is gone.
|
|
30
|
+
|
|
31
|
+
The command itself is unchanged — it is still `template-kit dev`, `template-kit
|
|
32
|
+
check`, and so on. Add the new package as a devDependency alongside your existing
|
|
33
|
+
kit dependency:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
npm i -D @homepages/template-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The kit stays the package your templates import, under the same name and with the
|
|
40
|
+
same authoring API, so no `import` in a workspace changes. The CLI declares the kit
|
|
41
|
+
as a `peerDependency`, which is what guarantees a workspace resolves exactly one
|
|
42
|
+
copy of it.
|
|
43
|
+
|
|
44
|
+
Why: the CLI and its dev playground were 53% of the kit's published bytes while the
|
|
45
|
+
code that reaches a visitor's browser was under 1%, and they change on playground
|
|
46
|
+
cadence rather than contract cadence. Sharing one version number meant a
|
|
47
|
+
playground fix and an authoring-contract change were indistinguishable in the
|
|
48
|
+
number a template author reads.
|
|
49
|
+
|
|
50
|
+
`./ssr` additionally now exports `wrapClientModuleMagic`, `flattenLayout`,
|
|
51
|
+
`isShortSlot`, `resolveSectionRef`, `resolveAnchorMap` and `parseTreatment` — the
|
|
52
|
+
node-side schema and island helpers the CLI reaches across the peer edge. They are
|
|
53
|
+
deliberately absent from the authoring barrel: a renderer never imports `./ssr`.
|
|
54
|
+
|
|
55
|
+
- b7bfc96: Fixtures state media asset ids instead of URLs, and the kit resolves them.
|
|
56
|
+
|
|
57
|
+
A fixture now states what a saved page actually holds — `{ photo_id, alt }` — and
|
|
58
|
+
the kit resolves that id to a URL, an `alt`, and a responsive ladder when it loads
|
|
59
|
+
the fixture. Previously fixtures stated the post-resolution URL plus a synthesized
|
|
60
|
+
ladder, which exercised a code path real content never takes and left every preview
|
|
61
|
+
image broken.
|
|
62
|
+
|
|
63
|
+
Breaking changes to `@homepages/template-kit/fixtures`:
|
|
64
|
+
|
|
65
|
+
- `mkResponsive` is removed. Nothing needs to call it: the ladder is attached during
|
|
66
|
+
fixture load.
|
|
67
|
+
- `PhotoFixture.url` is removed; `PhotoFixture.id` now holds a media asset id.
|
|
68
|
+
- `ContactFixture.fields` replaces `headshot_url`, `logo_light`, and `logo_dark`
|
|
69
|
+
with `headshot_id`, `logo_light_id`, and `logo_dark_id`.
|
|
70
|
+
- `MediaFixture.video_url` becomes `video_id`. `tour_3d_url` is unchanged — a 3D
|
|
71
|
+
tour is a third-party embed, not a media asset.
|
|
72
|
+
- `FloorplanAssignment.url` and `.alt` are now optional: a fixture states the plan
|
|
73
|
+
ref, and url/alt/responsive appear only after resolution.
|
|
74
|
+
|
|
75
|
+
To migrate a fixture, drop `url` and `responsive` and keep the id:
|
|
76
|
+
|
|
77
|
+
```diff
|
|
78
|
+
hero_image: {
|
|
79
|
+
photo_id: photo.id,
|
|
80
|
+
- url: photo.url,
|
|
81
|
+
alt: photo.alt,
|
|
82
|
+
- responsive: mkResponsive(photo.url, 2048, 1259),
|
|
83
|
+
},
|
|
84
|
+
```
|
|
85
|
+
|
|
27
86
|
### Patch Changes
|
|
28
87
|
|
|
29
|
-
- 10f53a7: `template-kit dev`'s canvas hover/select ring no longer overflows the page's
|
|
30
|
-
x-axis when hovering a full-bleed section (e.g. a hero or header flush with
|
|
31
|
-
both page edges). The ring's geometry inflated the target's bounding rect by
|
|
32
|
-
a fixed offset on every side with no bound, so a rect already touching the
|
|
33
|
-
document edge pushed the ring 2px past it, growing the iframe's horizontal
|
|
34
|
-
scroll extent. The ring box is now clamped to `[0, containerWidth]`.
|
|
35
|
-
- f3f6d70: `template-kit check` no longer fails on a tsconfig `paths` alias (e.g.
|
|
36
|
-
`"@/platform/*": ["../platform/*"]`) or on a section whose contract files
|
|
37
|
-
share a module large enough for esbuild to code-split. Previously the
|
|
38
|
-
loader's css-stub plugin decided "external vs. bundle" from the specifier's
|
|
39
|
-
own text, so a `paths`-resolved alias got re-emitted as a literal bare
|
|
40
|
-
import Node couldn't resolve; separately, the loader's build applied
|
|
41
|
-
`publicPath` to code-split `chunk-*.js` cross-imports the same way it does
|
|
42
|
-
to real asset files, producing an import path Node couldn't resolve either.
|
|
43
|
-
Both are now decided from the actual resolved file, and `publicPath` is no
|
|
44
|
-
longer set on the loader's build.
|
|
45
|
-
- 1c2c2db: `template-kit dev`'s preview server no longer 500s on `/runtime/base.css`.
|
|
46
|
-
The route resolved the file at a path the build never emits to
|
|
47
|
-
(`dist/css/base.css`; the build copies it flat to `dist/base.css`), so every
|
|
48
|
-
section rendered unstyled — Tailwind-derived colors and layout were silently
|
|
49
|
-
missing everywhere, only arbitrary-value element geometry survived. The
|
|
50
|
-
route now checks the built (flat) path first and falls back to the source
|
|
51
|
-
(`src/css/`) layout, so it resolves correctly both from an installed kit and
|
|
52
|
-
when running the CLI unbuilt via `tsx` during kit development.
|
|
53
|
-
- 989d23e: `template-kit dev` gains an optional `--diagnostics-cmd` flag: point it at any
|
|
54
|
-
command that prints `{"violations": [...]}` JSON for a `--template`/`--section`
|
|
55
|
-
pair, and the standalone section preview
|
|
56
|
-
(`/sections/<template>/<section>/<fixture>`) shows a dismissible banner when it
|
|
57
|
-
reports violations. Unset by default — no behavior change for a workspace that
|
|
58
|
-
doesn't configure it.
|
|
59
|
-
- e1d5792: `template-kit dev`'s preview server now compiles a template's theme-color
|
|
60
|
-
Tailwind utilities (`bg-primary`, `text-ink`, `bg-background`, etc.) instead
|
|
61
|
-
of silently dropping them. `assembleTemplateCss` used to concatenate the
|
|
62
|
-
compiled theme (`compileThemeToCss`, the `@theme inline` alias layer plus
|
|
63
|
-
its `:root` custom props) onto Tailwind's CLI output _after_ the CLI had
|
|
64
|
-
already run, so the theme's color tokens were never part of the build graph
|
|
65
|
-
Tailwind scanned — `@theme` outside that graph is inert, and silently so, so
|
|
66
|
-
any utility built on a template color never got generated. No error, no
|
|
67
|
-
warning: every section rendered with correct layout but default
|
|
68
|
-
black-on-white text and backgrounds. The theme partial is now written to the
|
|
69
|
-
dev cache and `@import`ed into the Tailwind entry ahead of the section
|
|
70
|
-
`@source` scans, mirroring how the registry's own publish pipeline
|
|
71
|
-
(`ci/build-css.ts`) has always assembled it. `fontFaces` is still prepended
|
|
72
|
-
to the final bundle separately, since a nested `@import url(...)` doesn't
|
|
73
|
-
hoist out of an imported partial.
|
|
74
|
-
- 2e36277: Escape `>` and `&` as well as `<` in the dev server's island map, matching the escaping used by published pages.
|
|
75
88
|
- 1c4c7dd: Island hydration is now nesting-safe: `hydrateIslands` skips any island marker
|
|
76
89
|
nested inside another marker, so an island can render another island without the
|
|
77
90
|
child being hydrated twice (once by its parent root, once independently). Enables
|
|
78
91
|
interactive islands (accordion, card-slider, carousel) to wrap existing leaf
|
|
79
92
|
islands (expandable-text) on published pages.
|
|
80
|
-
- ff1d6de: `template-kit dev`'s canvas mirror now shows the Islands inspector panel for a
|
|
81
|
-
section-level selection, not just a slot selection. A `fill-parent`/`fill-self`
|
|
82
|
-
island with no owning slot of its own only ever gets its shield dropped by a
|
|
83
|
-
section-level click, so the panel previously could show it as `shielded` but
|
|
84
|
-
never `interactive`. Existing slot-selection behavior (edit panel + Islands
|
|
85
|
-
list) is unchanged.
|
|
86
|
-
- 41d0e88: `template-kit dev` now honors a workspace's tsconfig `paths` when resolving
|
|
87
|
-
imports, the same way `check` already does via esbuild's native tsconfig
|
|
88
|
-
lookup. Previously the dev server's Vite instance had no `paths` awareness at
|
|
89
|
-
all, so a workspace mapping (e.g. `"@/lib/*": ["../lib/*"]`) that made `check`
|
|
90
|
-
pass left `dev` 500ing with `Cannot find module`. A workspace with no `paths`
|
|
91
|
-
mapping is unaffected.
|
|
92
93
|
|
|
93
94
|
## 0.8.0
|
|
94
95
|
|
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# @homepages/template-kit
|
|
2
2
|
|
|
3
3
|
The authoring surface for HomePages marketing-section templates: schema system,
|
|
4
|
-
contract primitives, the theme system
|
|
4
|
+
contract primitives, and the theme system. The `template-kit` command lives in its
|
|
5
|
+
own package, [`@homepages/template-cli`](#install) — the kit is what your templates
|
|
6
|
+
`import`.
|
|
5
7
|
|
|
6
8
|
**Status: 0.0.x.** The **schema system** (the section authoring contract and the closed
|
|
7
9
|
vocabulary it validates against), the **contract primitives**, and the **theme system**
|
|
@@ -31,9 +33,16 @@ Prefer to wire a workspace by hand? See **Install** below.
|
|
|
31
33
|
|
|
32
34
|
```bash
|
|
33
35
|
npm install @homepages/template-kit react react-dom
|
|
36
|
+
npm install -D @homepages/template-cli # the `template-kit` command
|
|
34
37
|
npm install -D typescript eslint @typescript-eslint/parser esbuild # the authoring toolchain
|
|
35
38
|
```
|
|
36
39
|
|
|
40
|
+
The **command is `template-kit`; the package that provides it is
|
|
41
|
+
`@homepages/template-cli`** — a package/bin mismatch in the same spirit as
|
|
42
|
+
`typescript`/`tsc`. Everything you write is imported from `@homepages/template-kit`;
|
|
43
|
+
the CLI declares the kit as a peer dependency, so a workspace resolves exactly one
|
|
44
|
+
copy of it.
|
|
45
|
+
|
|
37
46
|
React 19 is a **peer dependency** — the kit never bundles its own copy.
|
|
38
47
|
|
|
39
48
|
The kit has exactly **one runtime dependency** (`zod`). The authoring toolchain the
|
|
@@ -97,6 +106,7 @@ Full contract: **[guide/primitives.md](guide/primitives.md)**.
|
|
|
97
106
|
| `@homepages/template-kit/browser` | Browser helpers for published pages (site config, signed ingest) |
|
|
98
107
|
| `@homepages/template-kit/styles.css` | The global Tailwind preamble: the breakpoint ladder, the spacing base unit, the motion defaults, kit source registration |
|
|
99
108
|
| `@homepages/template-kit/base.css` | Cascade-layer order, the three reset gaps Tailwind's preflight leaves, `.tr-section`, and the motion tokens |
|
|
109
|
+
| `@homepages/template-cli` | The `template-kit` command (its own package) |
|
|
100
110
|
| `@homepages/eslint-plugin-template` | ESLint flat-config preset (its own package) |
|
|
101
111
|
| `@homepages/template-kit/tsconfig` | tsconfig preset (`"extends"`) |
|
|
102
112
|
|
|
@@ -158,7 +168,7 @@ section also has a standalone page, and so does the whole template at
|
|
|
158
168
|
payload), and `/api/screenshot` (a full-page PNG, section or whole template). Like
|
|
159
169
|
`check`, it runs **your** toolchain — Vite and Tailwind resolved from your workspace,
|
|
160
170
|
installed with `npm i -D vite @vitejs/plugin-react tailwindcss @tailwindcss/cli` — not
|
|
161
|
-
shipped by
|
|
171
|
+
shipped by either package. Full contract: **[guide/dev.md](guide/dev.md)**.
|
|
162
172
|
|
|
163
173
|
## Checking a workspace
|
|
164
174
|
|
|
@@ -229,5 +239,5 @@ that vocabulary — your template names its own.
|
|
|
229
239
|
|
|
230
240
|
Don't — changesets owns `package.json`'s version. There is nothing else to keep
|
|
231
241
|
in step with it: `KIT_VERSION` is read from `package.json` and inlined at build
|
|
232
|
-
time, and the test suite asserts
|
|
233
|
-
|
|
242
|
+
time, and the test suite asserts it against `package.json` to prove the inlining
|
|
243
|
+
happened.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/contracts/fill-treatments.d.ts
|
|
2
|
+
declare const GENERATED_KINDS: readonly ["text", "list<text>"];
|
|
3
|
+
type GeneratedKind = (typeof GENERATED_KINDS)[number];
|
|
4
|
+
declare const COMPUTED_FNS: readonly ["haversine_miles", "mint_id"];
|
|
5
|
+
type ComputedFn = (typeof COMPUTED_FNS)[number];
|
|
6
|
+
declare const CATALOG_FIELDS: readonly ["key", "label", "icon", "slot"];
|
|
7
|
+
type CatalogField = (typeof CATALOG_FIELDS)[number];
|
|
8
|
+
type Treatment = {
|
|
9
|
+
kind: "source";
|
|
10
|
+
path: string | null;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "computed";
|
|
13
|
+
fn: ComputedFn;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "catalog";
|
|
16
|
+
field: CatalogField;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "generated";
|
|
19
|
+
outKind: GeneratedKind;
|
|
20
|
+
};
|
|
21
|
+
declare function parseTreatment(raw: string): Treatment | null;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { CATALOG_FIELDS, COMPUTED_FNS, CatalogField, ComputedFn, GENERATED_KINDS, GeneratedKind, Treatment, parseTreatment };
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { ResponsiveImage } from "../contracts/image-descriptor.js";
|
|
2
1
|
//#region src/fixtures/sample-property.d.ts
|
|
3
2
|
type PhotoFixture = {
|
|
4
3
|
id: string;
|
|
5
|
-
url: string;
|
|
6
4
|
alt: string;
|
|
7
5
|
tags: {
|
|
8
6
|
room?: string;
|
|
9
7
|
category?: string;
|
|
10
8
|
};
|
|
11
9
|
};
|
|
12
|
-
declare function mkResponsive(url: string, width: number, height: number): ResponsiveImage;
|
|
13
10
|
type PoiFixture = {
|
|
14
11
|
id: string;
|
|
15
12
|
category: "restaurant" | "park" | "transit" | "shopping" | "coffee" | "fitness";
|
|
@@ -31,14 +28,14 @@ type ContactFixture = {
|
|
|
31
28
|
display_name: string;
|
|
32
29
|
title: string;
|
|
33
30
|
bio: string;
|
|
34
|
-
|
|
31
|
+
headshot_id: string;
|
|
35
32
|
website_url: string;
|
|
36
33
|
email: string;
|
|
37
34
|
phone: string;
|
|
38
35
|
address: string;
|
|
39
36
|
org_name: string;
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
logo_light_id: string | null;
|
|
38
|
+
logo_dark_id: string | null;
|
|
42
39
|
socials: Array<{
|
|
43
40
|
platform: "instagram" | "linkedin" | "x" | "facebook";
|
|
44
41
|
url: string;
|
|
@@ -54,4 +51,4 @@ type AmenityItem = {
|
|
|
54
51
|
items: string[];
|
|
55
52
|
};
|
|
56
53
|
//#endregion
|
|
57
|
-
export { AmenityItem, ContactFixture, PhotoFixture, PoiFixture
|
|
54
|
+
export { AmenityItem, ContactFixture, PhotoFixture, PoiFixture };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
//#region src/fixtures/sample-property.ts
|
|
2
|
-
const PHOTO_BASE = "https://example.invalid/photos/queensway";
|
|
3
2
|
const galleryPhotos = [
|
|
4
3
|
{
|
|
5
|
-
id: "
|
|
6
|
-
url: `${PHOTO_BASE}/01-lobby.jpg`,
|
|
4
|
+
id: "dev_upl_queensway_01_lobby",
|
|
7
5
|
alt: "Lobby with terrazzo flooring and chandeliers.",
|
|
8
6
|
tags: {
|
|
9
7
|
room: "lobby",
|
|
@@ -11,8 +9,7 @@ const galleryPhotos = [
|
|
|
11
9
|
}
|
|
12
10
|
},
|
|
13
11
|
{
|
|
14
|
-
id: "
|
|
15
|
-
url: `${PHOTO_BASE}/02-gym-a.jpg`,
|
|
12
|
+
id: "dev_upl_queensway_02_gym_a",
|
|
16
13
|
alt: "Gym with cardio equipment and floor-to-ceiling mirrors.",
|
|
17
14
|
tags: {
|
|
18
15
|
room: "gym",
|
|
@@ -20,8 +17,7 @@ const galleryPhotos = [
|
|
|
20
17
|
}
|
|
21
18
|
},
|
|
22
19
|
{
|
|
23
|
-
id: "
|
|
24
|
-
url: `${PHOTO_BASE}/03-gym-b.jpg`,
|
|
20
|
+
id: "dev_upl_queensway_03_gym_b",
|
|
25
21
|
alt: "Gym free-weights area.",
|
|
26
22
|
tags: {
|
|
27
23
|
room: "gym",
|
|
@@ -29,8 +25,7 @@ const galleryPhotos = [
|
|
|
29
25
|
}
|
|
30
26
|
},
|
|
31
27
|
{
|
|
32
|
-
id: "
|
|
33
|
-
url: `${PHOTO_BASE}/04-living-a.jpg`,
|
|
28
|
+
id: "dev_upl_queensway_04_living_a",
|
|
34
29
|
alt: "Living area with bay windows and original mouldings.",
|
|
35
30
|
tags: {
|
|
36
31
|
room: "living",
|
|
@@ -38,8 +33,7 @@ const galleryPhotos = [
|
|
|
38
33
|
}
|
|
39
34
|
},
|
|
40
35
|
{
|
|
41
|
-
id: "
|
|
42
|
-
url: `${PHOTO_BASE}/05-living-b.jpg`,
|
|
36
|
+
id: "dev_upl_queensway_05_living_b",
|
|
43
37
|
alt: "Living area facing the fireplace.",
|
|
44
38
|
tags: {
|
|
45
39
|
room: "living",
|
|
@@ -47,8 +41,7 @@ const galleryPhotos = [
|
|
|
47
41
|
}
|
|
48
42
|
},
|
|
49
43
|
{
|
|
50
|
-
id: "
|
|
51
|
-
url: `${PHOTO_BASE}/06-kitchen-a.jpg`,
|
|
44
|
+
id: "dev_upl_queensway_06_kitchen_a",
|
|
52
45
|
alt: "Kitchen with quartz waterfall island.",
|
|
53
46
|
tags: {
|
|
54
47
|
room: "kitchen",
|
|
@@ -56,8 +49,7 @@ const galleryPhotos = [
|
|
|
56
49
|
}
|
|
57
50
|
},
|
|
58
51
|
{
|
|
59
|
-
id: "
|
|
60
|
-
url: `${PHOTO_BASE}/07-kitchen-b.jpg`,
|
|
52
|
+
id: "dev_upl_queensway_07_kitchen_b",
|
|
61
53
|
alt: "Kitchen breakfast nook by the window.",
|
|
62
54
|
tags: {
|
|
63
55
|
room: "kitchen",
|
|
@@ -65,8 +57,7 @@ const galleryPhotos = [
|
|
|
65
57
|
}
|
|
66
58
|
},
|
|
67
59
|
{
|
|
68
|
-
id: "
|
|
69
|
-
url: `${PHOTO_BASE}/08-dining.jpg`,
|
|
60
|
+
id: "dev_upl_queensway_08_dining",
|
|
70
61
|
alt: "Dining area set for six.",
|
|
71
62
|
tags: {
|
|
72
63
|
room: "dining",
|
|
@@ -74,8 +65,7 @@ const galleryPhotos = [
|
|
|
74
65
|
}
|
|
75
66
|
},
|
|
76
67
|
{
|
|
77
|
-
id: "
|
|
78
|
-
url: `${PHOTO_BASE}/09-living-c.jpg`,
|
|
68
|
+
id: "dev_upl_queensway_09_living_c",
|
|
79
69
|
alt: "Living area with statement art wall.",
|
|
80
70
|
tags: {
|
|
81
71
|
room: "living",
|
|
@@ -83,8 +73,7 @@ const galleryPhotos = [
|
|
|
83
73
|
}
|
|
84
74
|
},
|
|
85
75
|
{
|
|
86
|
-
id: "
|
|
87
|
-
url: `${PHOTO_BASE}/10-living-d.jpg`,
|
|
76
|
+
id: "dev_upl_queensway_10_living_d",
|
|
88
77
|
alt: "Living area opening onto private terrace.",
|
|
89
78
|
tags: {
|
|
90
79
|
room: "living",
|
|
@@ -92,8 +81,7 @@ const galleryPhotos = [
|
|
|
92
81
|
}
|
|
93
82
|
},
|
|
94
83
|
{
|
|
95
|
-
id: "
|
|
96
|
-
url: `${PHOTO_BASE}/11-living-e.jpg`,
|
|
84
|
+
id: "dev_upl_queensway_11_living_e",
|
|
97
85
|
alt: "Sunken living area with built-in shelving.",
|
|
98
86
|
tags: {
|
|
99
87
|
room: "living",
|
|
@@ -101,8 +89,7 @@ const galleryPhotos = [
|
|
|
101
89
|
}
|
|
102
90
|
},
|
|
103
91
|
{
|
|
104
|
-
id: "
|
|
105
|
-
url: `${PHOTO_BASE}/12-living-f.jpg`,
|
|
92
|
+
id: "dev_upl_queensway_12_living_f",
|
|
106
93
|
alt: "Living area corner with reading chair.",
|
|
107
94
|
tags: {
|
|
108
95
|
room: "living",
|
|
@@ -110,8 +97,7 @@ const galleryPhotos = [
|
|
|
110
97
|
}
|
|
111
98
|
},
|
|
112
99
|
{
|
|
113
|
-
id: "
|
|
114
|
-
url: `${PHOTO_BASE}/13-master-bedroom.jpg`,
|
|
100
|
+
id: "dev_upl_queensway_13_master_bedroom",
|
|
115
101
|
alt: "Primary bedroom with king bed and skylight.",
|
|
116
102
|
tags: {
|
|
117
103
|
room: "bedroom",
|
|
@@ -119,8 +105,7 @@ const galleryPhotos = [
|
|
|
119
105
|
}
|
|
120
106
|
},
|
|
121
107
|
{
|
|
122
|
-
id: "
|
|
123
|
-
url: `${PHOTO_BASE}/14-master-bath-a.jpg`,
|
|
108
|
+
id: "dev_upl_queensway_14_master_bath_a",
|
|
124
109
|
alt: "Spa-style primary bath with freestanding tub.",
|
|
125
110
|
tags: {
|
|
126
111
|
room: "bath",
|
|
@@ -128,8 +113,7 @@ const galleryPhotos = [
|
|
|
128
113
|
}
|
|
129
114
|
},
|
|
130
115
|
{
|
|
131
|
-
id: "
|
|
132
|
-
url: `${PHOTO_BASE}/15-master-bath-b.jpg`,
|
|
116
|
+
id: "dev_upl_queensway_15_master_bath_b",
|
|
133
117
|
alt: "Primary bath double vanity and shower.",
|
|
134
118
|
tags: {
|
|
135
119
|
room: "bath",
|
|
@@ -137,8 +121,7 @@ const galleryPhotos = [
|
|
|
137
121
|
}
|
|
138
122
|
},
|
|
139
123
|
{
|
|
140
|
-
id: "
|
|
141
|
-
url: `${PHOTO_BASE}/16-common-bath.jpg`,
|
|
124
|
+
id: "dev_upl_queensway_16_common_bath",
|
|
142
125
|
alt: "Common bath with marble subway tile.",
|
|
143
126
|
tags: {
|
|
144
127
|
room: "bath",
|
|
@@ -146,8 +129,7 @@ const galleryPhotos = [
|
|
|
146
129
|
}
|
|
147
130
|
},
|
|
148
131
|
{
|
|
149
|
-
id: "
|
|
150
|
-
url: `${PHOTO_BASE}/17-entrance.jpg`,
|
|
132
|
+
id: "dev_upl_queensway_17_entrance",
|
|
151
133
|
alt: "Entrance foyer with original mosaic floor.",
|
|
152
134
|
tags: {
|
|
153
135
|
room: "entry",
|
|
@@ -155,8 +137,7 @@ const galleryPhotos = [
|
|
|
155
137
|
}
|
|
156
138
|
},
|
|
157
139
|
{
|
|
158
|
-
id: "
|
|
159
|
-
url: `${PHOTO_BASE}/18-patio.jpg`,
|
|
140
|
+
id: "dev_upl_queensway_18_patio",
|
|
160
141
|
alt: "Patio with built-in seating and planters.",
|
|
161
142
|
tags: {
|
|
162
143
|
room: "patio",
|
|
@@ -164,8 +145,7 @@ const galleryPhotos = [
|
|
|
164
145
|
}
|
|
165
146
|
},
|
|
166
147
|
{
|
|
167
|
-
id: "
|
|
168
|
-
url: `${PHOTO_BASE}/19-outdoor-deck.jpg`,
|
|
148
|
+
id: "dev_upl_queensway_19_outdoor_deck",
|
|
169
149
|
alt: "Outdoor deck with sunset view.",
|
|
170
150
|
tags: {
|
|
171
151
|
room: "deck",
|
|
@@ -173,8 +153,7 @@ const galleryPhotos = [
|
|
|
173
153
|
}
|
|
174
154
|
},
|
|
175
155
|
{
|
|
176
|
-
id: "
|
|
177
|
-
url: `${PHOTO_BASE}/20-exterior-hero.jpg`,
|
|
156
|
+
id: "dev_upl_queensway_20_exterior_hero",
|
|
178
157
|
alt: "Mansard victorian facade at golden hour.",
|
|
179
158
|
tags: {
|
|
180
159
|
room: "exterior-front",
|
|
@@ -183,56 +162,21 @@ const galleryPhotos = [
|
|
|
183
162
|
}
|
|
184
163
|
];
|
|
185
164
|
const allPhotos = galleryPhotos;
|
|
186
|
-
|
|
187
|
-
320,
|
|
188
|
-
640,
|
|
189
|
-
960,
|
|
190
|
-
1200,
|
|
191
|
-
1600,
|
|
192
|
-
2048
|
|
193
|
-
];
|
|
194
|
-
function mkResponsive(url, width, height) {
|
|
195
|
-
const widths = RUNG_WIDTHS.filter((w) => w <= width);
|
|
196
|
-
if (widths.length === 0) widths.push(width);
|
|
197
|
-
const ladder = (ext) => widths.map((w) => `${url}.${w}.${ext} ${w}w`).join(", ");
|
|
198
|
-
return {
|
|
199
|
-
sources: [
|
|
200
|
-
{
|
|
201
|
-
type: "image/avif",
|
|
202
|
-
srcset: ladder("avif")
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
type: "image/webp",
|
|
206
|
-
srcset: ladder("webp")
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
type: "image/jpeg",
|
|
210
|
-
srcset: ladder("jpg")
|
|
211
|
-
}
|
|
212
|
-
],
|
|
213
|
-
width,
|
|
214
|
-
height
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
const FP_BASE = "https://example.invalid/floorplans/queensway";
|
|
218
|
-
function fp(id, url, alt, floorLabel, position) {
|
|
165
|
+
function fp(id, floorLabel, position) {
|
|
219
166
|
return {
|
|
220
167
|
id,
|
|
221
|
-
url,
|
|
222
|
-
alt,
|
|
223
168
|
floor_label: floorLabel,
|
|
224
|
-
position
|
|
225
|
-
responsive: mkResponsive(url, 1024, 1024)
|
|
169
|
+
position
|
|
226
170
|
};
|
|
227
171
|
}
|
|
228
|
-
const FLOORPLAN_3BR = (suffix) => [fp(`
|
|
229
|
-
const FLOORPLAN_2BR = (suffix) => [fp(`
|
|
172
|
+
const FLOORPLAN_3BR = (suffix) => [fp(`dev_efp_queensway_3br_${suffix}_l1`, "Main Floor", 0), fp(`dev_efp_queensway_3br_${suffix}_l2`, "Upper Floor", 1)];
|
|
173
|
+
const FLOORPLAN_2BR = (suffix) => [fp(`dev_efp_queensway_2br_${suffix}_l1`, null, 0)];
|
|
230
174
|
const FLOORPLAN_4BR = (suffix) => [
|
|
231
|
-
fp(`
|
|
232
|
-
fp(`
|
|
233
|
-
fp(`
|
|
175
|
+
fp(`dev_efp_queensway_4br_${suffix}_l1`, "Main Floor", 0),
|
|
176
|
+
fp(`dev_efp_queensway_4br_${suffix}_l2`, "Upper Floor", 1),
|
|
177
|
+
fp(`dev_efp_queensway_4br_${suffix}_l3`, "Penthouse", 2)
|
|
234
178
|
];
|
|
235
|
-
const FLOORPLAN_STUDIO = (suffix) => [fp(`
|
|
179
|
+
const FLOORPLAN_STUDIO = (suffix) => [fp(`dev_efp_queensway_studio_${suffix}_l1`, null, 0)];
|
|
236
180
|
function unit(position, unitLabel, beds, baths, sqft, price, notes, description, features, floorPlans) {
|
|
237
181
|
return {
|
|
238
182
|
unit_id: `unit_${String(position + 1).padStart(2, "0")}`,
|
|
@@ -645,14 +589,14 @@ const sampleContacts = [
|
|
|
645
589
|
display_name: "James Donovan",
|
|
646
590
|
title: "Listing Agent",
|
|
647
591
|
bio: "James Donovan is a 15-year veteran of the Boston real estate market, specializing in historic multi-family conversions in Jamaica Plain and the South End. He has closed over $400M in residential transactions and is known for white-glove attention to multi-unit listings.",
|
|
648
|
-
|
|
592
|
+
headshot_id: "dev_lib_james_donovan",
|
|
649
593
|
website_url: "https://okane-marketing.example.invalid",
|
|
650
594
|
email: "info@homepages.io",
|
|
651
595
|
phone: "(617) 555-1068",
|
|
652
596
|
address: "677 Centre St, Suite 200, Jamaica Plain, MA 02130",
|
|
653
597
|
org_name: "Okane Marketing",
|
|
654
|
-
|
|
655
|
-
|
|
598
|
+
logo_light_id: "dev_lib_okane_logo_light",
|
|
599
|
+
logo_dark_id: "dev_lib_okane_logo_dark",
|
|
656
600
|
socials: [
|
|
657
601
|
{
|
|
658
602
|
platform: "instagram",
|
|
@@ -682,14 +626,14 @@ const sampleContacts = [
|
|
|
682
626
|
display_name: "Elena Marsh",
|
|
683
627
|
title: "Buyer's Agent",
|
|
684
628
|
bio: "Elena Marsh has guided over 120 buyer clients through the Boston multi-family market since joining the team in 2018, with a focus on Jamaica Plain, Roslindale, and West Roxbury first-time and investor purchases. She is a certified condo-conversion specialist and negotiates every offer personally.",
|
|
685
|
-
|
|
629
|
+
headshot_id: "dev_lib_elena_marsh",
|
|
686
630
|
website_url: "https://okane-marketing.example.invalid",
|
|
687
631
|
email: "elena@homepages.io",
|
|
688
632
|
phone: "(617) 555-2214",
|
|
689
633
|
address: "677 Centre St, Suite 200, Jamaica Plain, MA 02130",
|
|
690
634
|
org_name: "Okane Marketing",
|
|
691
|
-
|
|
692
|
-
|
|
635
|
+
logo_light_id: "dev_lib_okane_logo_light",
|
|
636
|
+
logo_dark_id: "dev_lib_okane_logo_dark",
|
|
693
637
|
socials: [{
|
|
694
638
|
platform: "instagram",
|
|
695
639
|
url: "https://instagram.com/elenamarsh.realty/"
|
|
@@ -708,14 +652,14 @@ const sampleContacts = [
|
|
|
708
652
|
display_name: "Marcus Webb",
|
|
709
653
|
title: "Director of Sales",
|
|
710
654
|
bio: "Marcus Webb leads the team's dispositions practice, working with investors and owner-occupants on multi-unit acquisitions and conversions across greater Boston. A former general contractor, he brings a builder's eye to every walkthrough and has overseen more than 60 multi-family closings.",
|
|
711
|
-
|
|
655
|
+
headshot_id: "dev_lib_marcus_webb",
|
|
712
656
|
website_url: "https://okane-marketing.example.invalid",
|
|
713
657
|
email: "marcus@homepages.io",
|
|
714
658
|
phone: "(617) 555-3357",
|
|
715
659
|
address: "677 Centre St, Suite 200, Jamaica Plain, MA 02130",
|
|
716
660
|
org_name: "Okane Marketing",
|
|
717
|
-
|
|
718
|
-
|
|
661
|
+
logo_light_id: "dev_lib_okane_logo_light",
|
|
662
|
+
logo_dark_id: "dev_lib_okane_logo_dark",
|
|
719
663
|
socials: [{
|
|
720
664
|
platform: "linkedin",
|
|
721
665
|
url: "https://linkedin.com/in/marcus-webb-realty/"
|
|
@@ -824,10 +768,10 @@ const sampleProperty = {
|
|
|
824
768
|
phone: c.fields.phone,
|
|
825
769
|
address: c.fields.address,
|
|
826
770
|
website_url: c.fields.website_url,
|
|
827
|
-
avatar_upload_id:
|
|
771
|
+
avatar_upload_id: c.fields.headshot_id,
|
|
828
772
|
org_name: c.fields.org_name,
|
|
829
|
-
logo_light_upload_id: c.fields.
|
|
830
|
-
logo_dark_upload_id: c.fields.
|
|
773
|
+
logo_light_upload_id: c.fields.logo_light_id,
|
|
774
|
+
logo_dark_upload_id: c.fields.logo_dark_id,
|
|
831
775
|
instagram_url: c.fields.socials.find((s) => s.platform === "instagram")?.url ?? null,
|
|
832
776
|
linkedin_url: c.fields.socials.find((s) => s.platform === "linkedin")?.url ?? null,
|
|
833
777
|
x_url: c.fields.socials.find((s) => s.platform === "x")?.url ?? null,
|
|
@@ -836,4 +780,4 @@ const sampleProperty = {
|
|
|
836
780
|
};
|
|
837
781
|
|
|
838
782
|
//#endregion
|
|
839
|
-
export { allPhotos,
|
|
783
|
+
export { allPhotos, sampleAmenities, sampleContacts, samplePois, sampleProperty };
|
|
@@ -3,7 +3,7 @@ import { AmenityItem, ContactFixture, PhotoFixture, PoiFixture } from "./sample-
|
|
|
3
3
|
//#region src/fixtures/scenario.d.ts
|
|
4
4
|
type ScenarioKey = "luxuryMultiUnit" | "sparseSingleFamily" | "forRentCondo";
|
|
5
5
|
type MediaFixture = {
|
|
6
|
-
|
|
6
|
+
video_id: string | null;
|
|
7
7
|
tour_3d_url: string | null;
|
|
8
8
|
};
|
|
9
9
|
type Scenario = {
|