@aglyn/aglyn 1.0.0-beta.217 → 1.0.0-beta.218
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/lib/app-utils/admin-audit-index.js +2 -2
- package/src/lib/app-utils/admin-audit-index.js.map +1 -1
- package/src/lib/app-utils/analytics-events.d.ts +10 -1
- package/src/lib/app-utils/analytics-events.js +11 -2
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/binding-tokens.js +1 -1
- package/src/lib/app-utils/binding-tokens.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +4 -4
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/lockdown.d.ts +33 -1
- package/src/lib/app-utils/lockdown.js +45 -4
- package/src/lib/app-utils/lockdown.js.map +1 -1
- package/src/lib/app-utils/marketplace-theme.js +3 -0
- package/src/lib/app-utils/marketplace-theme.js.map +1 -1
- package/src/lib/app-utils/screen-route.d.ts +15 -0
- package/src/lib/app-utils/screen-route.js +20 -0
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/starter-templates.d.ts +20 -0
- package/src/lib/app-utils/starter-templates.js +49 -0
- package/src/lib/app-utils/starter-templates.js.map +1 -1
- package/src/lib/canvas-manager/canvas-manager.js +3 -3
- package/src/lib/canvas-manager/canvas-manager.js.map +1 -1
- package/src/lib/foundation/definitions/org-billing.types.d.ts +9 -0
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/foundation/definitions/organization.types.d.ts +5 -0
- package/src/lib/foundation/definitions/organization.types.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +16 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/plugin-manager/first-party-plugins.generated.js +1 -4
- package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
|
@@ -350,6 +350,55 @@ const commerceBlock = (id, componentId, props)=>({
|
|
|
350
350
|
}
|
|
351
351
|
];
|
|
352
352
|
}
|
|
353
|
+
/**
|
|
354
|
+
* The home page every new site is born with (AGL-3408).
|
|
355
|
+
*
|
|
356
|
+
* A site used to be created with an empty routing map, so the address the
|
|
357
|
+
* create dialog calls live answered with the tenant's 404 until somebody
|
|
358
|
+
* built and published a page. `claimHostForOrg` now writes this screen, its
|
|
359
|
+
* first version and its `/` route in the same transaction that creates the
|
|
360
|
+
* host, which makes "a site with no home page" a state no new site starts in.
|
|
361
|
+
*
|
|
362
|
+
* It is PUBLIC from the first request, so the copy speaks to a visitor, never
|
|
363
|
+
* to the owner — no "edit this in the besigner". The site's name is written in
|
|
364
|
+
* as text, not bound: there is no page-content token for it, and a heading
|
|
365
|
+
* that followed a rename is not worth one.
|
|
366
|
+
*
|
|
367
|
+
* Deliberately not a starter: it is not offered in the gallery, and applying a
|
|
368
|
+
* starter may take the root back from it (see `defaultHomeScreenId`).
|
|
369
|
+
*
|
|
370
|
+
* PERSISTED IDENTIFIERS: every node id below is stored on every new site.
|
|
371
|
+
*/ export function buildDefaultHomeScreen(siteName) {
|
|
372
|
+
const name = siteName.trim() || 'Welcome';
|
|
373
|
+
return {
|
|
374
|
+
key: 'home',
|
|
375
|
+
displayName: 'Home',
|
|
376
|
+
slug: SCREEN_ROOT_PATH,
|
|
377
|
+
nodes: buildNodes([
|
|
378
|
+
section('dh_heroSection', 'md', 12, [
|
|
379
|
+
{
|
|
380
|
+
id: 'dh_hero',
|
|
381
|
+
componentId: 'muiStack',
|
|
382
|
+
props: {
|
|
383
|
+
spacing: 2
|
|
384
|
+
},
|
|
385
|
+
sx: {
|
|
386
|
+
alignItems: 'center'
|
|
387
|
+
},
|
|
388
|
+
children: [
|
|
389
|
+
text('dh_heroTitle', 'h2', name, {
|
|
390
|
+
align: 'center'
|
|
391
|
+
}),
|
|
392
|
+
text('dh_heroSub', 'h6', 'Welcome — our new website is on its way.', {
|
|
393
|
+
align: 'center',
|
|
394
|
+
color: 'text.secondary'
|
|
395
|
+
})
|
|
396
|
+
]
|
|
397
|
+
}
|
|
398
|
+
])
|
|
399
|
+
])
|
|
400
|
+
};
|
|
401
|
+
}
|
|
353
402
|
export const STARTER_TEMPLATES = [
|
|
354
403
|
{
|
|
355
404
|
id: 'landing',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/starter-templates.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Leaf imports only, deliberately (AGL-687). This module is imported from\n// BOTH graphs — the console's client gallery renders virtual starters from\n// it, the console's seed route materializes them, and the AI plugin's server\n// shows them to a model — and neither barrel works in both: the full\n// `@aglyn/aglyn` barrel breaks the RSC/server-route graph, while the server\n// entry drags `node:fs` into the client bundle. The canvas constants are a\n// leaf with no imports of their own, and `screen-route` imports only a TYPE\n// from foundation, so both are safe on either side.\nimport { CANVAS_ROOT_ELEMENT_ID } from '../foundation/constants/canvas'\nimport { normalizeScreenSlug, SCREEN_ROOT_PATH } from './screen-route'\n\n/**\n * First-party starter definitions (AGL-78/79), SEED INPUT (AGL-687).\n *\n * These used to be rendered straight into the gallery and instantiated from\n * code, which made a starter a second kind of template: no version history,\n * no placeholders, no editor, changeable only by shipping a release. Now\n * they are seeded into each host's own template library as ordinary\n * `hosts/{hostId}/templates` documents (see the console's\n * `utils/server/seed-starter-templates.ts` for why copy-on-use rather than a\n * global read-only collection), and nothing reads this file at render time.\n *\n * They are also the page examples the AI plugin's template generator shows a\n * model (AGL-2909), which is why they live in the core package rather than\n * beside the console gallery that renders them.\n *\n * Node ids stay template-local (unique within each screen's version doc);\n * `createPageFromTemplate` re-keys screen and version ids at instantiation.\n *\n * PERSISTED IDENTIFIERS: `StarterTemplate.id`, `StarterTemplateScreen.key`\n * and every node id below appear in stored documents (seeded template doc\n * ids are derived from the first two). They must never be renamed.\n */\nexport interface StarterTemplateScreen {\n /**\n * Stable, starter-local key. Part of the seeded document id, so it is a\n * persisted identifier — never rename one.\n */\n key: string\n displayName: string\n description?: string\n /**\n * Routing-map slug. `SCREEN_ROOT_PATH` (`'/'`) asks for the site root — the\n * home page — and anything else is a single path segment.\n *\n * It used to be `''` that meant home, which no normalizer agreed with: both\n * the apply path and the seed below read an empty string as \"no address\n * authored\" and derived one from the display name, so the shop starters'\n * home page was published at `/home` and the site 404'd at its own URL\n * (AGL-1575).\n */\n slug: string\n seo?: { title?: string; description?: string }\n /** Flat node map including the canvas root. */\n nodes: Record<string, any>\n}\n\nexport interface StarterTemplate {\n id: string\n displayName: string\n description: string\n category: string\n screens: StarterTemplateScreen[]\n}\n\n/** A materialized starter template document, keyed by its deterministic id. */\nexport interface StarterTemplateDoc {\n id: string\n /** Which starter this page belongs to — lets one starter be selected. */\n starterId: string\n data: Record<string, unknown>\n}\n\n/**\n * Deterministic document id for a seeded starter screen (AGL-687).\n *\n * Derived from the starter id and the screen key — never randomly generated\n * — so re-running the seed addresses the same documents instead of stacking\n * duplicate copies of every starter on every run.\n */\nexport function starterTemplateDocId(\n starterId: string,\n screenKey: string,\n): string {\n return `starter-${starterId}-${screenKey}`\n}\n\n/**\n * Expands one starter into the template documents it seeds as.\n *\n * One page template per screen, matching what a marketplace install of a\n * multi-screen site template already produces (AGL-669) — the alternative,\n * a bespoke multi-page template shape, would be a third lifecycle on top of\n * the two this issue exists to merge. The bundle's name/description/order\n * ride `source` so the gallery can still present the starter as one card.\n */\nexport function buildStarterTemplateDocs(\n starter: StarterTemplate,\n): StarterTemplateDoc[] {\n return starter.screens.map((screen, index) => {\n // Normalized on the way into the document so the persisted address is in\n // the routing-map format the tenant matches against — in particular the\n // root, which the previous `screen.slug ? …` guard dropped entirely when\n // home was spelled `''` (AGL-1575). A slug that sanitizes away carries no\n // field, and the apply path derives one from the display name.\n const slug = normalizeScreenSlug(screen.slug)\n return {\n id: starterTemplateDocId(starter.id, screen.key),\n starterId: starter.id,\n data: {\n kind: 'page',\n displayName: screen.displayName,\n // Only the screen's own description, never the starter blurb: a\n // template's `description` is carried onto the page it creates, and a\n // screen description is the live site's meta-description fallback.\n // The bundle blurb lives on `source.starterDescription` instead.\n ...(screen.description ? { description: screen.description } : {}),\n category: starter.category,\n ...(slug ? { slug } : {}),\n ...(screen.seo ? { seo: screen.seo } : {}),\n nodes: screen.nodes,\n source: {\n type: 'starter',\n starterId: starter.id,\n starterName: starter.displayName,\n starterDescription: starter.description,\n starterOrder: index,\n },\n },\n }\n })\n}\n\n/** Every document a starter COULD materialize as, in bundle order. */\nexport function buildAllStarterTemplateDocs(): StarterTemplateDoc[] {\n return STARTER_TEMPLATES.flatMap(buildStarterTemplateDocs)\n}\n\ntype NodeSpec = {\n id: string\n componentId: string\n /** Bundle owning the component; defaults to 'mui' (AGL-300). */\n pluginId?: string\n props?: Record<string, unknown>\n /**\n * Node-level styles — a SIBLING of props, never `props.sx` (AGL-1346).\n *\n * Both records render (`Leaf` composes `(sx, props.sx, node.sx)`, later\n * wins), but the Styles panel edits `node.sx`. A starter that seeded its\n * styling into `props.sx` handed the author a document full of values\n * the panel could show but no click could change or clear.\n */\n sx?: Record<string, unknown>\n children?: NodeSpec[]\n}\n\n/** Builds the flat, persisted node map from a nested spec. */\nfunction buildNodes(children: NodeSpec[]): Record<string, any> {\n const map: Record<string, any> = {\n [CANVAS_ROOT_ELEMENT_ID]: {\n $id: CANVAS_ROOT_ELEMENT_ID,\n componentId: 'div',\n nodes: children.map((child) => child.id),\n },\n }\n const walk = (spec: NodeSpec, parentId: string) => {\n map[spec.id] = {\n $id: spec.id,\n componentId: spec.componentId,\n pluginId: spec.pluginId ?? 'mui',\n parentId,\n props: spec.props ?? {},\n ...(spec.sx ? { sx: spec.sx } : {}),\n nodes: (spec.children ?? []).map((child) => child.id),\n }\n for (const child of spec.children ?? []) walk(child, spec.id)\n }\n for (const child of children) walk(child, CANVAS_ROOT_ELEMENT_ID)\n return map\n}\n\nconst text = (\n id: string,\n variant: string,\n children: string,\n extra?: Record<string, unknown>,\n): NodeSpec => ({\n id,\n componentId: 'muiTypography',\n props: { variant, children, ...extra },\n})\n\n/**\n * The stock widths a starter band may be (AGL-1932, AGL-1298).\n *\n * Three cases, and only three, because the standard has three. There is no\n * pixel case: `1328` is a CONTENT width, not a breakpoint, and the ban on\n * bespoke numbers is the half of AGL-1298 these templates used to violate\n * four times over.\n */\ntype SectionWidth = 'md' | 'lg' | 'xl'\n\n/**\n * One page band: a `Container` at a stock width, carrying the band's own\n * vertical rhythm (AGL-1932).\n *\n * The layout standard (AGL-1298): every section is a Container. Full-bleed is\n * the Container's own full-width attribute, never the absence of a Container,\n * and anything else is one of three stock widths. A template that seeds no\n * Container hands every customer a site that starts outside the standard.\n *\n * How the three widths are chosen here, stated so the next audit does not\n * have to guess:\n *\n * - `xl` — a marketing band: hero, feature row, product grid, gallery. The\n * default width, and what an unremarkable page should be.\n * - `lg` — the deliberate middle case: wide but text-led and interactive.\n * Cart and account are the honest instances, not decoration.\n * - `md` — long-form prose and narrow form columns, on READING grounds: at\n * `xl` a paragraph runs 110–120 characters a line. This is the case the\n * `Prose Container` preset exists for.\n *\n * Horizontal padding is the Container's own gutters, so bands no longer carry\n * horizontal padding at all. Only the vertical rhythm rides here, which is\n * rhythm rather than width.\n *\n * Written as the two longhands rather than MUI's `py` (AGL-2207/2208): the\n * Styles panel's Padding control is named for the four sides, so a band\n * seeded with `py` handed the customer a document whose padding the panel\n * showed as empty and no click could clear.\n */\nconst section = (\n id: string,\n maxWidth: SectionWidth,\n verticalPadding: number,\n children: NodeSpec[],\n): NodeSpec => ({\n id,\n componentId: 'muiContainer',\n props: { maxWidth },\n sx: { paddingTop: verticalPadding, paddingBottom: verticalPadding },\n children,\n})\n\nconst heroSection = (prefix: string, headline: string, tagline: string) =>\n // The Container is a NEW node (`…heroSection`); `…hero` keeps its id and\n // stays the Stack. Node ids here are persisted identifiers, so bands are\n // wrapped rather than re-pointed.\n section(`${prefix}heroSection`, 'xl', 10, [\n {\n id: `${prefix}hero`,\n componentId: 'muiStack',\n props: { spacing: 2 },\n sx: { alignItems: 'center' },\n children: [\n text(`${prefix}heroTitle`, 'h2', headline, { align: 'center' }),\n text(`${prefix}heroSub`, 'h6', tagline, { align: 'center' }),\n {\n id: `${prefix}heroCta`,\n componentId: 'muiButton',\n props: {\n variant: 'contained',\n size: 'large',\n children: 'Get in touch',\n },\n },\n ],\n },\n ])\n\nconst featureColumn = (id: string, title: string, body: string): NodeSpec => ({\n id,\n componentId: 'muiStack',\n props: { spacing: 1 },\n // `flex: 1` is a column's share of its row, not a width cap — it survives\n // the sweep deliberately. Only `maxWidth` in raw pixels was the violation.\n sx: {\n flex: 1,\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n },\n children: [text(`${id}T`, 'h5', title), text(`${id}B`, 'body1', body)],\n})\n\nconst contactForm = (prefix: string): NodeSpec => ({\n id: `${prefix}form`,\n componentId: 'form',\n props: {\n formName: 'Contact',\n submitLabel: 'Send message',\n successMessage: 'Thanks — we will get back to you soon.',\n },\n children: [\n {\n id: `${prefix}fName`,\n componentId: 'formField',\n props: { fieldName: 'name', label: 'Name', required: true },\n },\n {\n id: `${prefix}fEmail`,\n componentId: 'formField',\n props: {\n fieldName: 'email',\n label: 'Email',\n fieldType: 'email',\n required: true,\n },\n },\n {\n id: `${prefix}fMessage`,\n componentId: 'formField',\n props: {\n fieldName: 'message',\n label: 'Message',\n fieldType: 'textarea',\n required: true,\n },\n },\n ],\n})\n\n\nconst commerceBlock = (\n id: string,\n componentId: string,\n props?: Record<string, unknown>,\n): NodeSpec => ({ id, componentId, pluginId: 'commerce', props })\n\n/** Shared screens for the shop starters (AGL-300). */\nfunction shopScreens(prefix: string, digital: boolean): StarterTemplateScreen[] {\n return [\n {\n key: 'home',\n displayName: 'Home',\n // The site root, spelled the way the routing map spells it. `''` here\n // read as \"no address\" everywhere downstream and put the shop's home\n // page at `/home` (AGL-1575).\n slug: SCREEN_ROOT_PATH,\n seo: {\n title: digital ? 'Digital shop' : 'Shop',\n description: 'Browse our products.',\n },\n nodes: buildNodes([\n heroSection(\n `${prefix}h_`,\n digital ? 'Downloads that level you up' : 'Gear you can trust',\n digital\n ? 'Instant delivery. Lifetime updates.'\n : 'Quality parts, shipped fast.',\n ),\n section(`${prefix}h_gridSection`, 'xl', 6, [\n commerceBlock(`${prefix}h_grid`, 'product-grid', {\n source: 'all',\n sort: 'newest',\n columns: 3,\n maxItems: 6,\n }),\n ]),\n // A newsletter capture is a short text-led band, not a gallery.\n section(`${prefix}h_newsSection`, 'md', 6, [\n commerceBlock(`${prefix}h_news`, 'newsletter-signup', {\n heading: 'Get updates and offers',\n }),\n ]),\n ]),\n },\n {\n key: 'shop',\n displayName: 'Shop',\n slug: 'shop',\n seo: { title: 'All products' },\n nodes: buildNodes([\n section(`${prefix}s_section`, 'xl', 6, [\n text(`${prefix}s_title`, 'h3', 'All products'),\n commerceBlock(`${prefix}s_grid`, 'product-grid', {\n source: 'all',\n columns: 4,\n showFilters: true,\n }),\n ]),\n ]),\n },\n {\n key: 'product',\n displayName: 'Product page',\n slug: 'product',\n seo: { title: 'Product' },\n nodes: buildNodes([\n section(`${prefix}p_section`, 'xl', 6, [\n commerceBlock(`${prefix}p_detail`, 'product-detail', {}),\n ]),\n ]),\n },\n {\n key: 'cart',\n displayName: 'Cart',\n slug: 'cart',\n seo: { title: 'Your cart' },\n // LG, the deliberate middle case: a cart is a wide table but it is read\n // line by line, so a full XL band spreads it further than the eye\n // tracks. Same for the account screen below.\n nodes: buildNodes([\n section(`${prefix}c_section`, 'lg', 6, [\n text(`${prefix}c_title`, 'h3', 'Your cart'),\n commerceBlock(`${prefix}c_cart`, 'cart', {\n variant: 'inline',\n showCoupon: true,\n }),\n ]),\n ]),\n },\n {\n key: 'account',\n displayName: 'Account',\n slug: 'account',\n seo: { title: 'Your account' },\n nodes: buildNodes([\n section(`${prefix}a_section`, 'lg', 6, [\n commerceBlock(`${prefix}a_account`, 'customer-account', {\n signedOutHeading: 'Your account',\n }),\n ]),\n ]),\n },\n ]\n}\n\nexport const STARTER_TEMPLATES: StarterTemplate[] = [\n {\n id: 'landing',\n displayName: 'Landing Page',\n description:\n 'One-page launch site: hero, three selling points, and a contact form.',\n category: 'Marketing',\n screens: [\n {\n key: 'landing',\n displayName: 'Landing',\n slug: 'landing',\n seo: {\n title: 'Welcome',\n description: 'Everything you need to know, on one page.',\n },\n nodes: buildNodes([\n heroSection(\n 'l_',\n 'A headline that sells your idea',\n 'One clear sentence about the value you deliver.',\n ),\n section('l_featuresSection', 'xl', 6, [\n {\n id: 'l_features',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n featureColumn(\n 'l_f1',\n 'Fast',\n 'Explain the first reason customers pick you.',\n ),\n featureColumn(\n 'l_f2',\n 'Simple',\n 'Explain the second reason customers pick you.',\n ),\n featureColumn(\n 'l_f3',\n 'Reliable',\n 'Explain the third reason customers pick you.',\n ),\n ],\n },\n ]),\n // Was `maxWidth: 560`. A band, not an inner measure: it sat at the\n // top level carrying the section's own gutters and rhythm, so the\n // pixel value was capping the BAND. MD is the stock width for a\n // narrow, form-led column.\n section('l_contactSection', 'md', 6, [\n {\n id: 'l_contact',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('l_contactTitle', 'h4', 'Get in touch'),\n contactForm('l_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'business',\n displayName: 'Business',\n description:\n 'Company site: home with services, an about page, and a contact page.',\n category: 'Business',\n screens: [\n {\n key: 'home',\n displayName: 'Business Home',\n slug: 'home',\n seo: { title: 'Home' },\n nodes: buildNodes([\n heroSection(\n 'b_',\n 'Your business, done right',\n 'Tell visitors what you do and who you do it for.',\n ),\n section('b_servicesSection', 'xl', 6, [\n {\n id: 'b_services',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n featureColumn('b_s1', 'Service one', 'Describe this service.'),\n featureColumn('b_s2', 'Service two', 'Describe this service.'),\n featureColumn(\n 'b_s3',\n 'Service three',\n 'Describe this service.',\n ),\n ],\n },\n ]),\n ]),\n },\n {\n key: 'about-us',\n displayName: 'About Us',\n slug: 'about-us',\n seo: { title: 'About us' },\n nodes: buildNodes([\n // Was `maxWidth: 720` — the one unambiguous PROSE band in the set,\n // and the case the Prose Container preset exists for. MD (900px)\n // lands near the 65–75 characters a line that reads comfortably.\n section('a_wrapSection', 'md', 8, [\n {\n id: 'a_wrap',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('a_title', 'h3', 'About us'),\n text(\n 'a_body',\n 'body1',\n 'Share your story: how you started, what you believe, and ' +\n 'why customers trust you.',\n ),\n ],\n },\n ]),\n ]),\n },\n {\n key: 'contact-us',\n displayName: 'Contact Us',\n slug: 'contact-us',\n seo: { title: 'Contact' },\n nodes: buildNodes([\n // Was `maxWidth: 560`. Same reading as the landing page's contact\n // band: text plus a form column, so MD.\n section('c_wrapSection', 'md', 8, [\n {\n id: 'c_wrap',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('c_title', 'h3', 'Contact us'),\n text(\n 'c_body',\n 'body1',\n 'Questions or quotes — send a message and we reply within ' +\n 'one business day.',\n ),\n contactForm('c_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'portfolio',\n displayName: 'Portfolio',\n description: 'Personal portfolio: intro, work grid, and contact form.',\n category: 'Personal',\n screens: [\n {\n key: 'portfolio',\n displayName: 'Portfolio',\n slug: 'portfolio',\n seo: { title: 'Portfolio' },\n nodes: buildNodes([\n heroSection(\n 'p_',\n 'Hi, I make things',\n 'Designer / developer / photographer — introduce yourself here.',\n ),\n section('p_gridSection', 'xl', 6, [\n {\n id: 'p_grid',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n {\n id: 'p_img1',\n componentId: 'image',\n // `height` is an image's own intrinsic sizing prop, not a\n // band cap — out of scope for the container standard.\n props: { alt: 'Project one', height: '220px' },\n },\n {\n id: 'p_img2',\n componentId: 'image',\n props: { alt: 'Project two', height: '220px' },\n },\n {\n id: 'p_img3',\n componentId: 'image',\n props: { alt: 'Project three', height: '220px' },\n },\n ],\n },\n ]),\n // Was `maxWidth: 560`, the third of the three contact bands.\n section('p_contactSection', 'md', 6, [\n {\n id: 'p_contact',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('p_contactTitle', 'h4', 'Work with me'),\n contactForm('p_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'physical-shop',\n displayName: 'Shop (physical products)',\n description:\n 'Storefront starter: home with featured products, filterable shop, ' +\n 'product page, cart, and customer accounts. After applying, set the ' +\n 'Product page as the product template in Store settings.',\n category: 'Commerce',\n screens: shopScreens('ps_', false),\n },\n {\n id: 'digital-shop',\n displayName: 'Shop (digital products)',\n description:\n 'Digital storefront starter: downloads-focused home, shop, product ' +\n 'page, cart, and accounts with a newsletter capture. Set the Product ' +\n 'page as the product template in Store settings after applying.',\n category: 'Commerce',\n screens: shopScreens('ds_', true),\n },\n]\n"],"names":["CANVAS_ROOT_ELEMENT_ID","normalizeScreenSlug","SCREEN_ROOT_PATH","starterTemplateDocId","starterId","screenKey","buildStarterTemplateDocs","starter","screens","map","screen","index","slug","id","key","data","kind","displayName","description","category","seo","nodes","source","type","starterName","starterDescription","starterOrder","buildAllStarterTemplateDocs","STARTER_TEMPLATES","flatMap","buildNodes","children","$id","componentId","child","walk","spec","parentId","pluginId","props","sx","text","variant","extra","section","maxWidth","verticalPadding","paddingTop","paddingBottom","heroSection","prefix","headline","tagline","spacing","alignItems","align","size","featureColumn","title","body","flex","paddingRight","paddingLeft","contactForm","formName","submitLabel","successMessage","fieldName","label","required","fieldType","commerceBlock","shopScreens","digital","sort","columns","maxItems","heading","showFilters","showCoupon","signedOutHeading","direction","alt","height"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/starter-templates.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Leaf imports only, deliberately (AGL-687). This module is imported from\n// BOTH graphs — the console's client gallery renders virtual starters from\n// it, the console's seed route materializes them, and the AI plugin's server\n// shows them to a model — and neither barrel works in both: the full\n// `@aglyn/aglyn` barrel breaks the RSC/server-route graph, while the server\n// entry drags `node:fs` into the client bundle. The canvas constants are a\n// leaf with no imports of their own, and `screen-route` imports only a TYPE\n// from foundation, so both are safe on either side.\nimport { CANVAS_ROOT_ELEMENT_ID } from '../foundation/constants/canvas'\nimport { normalizeScreenSlug, SCREEN_ROOT_PATH } from './screen-route'\n\n/**\n * First-party starter definitions (AGL-78/79), SEED INPUT (AGL-687).\n *\n * These used to be rendered straight into the gallery and instantiated from\n * code, which made a starter a second kind of template: no version history,\n * no placeholders, no editor, changeable only by shipping a release. Now\n * they are seeded into each host's own template library as ordinary\n * `hosts/{hostId}/templates` documents (see the console's\n * `utils/server/seed-starter-templates.ts` for why copy-on-use rather than a\n * global read-only collection), and nothing reads this file at render time.\n *\n * They are also the page examples the AI plugin's template generator shows a\n * model (AGL-2909), which is why they live in the core package rather than\n * beside the console gallery that renders them.\n *\n * Node ids stay template-local (unique within each screen's version doc);\n * `createPageFromTemplate` re-keys screen and version ids at instantiation.\n *\n * PERSISTED IDENTIFIERS: `StarterTemplate.id`, `StarterTemplateScreen.key`\n * and every node id below appear in stored documents (seeded template doc\n * ids are derived from the first two). They must never be renamed.\n */\nexport interface StarterTemplateScreen {\n /**\n * Stable, starter-local key. Part of the seeded document id, so it is a\n * persisted identifier — never rename one.\n */\n key: string\n displayName: string\n description?: string\n /**\n * Routing-map slug. `SCREEN_ROOT_PATH` (`'/'`) asks for the site root — the\n * home page — and anything else is a single path segment.\n *\n * It used to be `''` that meant home, which no normalizer agreed with: both\n * the apply path and the seed below read an empty string as \"no address\n * authored\" and derived one from the display name, so the shop starters'\n * home page was published at `/home` and the site 404'd at its own URL\n * (AGL-1575).\n */\n slug: string\n seo?: { title?: string; description?: string }\n /** Flat node map including the canvas root. */\n nodes: Record<string, any>\n}\n\nexport interface StarterTemplate {\n id: string\n displayName: string\n description: string\n category: string\n screens: StarterTemplateScreen[]\n}\n\n/** A materialized starter template document, keyed by its deterministic id. */\nexport interface StarterTemplateDoc {\n id: string\n /** Which starter this page belongs to — lets one starter be selected. */\n starterId: string\n data: Record<string, unknown>\n}\n\n/**\n * Deterministic document id for a seeded starter screen (AGL-687).\n *\n * Derived from the starter id and the screen key — never randomly generated\n * — so re-running the seed addresses the same documents instead of stacking\n * duplicate copies of every starter on every run.\n */\nexport function starterTemplateDocId(\n starterId: string,\n screenKey: string,\n): string {\n return `starter-${starterId}-${screenKey}`\n}\n\n/**\n * Expands one starter into the template documents it seeds as.\n *\n * One page template per screen, matching what a marketplace install of a\n * multi-screen site template already produces (AGL-669) — the alternative,\n * a bespoke multi-page template shape, would be a third lifecycle on top of\n * the two this issue exists to merge. The bundle's name/description/order\n * ride `source` so the gallery can still present the starter as one card.\n */\nexport function buildStarterTemplateDocs(\n starter: StarterTemplate,\n): StarterTemplateDoc[] {\n return starter.screens.map((screen, index) => {\n // Normalized on the way into the document so the persisted address is in\n // the routing-map format the tenant matches against — in particular the\n // root, which the previous `screen.slug ? …` guard dropped entirely when\n // home was spelled `''` (AGL-1575). A slug that sanitizes away carries no\n // field, and the apply path derives one from the display name.\n const slug = normalizeScreenSlug(screen.slug)\n return {\n id: starterTemplateDocId(starter.id, screen.key),\n starterId: starter.id,\n data: {\n kind: 'page',\n displayName: screen.displayName,\n // Only the screen's own description, never the starter blurb: a\n // template's `description` is carried onto the page it creates, and a\n // screen description is the live site's meta-description fallback.\n // The bundle blurb lives on `source.starterDescription` instead.\n ...(screen.description ? { description: screen.description } : {}),\n category: starter.category,\n ...(slug ? { slug } : {}),\n ...(screen.seo ? { seo: screen.seo } : {}),\n nodes: screen.nodes,\n source: {\n type: 'starter',\n starterId: starter.id,\n starterName: starter.displayName,\n starterDescription: starter.description,\n starterOrder: index,\n },\n },\n }\n })\n}\n\n/** Every document a starter COULD materialize as, in bundle order. */\nexport function buildAllStarterTemplateDocs(): StarterTemplateDoc[] {\n return STARTER_TEMPLATES.flatMap(buildStarterTemplateDocs)\n}\n\ntype NodeSpec = {\n id: string\n componentId: string\n /** Bundle owning the component; defaults to 'mui' (AGL-300). */\n pluginId?: string\n props?: Record<string, unknown>\n /**\n * Node-level styles — a SIBLING of props, never `props.sx` (AGL-1346).\n *\n * Both records render (`Leaf` composes `(sx, props.sx, node.sx)`, later\n * wins), but the Styles panel edits `node.sx`. A starter that seeded its\n * styling into `props.sx` handed the author a document full of values\n * the panel could show but no click could change or clear.\n */\n sx?: Record<string, unknown>\n children?: NodeSpec[]\n}\n\n/** Builds the flat, persisted node map from a nested spec. */\nfunction buildNodes(children: NodeSpec[]): Record<string, any> {\n const map: Record<string, any> = {\n [CANVAS_ROOT_ELEMENT_ID]: {\n $id: CANVAS_ROOT_ELEMENT_ID,\n componentId: 'div',\n nodes: children.map((child) => child.id),\n },\n }\n const walk = (spec: NodeSpec, parentId: string) => {\n map[spec.id] = {\n $id: spec.id,\n componentId: spec.componentId,\n pluginId: spec.pluginId ?? 'mui',\n parentId,\n props: spec.props ?? {},\n ...(spec.sx ? { sx: spec.sx } : {}),\n nodes: (spec.children ?? []).map((child) => child.id),\n }\n for (const child of spec.children ?? []) walk(child, spec.id)\n }\n for (const child of children) walk(child, CANVAS_ROOT_ELEMENT_ID)\n return map\n}\n\nconst text = (\n id: string,\n variant: string,\n children: string,\n extra?: Record<string, unknown>,\n): NodeSpec => ({\n id,\n componentId: 'muiTypography',\n props: { variant, children, ...extra },\n})\n\n/**\n * The stock widths a starter band may be (AGL-1932, AGL-1298).\n *\n * Three cases, and only three, because the standard has three. There is no\n * pixel case: `1328` is a CONTENT width, not a breakpoint, and the ban on\n * bespoke numbers is the half of AGL-1298 these templates used to violate\n * four times over.\n */\ntype SectionWidth = 'md' | 'lg' | 'xl'\n\n/**\n * One page band: a `Container` at a stock width, carrying the band's own\n * vertical rhythm (AGL-1932).\n *\n * The layout standard (AGL-1298): every section is a Container. Full-bleed is\n * the Container's own full-width attribute, never the absence of a Container,\n * and anything else is one of three stock widths. A template that seeds no\n * Container hands every customer a site that starts outside the standard.\n *\n * How the three widths are chosen here, stated so the next audit does not\n * have to guess:\n *\n * - `xl` — a marketing band: hero, feature row, product grid, gallery. The\n * default width, and what an unremarkable page should be.\n * - `lg` — the deliberate middle case: wide but text-led and interactive.\n * Cart and account are the honest instances, not decoration.\n * - `md` — long-form prose and narrow form columns, on READING grounds: at\n * `xl` a paragraph runs 110–120 characters a line. This is the case the\n * `Prose Container` preset exists for.\n *\n * Horizontal padding is the Container's own gutters, so bands no longer carry\n * horizontal padding at all. Only the vertical rhythm rides here, which is\n * rhythm rather than width.\n *\n * Written as the two longhands rather than MUI's `py` (AGL-2207/2208): the\n * Styles panel's Padding control is named for the four sides, so a band\n * seeded with `py` handed the customer a document whose padding the panel\n * showed as empty and no click could clear.\n */\nconst section = (\n id: string,\n maxWidth: SectionWidth,\n verticalPadding: number,\n children: NodeSpec[],\n): NodeSpec => ({\n id,\n componentId: 'muiContainer',\n props: { maxWidth },\n sx: { paddingTop: verticalPadding, paddingBottom: verticalPadding },\n children,\n})\n\nconst heroSection = (prefix: string, headline: string, tagline: string) =>\n // The Container is a NEW node (`…heroSection`); `…hero` keeps its id and\n // stays the Stack. Node ids here are persisted identifiers, so bands are\n // wrapped rather than re-pointed.\n section(`${prefix}heroSection`, 'xl', 10, [\n {\n id: `${prefix}hero`,\n componentId: 'muiStack',\n props: { spacing: 2 },\n sx: { alignItems: 'center' },\n children: [\n text(`${prefix}heroTitle`, 'h2', headline, { align: 'center' }),\n text(`${prefix}heroSub`, 'h6', tagline, { align: 'center' }),\n {\n id: `${prefix}heroCta`,\n componentId: 'muiButton',\n props: {\n variant: 'contained',\n size: 'large',\n children: 'Get in touch',\n },\n },\n ],\n },\n ])\n\nconst featureColumn = (id: string, title: string, body: string): NodeSpec => ({\n id,\n componentId: 'muiStack',\n props: { spacing: 1 },\n // `flex: 1` is a column's share of its row, not a width cap — it survives\n // the sweep deliberately. Only `maxWidth` in raw pixels was the violation.\n sx: {\n flex: 1,\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n },\n children: [text(`${id}T`, 'h5', title), text(`${id}B`, 'body1', body)],\n})\n\nconst contactForm = (prefix: string): NodeSpec => ({\n id: `${prefix}form`,\n componentId: 'form',\n props: {\n formName: 'Contact',\n submitLabel: 'Send message',\n successMessage: 'Thanks — we will get back to you soon.',\n },\n children: [\n {\n id: `${prefix}fName`,\n componentId: 'formField',\n props: { fieldName: 'name', label: 'Name', required: true },\n },\n {\n id: `${prefix}fEmail`,\n componentId: 'formField',\n props: {\n fieldName: 'email',\n label: 'Email',\n fieldType: 'email',\n required: true,\n },\n },\n {\n id: `${prefix}fMessage`,\n componentId: 'formField',\n props: {\n fieldName: 'message',\n label: 'Message',\n fieldType: 'textarea',\n required: true,\n },\n },\n ],\n})\n\n\nconst commerceBlock = (\n id: string,\n componentId: string,\n props?: Record<string, unknown>,\n): NodeSpec => ({ id, componentId, pluginId: 'commerce', props })\n\n/** Shared screens for the shop starters (AGL-300). */\nfunction shopScreens(prefix: string, digital: boolean): StarterTemplateScreen[] {\n return [\n {\n key: 'home',\n displayName: 'Home',\n // The site root, spelled the way the routing map spells it. `''` here\n // read as \"no address\" everywhere downstream and put the shop's home\n // page at `/home` (AGL-1575).\n slug: SCREEN_ROOT_PATH,\n seo: {\n title: digital ? 'Digital shop' : 'Shop',\n description: 'Browse our products.',\n },\n nodes: buildNodes([\n heroSection(\n `${prefix}h_`,\n digital ? 'Downloads that level you up' : 'Gear you can trust',\n digital\n ? 'Instant delivery. Lifetime updates.'\n : 'Quality parts, shipped fast.',\n ),\n section(`${prefix}h_gridSection`, 'xl', 6, [\n commerceBlock(`${prefix}h_grid`, 'product-grid', {\n source: 'all',\n sort: 'newest',\n columns: 3,\n maxItems: 6,\n }),\n ]),\n // A newsletter capture is a short text-led band, not a gallery.\n section(`${prefix}h_newsSection`, 'md', 6, [\n commerceBlock(`${prefix}h_news`, 'newsletter-signup', {\n heading: 'Get updates and offers',\n }),\n ]),\n ]),\n },\n {\n key: 'shop',\n displayName: 'Shop',\n slug: 'shop',\n seo: { title: 'All products' },\n nodes: buildNodes([\n section(`${prefix}s_section`, 'xl', 6, [\n text(`${prefix}s_title`, 'h3', 'All products'),\n commerceBlock(`${prefix}s_grid`, 'product-grid', {\n source: 'all',\n columns: 4,\n showFilters: true,\n }),\n ]),\n ]),\n },\n {\n key: 'product',\n displayName: 'Product page',\n slug: 'product',\n seo: { title: 'Product' },\n nodes: buildNodes([\n section(`${prefix}p_section`, 'xl', 6, [\n commerceBlock(`${prefix}p_detail`, 'product-detail', {}),\n ]),\n ]),\n },\n {\n key: 'cart',\n displayName: 'Cart',\n slug: 'cart',\n seo: { title: 'Your cart' },\n // LG, the deliberate middle case: a cart is a wide table but it is read\n // line by line, so a full XL band spreads it further than the eye\n // tracks. Same for the account screen below.\n nodes: buildNodes([\n section(`${prefix}c_section`, 'lg', 6, [\n text(`${prefix}c_title`, 'h3', 'Your cart'),\n commerceBlock(`${prefix}c_cart`, 'cart', {\n variant: 'inline',\n showCoupon: true,\n }),\n ]),\n ]),\n },\n {\n key: 'account',\n displayName: 'Account',\n slug: 'account',\n seo: { title: 'Your account' },\n nodes: buildNodes([\n section(`${prefix}a_section`, 'lg', 6, [\n commerceBlock(`${prefix}a_account`, 'customer-account', {\n signedOutHeading: 'Your account',\n }),\n ]),\n ]),\n },\n ]\n}\n\n/**\n * The home page every new site is born with (AGL-3408).\n *\n * A site used to be created with an empty routing map, so the address the\n * create dialog calls live answered with the tenant's 404 until somebody\n * built and published a page. `claimHostForOrg` now writes this screen, its\n * first version and its `/` route in the same transaction that creates the\n * host, which makes \"a site with no home page\" a state no new site starts in.\n *\n * It is PUBLIC from the first request, so the copy speaks to a visitor, never\n * to the owner — no \"edit this in the besigner\". The site's name is written in\n * as text, not bound: there is no page-content token for it, and a heading\n * that followed a rename is not worth one.\n *\n * Deliberately not a starter: it is not offered in the gallery, and applying a\n * starter may take the root back from it (see `defaultHomeScreenId`).\n *\n * PERSISTED IDENTIFIERS: every node id below is stored on every new site.\n */\nexport function buildDefaultHomeScreen(siteName: string): StarterTemplateScreen {\n const name = siteName.trim() || 'Welcome'\n return {\n key: 'home',\n displayName: 'Home',\n slug: SCREEN_ROOT_PATH,\n nodes: buildNodes([\n section('dh_heroSection', 'md', 12, [\n {\n id: 'dh_hero',\n componentId: 'muiStack',\n props: { spacing: 2 },\n sx: { alignItems: 'center' },\n children: [\n text('dh_heroTitle', 'h2', name, { align: 'center' }),\n text(\n 'dh_heroSub',\n 'h6',\n 'Welcome — our new website is on its way.',\n { align: 'center', color: 'text.secondary' },\n ),\n ],\n },\n ]),\n ]),\n }\n}\n\nexport const STARTER_TEMPLATES: StarterTemplate[] = [\n {\n id: 'landing',\n displayName: 'Landing Page',\n description:\n 'One-page launch site: hero, three selling points, and a contact form.',\n category: 'Marketing',\n screens: [\n {\n key: 'landing',\n displayName: 'Landing',\n slug: 'landing',\n seo: {\n title: 'Welcome',\n description: 'Everything you need to know, on one page.',\n },\n nodes: buildNodes([\n heroSection(\n 'l_',\n 'A headline that sells your idea',\n 'One clear sentence about the value you deliver.',\n ),\n section('l_featuresSection', 'xl', 6, [\n {\n id: 'l_features',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n featureColumn(\n 'l_f1',\n 'Fast',\n 'Explain the first reason customers pick you.',\n ),\n featureColumn(\n 'l_f2',\n 'Simple',\n 'Explain the second reason customers pick you.',\n ),\n featureColumn(\n 'l_f3',\n 'Reliable',\n 'Explain the third reason customers pick you.',\n ),\n ],\n },\n ]),\n // Was `maxWidth: 560`. A band, not an inner measure: it sat at the\n // top level carrying the section's own gutters and rhythm, so the\n // pixel value was capping the BAND. MD is the stock width for a\n // narrow, form-led column.\n section('l_contactSection', 'md', 6, [\n {\n id: 'l_contact',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('l_contactTitle', 'h4', 'Get in touch'),\n contactForm('l_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'business',\n displayName: 'Business',\n description:\n 'Company site: home with services, an about page, and a contact page.',\n category: 'Business',\n screens: [\n {\n key: 'home',\n displayName: 'Business Home',\n slug: 'home',\n seo: { title: 'Home' },\n nodes: buildNodes([\n heroSection(\n 'b_',\n 'Your business, done right',\n 'Tell visitors what you do and who you do it for.',\n ),\n section('b_servicesSection', 'xl', 6, [\n {\n id: 'b_services',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n featureColumn('b_s1', 'Service one', 'Describe this service.'),\n featureColumn('b_s2', 'Service two', 'Describe this service.'),\n featureColumn(\n 'b_s3',\n 'Service three',\n 'Describe this service.',\n ),\n ],\n },\n ]),\n ]),\n },\n {\n key: 'about-us',\n displayName: 'About Us',\n slug: 'about-us',\n seo: { title: 'About us' },\n nodes: buildNodes([\n // Was `maxWidth: 720` — the one unambiguous PROSE band in the set,\n // and the case the Prose Container preset exists for. MD (900px)\n // lands near the 65–75 characters a line that reads comfortably.\n section('a_wrapSection', 'md', 8, [\n {\n id: 'a_wrap',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('a_title', 'h3', 'About us'),\n text(\n 'a_body',\n 'body1',\n 'Share your story: how you started, what you believe, and ' +\n 'why customers trust you.',\n ),\n ],\n },\n ]),\n ]),\n },\n {\n key: 'contact-us',\n displayName: 'Contact Us',\n slug: 'contact-us',\n seo: { title: 'Contact' },\n nodes: buildNodes([\n // Was `maxWidth: 560`. Same reading as the landing page's contact\n // band: text plus a form column, so MD.\n section('c_wrapSection', 'md', 8, [\n {\n id: 'c_wrap',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('c_title', 'h3', 'Contact us'),\n text(\n 'c_body',\n 'body1',\n 'Questions or quotes — send a message and we reply within ' +\n 'one business day.',\n ),\n contactForm('c_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'portfolio',\n displayName: 'Portfolio',\n description: 'Personal portfolio: intro, work grid, and contact form.',\n category: 'Personal',\n screens: [\n {\n key: 'portfolio',\n displayName: 'Portfolio',\n slug: 'portfolio',\n seo: { title: 'Portfolio' },\n nodes: buildNodes([\n heroSection(\n 'p_',\n 'Hi, I make things',\n 'Designer / developer / photographer — introduce yourself here.',\n ),\n section('p_gridSection', 'xl', 6, [\n {\n id: 'p_grid',\n componentId: 'muiStack',\n props: { direction: 'row', spacing: 2 },\n children: [\n {\n id: 'p_img1',\n componentId: 'image',\n // `height` is an image's own intrinsic sizing prop, not a\n // band cap — out of scope for the container standard.\n props: { alt: 'Project one', height: '220px' },\n },\n {\n id: 'p_img2',\n componentId: 'image',\n props: { alt: 'Project two', height: '220px' },\n },\n {\n id: 'p_img3',\n componentId: 'image',\n props: { alt: 'Project three', height: '220px' },\n },\n ],\n },\n ]),\n // Was `maxWidth: 560`, the third of the three contact bands.\n section('p_contactSection', 'md', 6, [\n {\n id: 'p_contact',\n componentId: 'muiStack',\n props: { spacing: 2 },\n children: [\n text('p_contactTitle', 'h4', 'Work with me'),\n contactForm('p_'),\n ],\n },\n ]),\n ]),\n },\n ],\n },\n {\n id: 'physical-shop',\n displayName: 'Shop (physical products)',\n description:\n 'Storefront starter: home with featured products, filterable shop, ' +\n 'product page, cart, and customer accounts. After applying, set the ' +\n 'Product page as the product template in Store settings.',\n category: 'Commerce',\n screens: shopScreens('ps_', false),\n },\n {\n id: 'digital-shop',\n displayName: 'Shop (digital products)',\n description:\n 'Digital storefront starter: downloads-focused home, shop, product ' +\n 'page, cart, and accounts with a newsletter capture. Set the Product ' +\n 'page as the product template in Store settings after applying.',\n category: 'Commerce',\n screens: shopScreens('ds_', true),\n },\n]\n"],"names":["CANVAS_ROOT_ELEMENT_ID","normalizeScreenSlug","SCREEN_ROOT_PATH","starterTemplateDocId","starterId","screenKey","buildStarterTemplateDocs","starter","screens","map","screen","index","slug","id","key","data","kind","displayName","description","category","seo","nodes","source","type","starterName","starterDescription","starterOrder","buildAllStarterTemplateDocs","STARTER_TEMPLATES","flatMap","buildNodes","children","$id","componentId","child","walk","spec","parentId","pluginId","props","sx","text","variant","extra","section","maxWidth","verticalPadding","paddingTop","paddingBottom","heroSection","prefix","headline","tagline","spacing","alignItems","align","size","featureColumn","title","body","flex","paddingRight","paddingLeft","contactForm","formName","submitLabel","successMessage","fieldName","label","required","fieldType","commerceBlock","shopScreens","digital","sort","columns","maxItems","heading","showFilters","showCoupon","signedOutHeading","buildDefaultHomeScreen","siteName","name","trim","color","direction","alt","height"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
18
18
|
import { arraySafe } from "@aglyn/shared-util-tools";
|
|
19
19
|
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
20
20
|
import isEqual from "lodash-es/isEqual.js";
|
|
21
|
-
import { action, computed, makeAutoObservable, makeObservable, observable, runInAction, toJS } from "mobx";
|
|
21
|
+
import { action, computed, makeAutoObservable, makeObservable, observable, observableRef, runInAction, toJS } from "mobx";
|
|
22
22
|
// The leaf module, not the 68 KB package bundle — see the note there.
|
|
23
23
|
import { computedFn } from "@aglyn/shared-util-vendor/mobx-computed-fn";
|
|
24
24
|
import { schemaAcceptsChildren } from "../app-utils/child-contract.js";
|
|
@@ -1327,13 +1327,13 @@ export class CanvasManager {
|
|
|
1327
1327
|
return newNode;
|
|
1328
1328
|
});
|
|
1329
1329
|
makeObservable(this, {
|
|
1330
|
-
_initial:
|
|
1330
|
+
_initial: observableRef,
|
|
1331
1331
|
_initialConfirmed: observable,
|
|
1332
1332
|
// Observable for the same reason `_epoch` is: {@link isDraftedSame} is
|
|
1333
1333
|
// read while rendering the toolbar, and the label it decides has to
|
|
1334
1334
|
// change on the author's next keystroke rather than on the next
|
|
1335
1335
|
// unrelated render (AGL-3271).
|
|
1336
|
-
_drafted:
|
|
1336
|
+
_drafted: observableRef,
|
|
1337
1337
|
// Observable so {@link hasRemoteEdits} is a computed a React observer
|
|
1338
1338
|
// re-renders on: the draft prompt has to stop offering Restore the
|
|
1339
1339
|
// moment a peer's first change lands, not on the next unrelated
|