@aglyn/plugins-ai 1.0.0-beta.292 → 1.0.0-beta.293

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-site-import-job.component.js +5 -4
  3. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  4. package/src/lib/components/ai-site-import-start.component.js +3 -3
  5. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  6. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  7. package/src/lib/components/ai-site-start-card.component.js +129 -29
  8. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  9. package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
  10. package/src/lib/components/ai-site-start-steps.component.js +42 -25
  11. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  12. package/src/lib/components/ai-site-style-previews.d.ts +17 -0
  13. package/src/lib/components/ai-site-style-previews.js +26 -95
  14. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  15. package/src/lib/declarations.server.js +22 -0
  16. package/src/lib/declarations.server.js.map +1 -1
  17. package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
  18. package/src/lib/jobs/ai-job-import-step.js +179 -49
  19. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  20. package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
  21. package/src/lib/jobs/ai-job-layout-language.js +156 -113
  22. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  23. package/src/lib/jobs/ai-job-layout-step.js +56 -17
  24. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  25. package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
  26. package/src/lib/jobs/ai-job-page-language.js +120 -66
  27. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  28. package/src/lib/jobs/ai-job-page-step.js +27 -7
  29. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  30. package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
  31. package/src/lib/jobs/ai-job-site-datasets.js +36 -16
  32. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  33. package/src/lib/jobs/ai-jobs.js +6 -2
  34. package/src/lib/jobs/ai-jobs.js.map +1 -1
  35. package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
  36. package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
  37. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  38. package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
  39. package/src/lib/jobs/ai-site-import-compile.js +1143 -0
  40. package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
  41. package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
  42. package/src/lib/jobs/ai-site-import-document.js +23 -489
  43. package/src/lib/jobs/ai-site-import-document.js.map +1 -1
  44. package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
  45. package/src/lib/jobs/ai-site-import-look.js +163 -52
  46. package/src/lib/jobs/ai-site-import-look.js.map +1 -1
  47. package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
  48. package/src/lib/jobs/ai-site-import-publish.js +19 -5
  49. package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
  50. package/src/lib/jobs/ai-site-late-photos.js +4 -2
  51. package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
  52. package/src/lib/jobs/ai-site-publish.d.ts +10 -1
  53. package/src/lib/jobs/ai-site-publish.js +8 -3
  54. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  55. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
  56. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
  57. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
  58. package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
  59. package/src/lib/layout-language/ai-layout-compiler.js +677 -33
  60. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  61. package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
  62. package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
  63. package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
  64. package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
  65. package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
  66. package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
  67. package/src/lib/layout-language/ai-layout-frame.js +121 -29
  68. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  69. package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
  70. package/src/lib/layout-language/ai-layout-language.js +85 -120
  71. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  72. package/src/lib/model/ai-credit-estimate.d.ts +11 -7
  73. package/src/lib/model/ai-credit-estimate.js +11 -7
  74. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  75. package/src/lib/model/ai-site-import.d.ts +307 -13
  76. package/src/lib/model/ai-site-import.js +227 -19
  77. package/src/lib/model/ai-site-import.js.map +1 -1
  78. package/src/lib/model/ai-site-look.d.ts +65 -1
  79. package/src/lib/model/ai-site-look.js +141 -23
  80. package/src/lib/model/ai-site-look.js.map +1 -1
  81. package/src/lib/model/ai-site-photos.d.ts +2 -0
  82. package/src/lib/model/ai-site-photos.js.map +1 -1
  83. package/src/lib/model/ai-site-start-steps.d.ts +4 -3
  84. package/src/lib/model/ai-site-start-steps.js +11 -3
  85. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  86. package/src/lib/model/ai-site-start.d.ts +23 -2
  87. package/src/lib/model/ai-site-start.js +25 -3
  88. package/src/lib/model/ai-site-start.js.map +1 -1
  89. package/src/lib/providers/routing.d.ts +11 -0
  90. package/src/lib/providers/routing.js +23 -0
  91. package/src/lib/providers/routing.js.map +1 -1
  92. package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
  93. package/src/lib/runtime/ai-doctrine-validators.js +7 -2
  94. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  95. package/src/lib/runtime/ai-icon-library.d.ts +4 -0
  96. package/src/lib/runtime/ai-icon-library.js +4 -0
  97. package/src/lib/runtime/ai-icon-library.js.map +1 -1
  98. package/src/lib/runtime/ai-node-tree.js +5 -1
  99. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  100. package/src/lib/runtime/ai-palette.d.ts +2 -0
  101. package/src/lib/runtime/ai-palette.generated.js +19 -3
  102. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  103. package/src/lib/runtime/ai-palette.js +2 -1
  104. package/src/lib/runtime/ai-palette.js.map +1 -1
  105. package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
  106. package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
  107. package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
  108. package/src/lib/site-import/site-import-crawl.d.ts +18 -1
  109. package/src/lib/site-import/site-import-crawl.js +70 -10
  110. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  111. package/src/lib/site-import/site-import-css.d.ts +110 -0
  112. package/src/lib/site-import/site-import-css.js +826 -0
  113. package/src/lib/site-import/site-import-css.js.map +1 -0
  114. package/src/lib/site-import/site-import-html.d.ts +116 -1
  115. package/src/lib/site-import/site-import-html.js +538 -46
  116. package/src/lib/site-import/site-import-html.js.map +1 -1
  117. package/src/lib/site-import/site-import-layout.d.ts +79 -0
  118. package/src/lib/site-import/site-import-layout.js +1608 -0
  119. package/src/lib/site-import/site-import-layout.js.map +1 -0
  120. package/src/lib/site-import/site-import-nav.d.ts +40 -0
  121. package/src/lib/site-import/site-import-nav.js +437 -0
  122. package/src/lib/site-import/site-import-nav.js.map +1 -0
  123. package/src/lib/site-import/site-import-page.d.ts +8 -1
  124. package/src/lib/site-import/site-import-page.js +24 -2
  125. package/src/lib/site-import/site-import-page.js.map +1 -1
  126. package/src/lib/assets/site-styles/beauty.webp +0 -0
  127. package/src/lib/assets/site-styles/blog.webp +0 -0
  128. package/src/lib/assets/site-styles/business.webp +0 -0
  129. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  130. package/src/lib/assets/site-styles/education.webp +0 -0
  131. package/src/lib/assets/site-styles/events.webp +0 -0
  132. package/src/lib/assets/site-styles/fitness.webp +0 -0
  133. package/src/lib/assets/site-styles/landing.webp +0 -0
  134. package/src/lib/assets/site-styles/music.webp +0 -0
  135. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  136. package/src/lib/assets/site-styles/personal.webp +0 -0
  137. package/src/lib/assets/site-styles/photography.webp +0 -0
  138. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  139. package/src/lib/assets/site-styles/professional.webp +0 -0
  140. package/src/lib/assets/site-styles/realestate.webp +0 -0
  141. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  142. package/src/lib/assets/site-styles/store.webp +0 -0
  143. package/src/lib/assets/site-styles/studio.webp +0 -0
  144. package/src/lib/assets/site-styles/trades.webp +0 -0
  145. package/src/lib/assets/site-styles/wellness.webp +0 -0
  146. package/src/lib/assets/site-styles/yoga.webp +0 -0
  147. package/src/lib/site-import/site-import-review.d.ts +0 -40
  148. package/src/lib/site-import/site-import-review.js +0 -149
  149. package/src/lib/site-import/site-import-review.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/layout-language/ai-layout-frame-source.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/*==========================================\n * A HEADER AND FOOTER BROUGHT IN AS THE SOURCE BUILDS THEM (AGL-4108).\n *\n * On 10/29 an imported header was the wave's page titles, seven of them cut\n * to 28 characters, wrapping onto two and three lines from 900 px up, with\n * no menus, its logo over \"Home\" at 1280 and its \"Start free\" sent to the\n * Forms page. The source's own header was five items, two of them menus,\n * and two buttons that leave for the app.\n *\n * So a site brought in from elsewhere is given its source's header and\n * footer as the reader found them (`site-import-nav.ts`), and they are drawn\n * here by code, with no model:\n *\n * - **The menu.** Each top-level item as the source has it: a link, or a\n * menu of its entries — the Besigner's Mega Menu where its entries carry a\n * line under them or sit in headed columns, its Dropdown Menu otherwise.\n * Every label on one line. The row shows from the screen width it fits at\n * (`aiLayoutNavBreakpoint`), and below it the phone menu's button.\n * - **The buttons.** The source's own, with their own addresses: an address\n * off the site stays off it, as the source sends it. Drawn as the source\n * draws them: filled, outlined or as text.\n * - **The phone menu.** Each menu as a heading over its entries, then the\n * links, then the buttons: every part of the menu as present as the rest.\n * - **The footer.** The source's columns under their headings, its words,\n * its profiles, its address, phone and email, and its © line word for word.\n *\n * Every word is the source's, as written; nothing here is a model's.\n *=========================================*/\n\nimport { aiIsIconPathData } from '../runtime/ai-icon-library'\nimport { isContactHref, isHttpsUrl, isRootRelativePath } from '../runtime/ai-node-tree'\nimport type { AiLayoutTreeBuilder } from './ai-layout-tree'\n\n/** How a source's button is drawn: filled, outlined, or as text. */\nexport type AiLayoutFrameSourceStyle = 'primary' | 'secondary' | 'quiet'\n\n/**\n * Where a link of a source's header or footer goes: `page:<id>` for a page of\n * the site, a path on the site (`/pricing`) for a page still to come in, or\n * the source's own address (`https:`, `mailto:`, `tel:`) for anywhere else.\n */\nexport type AiLayoutFrameSourceTo = string\n\nexport interface AiLayoutFrameSourceLink {\n label: string\n to: AiLayoutFrameSourceTo\n}\n\n/** One entry of a menu. */\nexport interface AiLayoutFrameSourceEntry extends AiLayoutFrameSourceLink {\n /** The line under it in a mega menu. */\n text?: string\n /** Its icon, drawn on a 24-unit square. */\n iconPath?: string\n /** The heading of the menu's column it sits in. */\n column?: string\n}\n\n/** A top-level item: a link, or a menu of entries under a name. */\nexport interface AiLayoutFrameSourceGroup {\n label: string\n /** Where the name itself goes; `null` when it only opens its menu. */\n to: AiLayoutFrameSourceTo | null\n /** Empty for a plain link. */\n items: AiLayoutFrameSourceEntry[]\n}\n\nexport interface AiLayoutFrameSourceCta extends AiLayoutFrameSourceLink {\n style: AiLayoutFrameSourceStyle\n}\n\nexport interface AiLayoutFrameSourceFooter {\n columns: Array<{ heading: string; links: AiLayoutFrameSourceLink[] }>\n /** Links outside any column and not a profile (Privacy, Terms). */\n links: AiLayoutFrameSourceLink[]\n /** Its lines of words outside links, as written. */\n text: string[]\n /** Its profiles on other sites, by network. */\n social: Array<AiLayoutFrameSourceLink & { network: string }>\n address: string | null\n phone: string | null\n email: string | null\n /** Its © line, word for word. */\n copyright: string | null\n}\n\n/**\n * What the source's header bar sits on: the page's own ground, paper, the\n * brand color, or a dark band.\n */\nexport type AiLayoutFrameSourceGround = 'page' | 'paper' | 'brand' | 'dark'\n\n/** A header and footer as the source builds them (AGL-4108). */\nexport interface AiLayoutFrameSource {\n nav: AiLayoutFrameSourceGroup[]\n ctas: AiLayoutFrameSourceCta[]\n header: AiLayoutFrameSourceGround\n footer: AiLayoutFrameSourceFooter | null\n}\n\n/** The most kept of each part: the reader's own limits, held again on the way in. */\nexport const AI_LAYOUT_FRAME_SOURCE_LIMITS = { groups: 12, entries: 40, ctas: 4, columns: 12, links: 60, text: 12, social: 20, label: 120, line: 300 } as const\n\nconst SCREEN_ID = /^[A-Za-z0-9_-]{1,64}$/\nconst STYLES: readonly AiLayoutFrameSourceStyle[] = ['primary', 'secondary', 'quiet']\nconst GROUNDS: readonly AiLayoutFrameSourceGround[] = ['page', 'paper', 'brand', 'dark']\n\n/** Whether a destination is one a link of the frame may carry. */\nexport function aiLayoutFrameSourceToAllowed(to: unknown): to is AiLayoutFrameSourceTo {\n if (typeof to !== 'string' || !to || to.length > 2_048) return false\n if (to.startsWith('page:')) return SCREEN_ID.test(to.slice(5))\n return isHttpsUrl(to) || isRootRelativePath(to) || isContactHref(to)\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => !!value && typeof value === 'object' && !Array.isArray(value)\n\nconst words = (value: unknown, max: number): string => {\n const line = typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : ''\n return line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line\n}\n\nconst listOf = (value: unknown): unknown[] => (Array.isArray(value) ? value : [])\n\nfunction linkOf(raw: unknown): AiLayoutFrameSourceLink | null {\n if (!isRecord(raw)) return null\n const label = words(raw['label'], AI_LAYOUT_FRAME_SOURCE_LIMITS.label)\n return label && aiLayoutFrameSourceToAllowed(raw['to']) ? { label, to: raw['to'] } : null\n}\n\nconst present = <T,>(value: T | null): value is T => value !== null\n\n/**\n * A source frame as a job carries it, read defensively: every label cut to\n * its limit, every destination one a link may carry, every icon one path.\n * `null` where it holds no menu item and no button to draw.\n */\nexport function aiLayoutFrameSourceOf(raw: unknown): AiLayoutFrameSource | null {\n if (!isRecord(raw)) return null\n const limits = AI_LAYOUT_FRAME_SOURCE_LIMITS\n const nav = listOf(raw['nav'])\n .slice(0, limits.groups)\n .map((group): AiLayoutFrameSourceGroup | null => {\n if (!isRecord(group)) return null\n const label = words(group['label'], limits.label)\n if (!label) return null\n const items = listOf(group['items'])\n .slice(0, limits.entries)\n .map((entry): AiLayoutFrameSourceEntry | null => {\n const link = linkOf(entry)\n if (!link || !isRecord(entry)) return null\n const text = words(entry['text'], limits.line)\n const column = words(entry['column'], limits.label)\n return {\n ...link,\n ...(text ? { text } : {}),\n ...(aiIsIconPathData(entry['iconPath']) ? { iconPath: entry['iconPath'] } : {}),\n ...(column ? { column } : {}),\n }\n })\n .filter(present)\n const to = aiLayoutFrameSourceToAllowed(group['to']) ? group['to'] : null\n // A name that opens nothing and goes nowhere is no item.\n return items.length || to ? { label, to, items } : null\n })\n .filter(present)\n const ctas = listOf(raw['ctas'])\n .slice(0, limits.ctas)\n .map((cta): AiLayoutFrameSourceCta | null => {\n const link = linkOf(cta)\n if (!link || !isRecord(cta)) return null\n const style = STYLES.includes(cta['style'] as AiLayoutFrameSourceStyle) ? (cta['style'] as AiLayoutFrameSourceStyle) : 'primary'\n return { ...link, style }\n })\n .filter(present)\n if (!nav.length && !ctas.length) return null\n const header = GROUNDS.includes(raw['header'] as AiLayoutFrameSourceGround) ? (raw['header'] as AiLayoutFrameSourceGround) : 'paper'\n return { nav, ctas, header, footer: footerOf(raw['footer']) }\n}\n\nfunction footerOf(raw: unknown): AiLayoutFrameSourceFooter | null {\n if (!isRecord(raw)) return null\n const limits = AI_LAYOUT_FRAME_SOURCE_LIMITS\n const columns = listOf(raw['columns'])\n .slice(0, limits.columns)\n .map((column) => {\n if (!isRecord(column)) return null\n const heading = words(column['heading'], limits.label)\n const links = listOf(column['links']).slice(0, limits.links).map(linkOf).filter(present)\n return heading && links.length ? { heading, links } : null\n })\n .filter(present)\n const links = listOf(raw['links']).slice(0, limits.links).map(linkOf).filter(present)\n const text = listOf(raw['text'])\n .slice(0, limits.text)\n .map((line) => words(line, limits.line))\n .filter(Boolean)\n const social = listOf(raw['social'])\n .slice(0, limits.social)\n .map((entry) => {\n const link = linkOf(entry)\n const network = isRecord(entry) ? words(entry['network'], 40) : ''\n return link && network && isHttpsUrl(link.to) ? { ...link, network } : null\n })\n .filter(present)\n const fact = (key: string) => words(raw[key], limits.line) || null\n const footer = { columns, links, text, social, address: fact('address'), phone: fact('phone'), email: fact('email'), copyright: fact('copyright') }\n const empty = !columns.length && !links.length && !text.length && !social.length && !footer.address && !footer.phone && !footer.email && !footer.copyright\n return empty ? null : footer\n}\n\n/** The pages a source frame links by id, each once. */\nexport function aiLayoutFrameSourcePageIds(source: AiLayoutFrameSource): string[] {\n const all = [\n ...source.nav.flatMap((group) => [group.to, ...group.items.map((entry) => entry.to)]),\n ...source.ctas.map((cta) => cta.to),\n ...(source.footer ? [...source.footer.columns.flatMap((column) => column.links.map((entry) => entry.to)), ...source.footer.links.map((entry) => entry.to)] : []),\n ]\n return [...new Set(all.filter((to): to is string => typeof to === 'string' && to.startsWith('page:')).map((to) => to.slice('page:'.length)))]\n}\n\n/** A link's props for where it goes: a page by its id, anywhere else by its address. */\nexport function aiLayoutFrameSourceLinkProps(to: AiLayoutFrameSourceTo): Record<string, unknown> {\n return to.startsWith('page:') ? { screenId: to.slice('page:'.length) } : { href: to }\n}\n\n/*------------------------------------------\n * Where the menu row fits\n *-----------------------------------------*/\n\n/**\n * The widths the header row is held to, in CSS pixels: a character of a\n * label at the body size, the chevron a menu's trigger carries, the gap\n * between the row's items and between its buttons, a button's padding, and\n * the row's room at each breakpoint (the Container's `lg` width less its\n * gutters).\n */\nexport const AI_LAYOUT_HEADER_MEASURE = {\n char: 9,\n chevron: 28,\n gap: 24,\n buttonGap: 8,\n padding: { primary: 32, secondary: 32, quiet: 16 },\n room: { md: 900 - 48, lg: 1200 - 48 },\n /** What share of the room the row may fill: the estimate is a character's average, so it keeps a margin. */\n fill: 0.9,\n /** A logo's width where its picture's shape is unknown. */\n logo: 160,\n} as const\n\n/** The header row's width in CSS pixels, its brand, its menu and its buttons side by side. */\nexport function aiLayoutHeaderRowWidth(input: {\n brandWidth: number\n nav: ReadonlyArray<{ label: string; menu: boolean }>\n ctas: ReadonlyArray<{ label: string; style: AiLayoutFrameSourceStyle }>\n}): number {\n const measure = AI_LAYOUT_HEADER_MEASURE\n const navWidth = input.nav.reduce((sum, item) => sum + item.label.length * measure.char + (item.menu ? measure.chevron : 0), 0) + Math.max(0, input.nav.length - 1) * measure.gap\n const ctaWidth = input.ctas.reduce((sum, cta) => sum + cta.label.length * measure.char + measure.padding[cta.style], 0) + Math.max(0, input.ctas.length - 1) * measure.buttonGap\n const parts = [input.brandWidth, navWidth, ctaWidth].filter((width) => width > 0)\n return parts.reduce((sum, width) => sum + width, 0) + Math.max(0, parts.length - 1) * measure.gap\n}\n\n/**\n * The screen width the menu row shows from (AGL-4108): `md` where it fits a\n * 900-pixel screen with room to spare, else `lg`; and `lg` whatever it\n * measures for a row of more than five items or more than 60 characters.\n * Below it the row is the phone menu's button.\n */\nexport function aiLayoutNavBreakpoint(input: Parameters<typeof aiLayoutHeaderRowWidth>[0]): 'md' | 'lg' {\n const chars = input.nav.reduce((sum, item) => sum + item.label.length, 0)\n if (input.nav.length > 5 || chars > 60) return 'lg'\n const measure = AI_LAYOUT_HEADER_MEASURE\n return aiLayoutHeaderRowWidth(input) <= measure.room.md * measure.fill ? 'md' : 'lg'\n}\n\n/** A source's header row as `aiLayoutHeaderRowWidth` measures it. */\nexport function aiLayoutFrameSourceRow(source: Pick<AiLayoutFrameSource, 'nav' | 'ctas'>, brandWidth: number): Parameters<typeof aiLayoutHeaderRowWidth>[0] {\n return {\n brandWidth,\n nav: source.nav.map((group) => ({ label: group.label, menu: group.items.length > 0 })),\n ctas: source.ctas.map((cta) => ({ label: cta.label, style: cta.style })),\n }\n}\n\n/*------------------------------------------\n * The header\n *-----------------------------------------*/\n\nconst VARIANT: Record<AiLayoutFrameSourceStyle, string> = { primary: 'contained', secondary: 'outlined', quiet: 'text' }\n\n/** A column of a menu: its heading, where its entries have one, and its entries. */\ninterface MenuColumn {\n heading: string | null\n entries: AiLayoutFrameSourceEntry[]\n}\n\n/** The most entries one unheaded column of a mega menu holds before it is drawn as two. */\nconst COLUMN_ENTRIES = 7\n\n/** A menu's entries in the columns the source sets them in, in order; a long unheaded run in two. */\nexport function aiLayoutMenuColumns(entries: readonly AiLayoutFrameSourceEntry[]): MenuColumn[] {\n const columns: MenuColumn[] = []\n for (const entry of entries) {\n const heading = entry.column ?? null\n const last = columns[columns.length - 1]\n if (last && last.heading === heading) last.entries.push(entry)\n else columns.push({ heading, entries: [entry] })\n }\n return columns.flatMap((column) => {\n if (column.heading || column.entries.length <= COLUMN_ENTRIES) return [column]\n const half = Math.ceil(column.entries.length / 2)\n return [\n { heading: null, entries: column.entries.slice(0, half) },\n { heading: null, entries: column.entries.slice(half) },\n ]\n })\n}\n\n/** Whether a menu is drawn as a Mega Menu: its entries carry a line under them, or sit in more than one headed column. */\nexport function aiLayoutMenuIsMega(group: Pick<AiLayoutFrameSourceGroup, 'items'>): boolean {\n if (group.items.some((entry) => entry.text)) return true\n return new Set(group.items.map((entry) => entry.column).filter(Boolean)).size >= 2 || group.items.length > COLUMN_ENTRIES * 2\n}\n\nexport interface AiLayoutSourceHeader {\n /** The menu row, shown from `breakpoint` up; `null` with no item to show. */\n nav: string | null\n /** The buttons beside it; `null` with none. */\n ctas: string | null\n /** The phone menu's contents, in order. */\n drawer: string[]\n breakpoint: 'md' | 'lg'\n}\n\n/**\n * The source's header drawn (AGL-4108): its menu row, its buttons and its\n * phone menu. `close` is the interaction a link of the phone menu closes it\n * with.\n */\nexport function aiLayoutSourceHeader(\n tree: AiLayoutTreeBuilder,\n source: AiLayoutFrameSource,\n input: { onBrand: boolean; close: unknown[]; brandWidth: number },\n): AiLayoutSourceHeader {\n const breakpoint = aiLayoutNavBreakpoint(aiLayoutFrameSourceRow(source, input.brandWidth))\n // A link's look is its parent's, which every link under it inherits: a\n // style repeated on each is one the doctrine asks be carried once.\n const link = (entry: AiLayoutFrameSourceLink, role: string, interactions?: unknown[], sx: Record<string, unknown> = {}) => {\n const id = tree.add(\n 'muiScreenLink',\n { children: entry.label, ...aiLayoutFrameSourceLinkProps(entry.to), renderAs: 'link', color: 'inherit' },\n { textDecoration: 'none', ...sx },\n null,\n role,\n )\n if (interactions) tree.nodes[id].interactions = interactions\n return id\n }\n const items = source.nav.map((group) => (group.items.length ? menu(tree, group, link) : group.to ? link({ label: group.label, to: group.to }, 'navLink') : null))\n const nav = items.some(Boolean)\n ? tree.add(\n 'muiStack',\n { component: 'nav', ariaLabel: 'Main', direction: 'row', spacing: '3', alignItems: 'center' },\n // Every label on one line, and the row never narrower than its labels.\n { display: { xs: 'none', [breakpoint]: 'flex' }, whiteSpace: 'nowrap', flexShrink: 0 },\n items,\n 'nav',\n )\n : null\n const button = (cta: AiLayoutFrameSourceCta, role: string, extra: Record<string, unknown> = {}) =>\n tree.add(\n 'muiButton',\n {\n children: cta.label,\n variant: VARIANT[cta.style],\n color: input.onBrand ? 'secondary' : 'primary',\n ...aiLayoutFrameSourceLinkProps(cta.to),\n ...extra,\n },\n null,\n null,\n role,\n )\n // On the smallest phones the buttons move into the menu. Their words on one line, as the row's.\n const ctas = source.ctas.length\n ? tree.add(\n 'muiStack',\n { direction: 'row', spacing: '1', alignItems: 'center' },\n { display: { xs: 'none', sm: 'flex' }, flexShrink: 0, whiteSpace: 'nowrap', ml: 'auto' },\n source.ctas.map((cta) => button(cta, 'cta')),\n 'ctas',\n )\n : null\n // The phone menu: each menu as a heading over its entries, its columns'\n // headings among them, the links, then the buttons.\n const drawer: string[] = []\n let links: string[] = []\n const flushLinks = () => {\n if (!links.length) return\n drawer.push(tree.add('muiStack', { spacing: '1.5' }, { typography: 'subtitle1' }, links, 'menuLinks'))\n links = []\n }\n for (const group of source.nav) {\n if (!group.items.length) {\n if (group.to) links.push(link({ label: group.label, to: group.to }, 'menuLink', input.close))\n continue\n }\n flushLinks()\n // The menu's name heads its entries; it links where the source's name opens a page and no entry does.\n const own = aiLayoutMenuOwnPage(group)\n const heading = own\n ? link({ label: group.label, to: own }, 'menuHeading', input.close, { typography: 'overline' })\n : tree.add('muiTypography', { children: group.label, variant: 'overline', component: 'p' }, { color: 'text.secondary' }, null, 'menuHeading')\n const entries: string[] = []\n let column: string | null = null\n for (const entry of group.items) {\n const under = entry.column ?? null\n if (under && under !== column) entries.push(tree.add('muiTypography', { children: under, variant: 'caption', component: 'p' }, { color: 'text.secondary' }, null, 'menuColumn'))\n column = under\n entries.push(link(entry, 'menuEntry', input.close))\n }\n drawer.push(tree.add('muiStack', { spacing: '1' }, { typography: 'body1' }, [heading, ...entries], 'menuGroup'))\n }\n flushLinks()\n if (source.ctas.length) {\n drawer.push(\n tree.add(\n 'muiStack',\n { spacing: '1' },\n { mt: 1 },\n source.ctas.map((cta) => button(cta, 'menuCta', { fullWidth: true })),\n 'menuCtas',\n ),\n )\n }\n return { nav, ctas, drawer, breakpoint }\n}\n\n/**\n * The page a menu's own name opens, where none of its entries does: a page\n * of the site, never an address elsewhere (a Squarespace folder's address\n * is no page). `null` otherwise.\n */\nexport function aiLayoutMenuOwnPage(group: Pick<AiLayoutFrameSourceGroup, 'to' | 'items'>): AiLayoutFrameSourceTo | null {\n const to = group.to\n if (!to || !(to.startsWith('page:') || isRootRelativePath(to))) return null\n return group.items.some((entry) => entry.to === to) ? null : to\n}\n\ntype LinkDraw = (entry: AiLayoutFrameSourceLink, role: string, interactions?: unknown[], sx?: Record<string, unknown>) => string\n\n/**\n * A top-level item with entries: the Mega Menu, its entries in the source's\n * columns, each with its icon and the line under it; or the Dropdown Menu.\n * Where the item's own name goes somewhere none of its entries does, the menu\n * opens with that link, so the page the source's name opens stays reachable.\n */\nfunction menu(tree: AiLayoutTreeBuilder, group: AiLayoutFrameSourceGroup, link: LinkDraw): string {\n const own = aiLayoutMenuOwnPage(group)\n const overview = own ? link({ label: group.label, to: own }, 'menuOverview', undefined, { fontWeight: 700 }) : null\n if (!aiLayoutMenuIsMega(group)) {\n // Its entries' words wrap as the source's do; only the row's labels are held to one line.\n return tree.add(\n 'muiNavMenu',\n { label: group.label },\n { flexShrink: 0 },\n [tree.add('muiStack', { spacing: '1' }, { whiteSpace: 'normal' }, [overview, ...group.items.map((entry) => link(entry, 'menuItem'))], 'menuItems')],\n 'navMenu',\n )\n }\n const columns = aiLayoutMenuColumns(group.items)\n // Its columns side by side from a tablet up, as many to a row as the source sets, three at most.\n const span = 12 / Math.min(3, Math.max(1, columns.length))\n const cells = columns.map((column) =>\n tree.add(\n 'muiGrid',\n { size: `xs:12 sm:${span}` },\n null,\n [\n tree.add(\n 'muiStack',\n { spacing: '1' },\n null,\n [\n column.heading\n ? tree.add('muiTypography', { children: column.heading, variant: 'overline', component: 'p' }, { color: 'text.secondary' }, null, 'menuColumnHeading')\n : null,\n ...column.entries.map((entry) => (entry.text || entry.iconPath ? described(tree, entry) : link(entry, 'menuItem'))),\n ],\n 'menuColumn',\n ),\n ],\n 'menuCell',\n ),\n )\n const grid = tree.add('muiGrid', { container: true, spacing: '2' }, null, cells, 'menuColumns')\n // Words in the panel wrap as the source's do; only the row's labels are held to one line.\n const panel = tree.add('muiStack', { spacing: '2' }, { whiteSpace: 'normal' }, [overview, grid], 'menuPanel')\n return tree.add('muiMegaMenu', { label: group.label, panelWidth: 'wide' }, { flexShrink: 0 }, [panel], 'megaMenu')\n}\n\n/** A mega menu's entry: the whole of it one link, its icon beside its name and the line under it. */\nfunction described(tree: AiLayoutTreeBuilder, entry: AiLayoutFrameSourceEntry): string {\n // In the brand's color, as the source draws its menu's icons.\n const icon = entry.iconPath ? tree.add('icon', { iconPath: entry.iconPath, size: '24', color: 'primary.main' }, null, null, 'menuIcon') : null\n const name = tree.add('muiTypography', { children: entry.label, variant: 'subtitle2', component: 'p' }, { fontWeight: 600 }, null, 'menuEntryName')\n const line = entry.text ? tree.add('muiTypography', { children: entry.text, variant: 'body2', component: 'p' }, { color: 'text.secondary' }, null, 'menuEntryText') : null\n const words = tree.add('muiStack', { spacing: '0.25' }, null, [name, line], 'menuEntryWords')\n const row = tree.add('muiStack', { direction: 'row', spacing: '1.5', alignItems: 'flex-start' }, null, [icon, words], 'menuEntryRow')\n return tree.add('muiLinkBox', { ...aiLayoutFrameSourceLinkProps(entry.to), ariaLabel: entry.label }, { color: 'inherit' }, [row], 'menuEntry')\n}\n\n/*------------------------------------------\n * The footer\n *-----------------------------------------*/\n\n/** The networks the Social Links element draws, by the reader's name for each. */\nconst SOCIAL_FIELDS: Readonly<Record<string, string>> = {\n x: 'twitter',\n twitter: 'twitter',\n instagram: 'instagram',\n facebook: 'facebook',\n linkedin: 'linkedin',\n youtube: 'youtube',\n github: 'github',\n}\n\n/** A phone number as a link that calls it: its digits, a `+` only first; `null` where it is no number. */\nexport function aiLayoutTelHref(phone: string): string | null {\n const digits = phone.replace(/[^\\d+]/g, '').replace(/(?!^)\\+/g, '')\n const href = `tel:${digits}`\n return isContactHref(href) ? href : null\n}\n\n/** The source's footer drawn (AGL-4108): its words and profiles beside its columns, its © line and other links under a rule. */\nexport function aiLayoutSourceFooter(\n tree: AiLayoutTreeBuilder,\n footer: AiLayoutFrameSourceFooter,\n input: { name: string },\n): { top: string | null; bottom: string; sx: Record<string, unknown> } {\n // The footer's words are quiet and small, set once on the footer for every line and link under it.\n const quiet = { color: 'text.secondary' }\n const footerLink = (entry: AiLayoutFrameSourceLink, role: string) =>\n tree.add(\n 'muiScreenLink',\n { children: entry.label, ...aiLayoutFrameSourceLinkProps(entry.to), renderAs: 'link', color: 'inherit' },\n { textDecoration: 'none' },\n null,\n role,\n )\n // Its words, its profiles and how to reach it, beside the columns.\n const lines = footer.text.map((line) => tree.add('muiTypography', { children: line, variant: 'body2', component: 'p' }, null, null, 'footerText'))\n const drawn: Record<string, string> = {}\n const others: AiLayoutFrameSourceLink[] = []\n for (const profile of footer.social) {\n const field = SOCIAL_FIELDS[profile.network.toLowerCase()]\n if (field && !drawn[field]) drawn[field] = profile.to\n else if (!field) others.push(profile)\n }\n const icons = Object.keys(drawn).length ? tree.add('socialLinks', drawn, { ml: -1 }, null, 'social') : null\n // A profile the Social Links element has no icon for is linked by its name, beside the icons.\n const named = others.map((profile) => footerLink(profile, 'socialLink'))\n const profiles =\n icons || named.length\n ? tree.add('muiStack', { direction: 'row', spacing: '1.5', alignItems: 'center', useFlexGap: true, flexWrap: 'wrap' }, null, [icons, ...named], 'profiles')\n : null\n const tel = footer.phone ? aiLayoutTelHref(footer.phone) : null\n const mail = footer.email ? `mailto:${footer.email}` : null\n const reach = [\n footer.address ? tree.add('muiTypography', { children: footer.address, variant: 'body2', component: 'p' }, null, null, 'address') : null,\n footer.phone && tel ? footerLink({ label: footer.phone, to: tel }, 'phone') : null,\n footer.email && mail && isContactHref(mail) ? footerLink({ label: footer.email, to: mail }, 'email') : null,\n ].filter((id): id is string => !!id)\n const about = [...lines, profiles, ...(reach.length ? [tree.add('muiStack', { spacing: '0.5' }, null, reach, 'reach')] : [])].filter((id): id is string => !!id)\n // Its columns, each under its heading.\n const count = footer.columns.length\n const span = Math.max(2, Math.min(6, Math.floor(12 / Math.max(1, count))))\n const columns = footer.columns.map((column) =>\n tree.add(\n 'muiGrid',\n { size: `xs:12 sm:4 md:${span}` },\n null,\n [\n tree.add(\n 'muiStack',\n { spacing: '1' },\n null,\n [\n // A heading in the text's own color over its quiet links.\n tree.add('muiTypography', { children: column.heading, variant: 'subtitle2', component: 'p' }, { color: 'text.primary' }, null, 'footerHeading'),\n ...column.links.map((entry) => footerLink(entry, 'footerLink')),\n ],\n 'footerColumn',\n ),\n ],\n 'footerCell',\n ),\n )\n const grid = columns.length ? tree.add('muiGrid', { container: true, spacing: '3' }, null, columns, 'footerColumns') : null\n const aboutStack = about.length ? tree.add('muiStack', { spacing: '2' }, null, about, 'footerAbout') : null\n const top =\n aboutStack && grid\n ? tree.add(\n 'muiGrid',\n { container: true, spacing: '4' },\n { alignItems: 'flex-start' },\n [tree.add('muiGrid', { size: 'xs:12 md:3' }, null, [aboutStack], 'footerAboutCell'), tree.add('muiGrid', { size: 'xs:12 md:9' }, null, [grid], 'footerColumnsCell')],\n 'footerTop',\n )\n : (aboutStack ?? grid)\n // The © line word for word, and the links outside the columns beside it.\n const copyright = tree.add('muiTypography', { children: footer.copyright ?? `© ${input.name}`, variant: 'body2', component: 'p' }, null, null, 'copyright')\n const legal = footer.links.length\n ? tree.add('muiStack', { direction: 'row', spacing: '2', useFlexGap: true, flexWrap: 'wrap' }, null, footer.links.map((entry) => footerLink(entry, 'footerLegal')), 'footerLinks')\n : null\n const bottom = tree.add(\n 'muiStack',\n { spacing: '2', useFlexGap: true },\n { pt: 3, borderTop: 1, borderColor: 'divider', flexDirection: { xs: 'column', md: 'row' }, justifyContent: 'space-between', alignItems: { xs: 'flex-start', md: 'center' } },\n [copyright, legal],\n 'footerBottom',\n )\n return { top, bottom, sx: { ...quiet, typography: 'body2' } }\n}\n"],"names":["aiIsIconPathData","isContactHref","isHttpsUrl","isRootRelativePath","AI_LAYOUT_FRAME_SOURCE_LIMITS","groups","entries","ctas","columns","links","text","social","label","line","SCREEN_ID","STYLES","GROUNDS","aiLayoutFrameSourceToAllowed","to","length","startsWith","test","slice","isRecord","value","Array","isArray","words","max","replace","trim","trimEnd","listOf","linkOf","raw","present","aiLayoutFrameSourceOf","limits","nav","map","group","items","entry","link","column","iconPath","filter","cta","style","includes","header","footer","footerOf","heading","Boolean","network","fact","key","address","phone","email","copyright","empty","aiLayoutFrameSourcePageIds","source","all","flatMap","Set","aiLayoutFrameSourceLinkProps","screenId","href","AI_LAYOUT_HEADER_MEASURE","char","chevron","gap","buttonGap","padding","primary","secondary","quiet","room","md","lg","fill","logo","aiLayoutHeaderRowWidth","input","measure","navWidth","reduce","sum","item","menu","Math","ctaWidth","parts","brandWidth","width","aiLayoutNavBreakpoint","chars","aiLayoutFrameSourceRow","VARIANT","COLUMN_ENTRIES","aiLayoutMenuColumns","last","push","half","ceil","aiLayoutMenuIsMega","some","size","aiLayoutSourceHeader","tree","breakpoint","role","interactions","sx","id","add","children","renderAs","color","textDecoration","nodes","component","ariaLabel","direction","spacing","alignItems","display","xs","whiteSpace","flexShrink","button","extra","variant","onBrand","sm","ml","drawer","flushLinks","typography","close","own","aiLayoutMenuOwnPage","under","mt","fullWidth","overview","undefined","fontWeight","span","min","cells","described","grid","container","panel","panelWidth","icon","name","row","SOCIAL_FIELDS","x","twitter","instagram","facebook","linkedin","youtube","github","aiLayoutTelHref","digits","aiLayoutSourceFooter","footerLink","lines","drawn","others","profile","field","toLowerCase","icons","Object","keys","named","profiles","useFlexGap","flexWrap","tel","mail","reach","about","count","floor","aboutStack","top","legal","bottom","pt","borderTop","borderColor","flexDirection","justifyContent"],"mappings":"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"}
@@ -17,6 +17,7 @@
17
17
  import type { AiStoreFrameLinks } from '../model/ai-site-store-pages';
18
18
  import { type AiLayoutBlock, type AiLayoutSection, type AiLayoutSettlement } from './ai-layout-language';
19
19
  import { type AiLayoutPage, type AiLayoutTargets } from './ai-layout-links';
20
+ import { type AiLayoutFrameSource } from './ai-layout-frame-source';
20
21
  import { type AiLayoutRawTree } from './ai-layout-tree';
21
22
  /**
22
23
  * A site's frame — the header and the footer every page renders between —
@@ -31,6 +32,15 @@ import { type AiLayoutRawTree } from './ai-layout-tree';
31
32
  * its Menu Button on a phone; the Layout Slot, the page's one main landmark,
32
33
  * held tall enough that the footer sits at the bottom of a short page; and
33
34
  * the site's pages and name in the footer, where the design gave neither.
35
+ *
36
+ * Every label of the navigation is held to one line, the logo never narrower
37
+ * than itself, and the row shows from the screen width it measures to fit
38
+ * (`aiLayoutNavBreakpoint`), the Menu Button below it (AGL-4108: the 10/29
39
+ * import's seven long titles wrapped from 900 px up and the logo lay over
40
+ * "Home" at 1280). A site brought in from elsewhere whose menu the reader
41
+ * found is drawn as its source builds it instead (`plan.source`,
42
+ * `ai-layout-frame-source.ts`): its menus, its buttons, its phone menu and its
43
+ * footer, in place of the site's pages and the design's button and footer.
34
44
  */
35
45
  export interface AiLayoutFramePlan {
36
46
  /** The site's name, which the header and the footer carry as its brand. */
@@ -74,6 +84,14 @@ export interface AiLayoutFramePlan {
74
84
  * header shows it. Absent, the name alone.
75
85
  */
76
86
  brand?: AiLayoutFrameBrand | null;
87
+ /**
88
+ * A site brought in from elsewhere whose header the reader found
89
+ * (AGL-4108): its menu with its menus, its buttons with their own
90
+ * addresses, its phone menu and its footer, drawn as the source has them
91
+ * (`ai-layout-frame-source.ts`) in place of the site's pages and the
92
+ * design's button and footer.
93
+ */
94
+ source?: AiLayoutFrameSource | null;
77
95
  }
78
96
  /** A header's brand as the source shows it (AGL-4084). */
79
97
  export interface AiLayoutFrameBrand {
@@ -83,6 +101,10 @@ export interface AiLayoutFrameBrand {
83
101
  } | null;
84
102
  /** Whether the header prints the name as words, beside the logo or alone. */
85
103
  name: boolean;
104
+ /** The logo's words for a screen reader, as the source names it (AGL-4108); the site's name where it gave none. */
105
+ alt?: string;
106
+ /** The logo's width over its height, which the header row is measured with (AGL-4108). */
107
+ aspect?: number;
86
108
  }
87
109
  /** The height a header's logo is drawn at: a Besigner field the owner may change. */
88
110
  export declare const AI_LAYOUT_LOGO_HEIGHT = "40px";
@@ -23,6 +23,7 @@ import { AI_LAYOUT_CART_ELEMENT } from "./ai-layout-listings.js";
23
23
  import { AI_LAYOUT_MAX_ITEMS } from "./ai-layout-language.js";
24
24
  import { AI_LAYOUT_LABELS_EN, aiLayoutLabel } from "./ai-layout-labels.js";
25
25
  import { aiLayoutRenamedLabel, aiLayoutResolveLink } from "./ai-layout-links.js";
26
+ import { AI_LAYOUT_HEADER_MEASURE, aiLayoutNavBreakpoint, aiLayoutSourceFooter, aiLayoutSourceHeader } from "./ai-layout-frame-source.js";
26
27
  import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
27
28
  /** The height a header's logo is drawn at: a Besigner field the owner may change. */ export const AI_LAYOUT_LOGO_HEIGHT = '40px';
28
29
  /** What the header's link to a store's account page says (AGL-3676), in English. */ export const AI_LAYOUT_ACCOUNT_LINK = AI_LAYOUT_LABELS_EN.account;
@@ -92,8 +93,8 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
92
93
  };
93
94
  }
94
95
  /** Compiles a site's header and footer, designed in the layout language, into its layout. */ export function aiCompileLayoutFrame(frame, plan, targets) {
95
- var _ref, _frame_header, _header_band, _ref1;
96
- var _plan_storeLinks, _plan_brand_logo, _plan_brand, _plan_brand1, _plan_storeLinks1;
96
+ var _ref, _frame_header, _header_band, _plan_source, _ref1, _ref2, _ref3;
97
+ var _plan_storeLinks, _plan_brand_logo, _plan_brand, _plan_brand1, _plan_brand2, _plan_brand3, _plan_brand4, _plan_storeLinks1;
97
98
  const tree = new AiLayoutTreeBuilder('lf');
98
99
  // A store's own pages are destinations the footer's list links by path (AGL-3676).
99
100
  const storePages = ((_ref = (_plan_storeLinks = plan.storeLinks) == null ? void 0 : _plan_storeLinks.footer) != null ? _ref : []).map((link)=>({
@@ -168,6 +169,8 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
168
169
  const centeredNav = header.align === 'center' && pages.length > 0;
169
170
  // The brand takes the room the navigation does not, and gives way before
170
171
  // it does: a long name ends in an ellipsis rather than pushing into the links.
172
+ // A logo never gives way: drawn narrower than itself it lay over the first
173
+ // link (the 10/29 header at 1280, AGL-4108).
171
174
  const brandSx = _extends({
172
175
  typography: 'h6',
173
176
  fontWeight: 800,
@@ -180,12 +183,16 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
180
183
  flexGrow: 1
181
184
  });
182
185
  const logo = ((_plan_brand = plan.brand) == null ? void 0 : (_plan_brand_logo = _plan_brand.logo) == null ? void 0 : _plan_brand_logo.src) ? plan.brand.logo.src : null;
186
+ const source = (_plan_source = plan.source) != null ? _plan_source : null;
187
+ const alt = ((_ref1 = (_plan_brand1 = plan.brand) == null ? void 0 : _plan_brand1.alt) != null ? _ref1 : '').replace(/\s+/g, ' ').trim().slice(0, 120) || name.slice(0, 40);
183
188
  const brand = logo ? brandMark(tree, {
184
189
  src: logo,
185
190
  name: name.slice(0, 40),
186
- withName: ((_plan_brand1 = plan.brand) == null ? void 0 : _plan_brand1.name) === true,
191
+ alt,
192
+ withName: ((_plan_brand2 = plan.brand) == null ? void 0 : _plan_brand2.name) === true,
187
193
  homeId: plan.homeId,
188
- centered: centeredNav
194
+ centered: centeredNav,
195
+ grow: !source
189
196
  }) : plan.homeId ? tree.add('muiScreenLink', {
190
197
  children: name.slice(0, 40),
191
198
  screenId: plan.homeId,
@@ -196,7 +203,30 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
196
203
  variant: 'h6',
197
204
  component: 'p'
198
205
  }, brandSx, null, 'brand');
199
- const nav = pages.length ? tree.add('muiStack', {
206
+ // How wide the brand is drawn, which the row is measured with (AGL-4108).
207
+ const aspect = ((_plan_brand3 = plan.brand) == null ? void 0 : _plan_brand3.aspect) && Number.isFinite(plan.brand.aspect) && plan.brand.aspect > 0 ? Math.min(plan.brand.aspect, 8) : null;
208
+ const logoHeight = Number.parseInt(AI_LAYOUT_LOGO_HEIGHT, 10);
209
+ const brandWidth = logo ? (aspect ? Math.round(aspect * logoHeight) : AI_LAYOUT_HEADER_MEASURE.logo) + (((_plan_brand4 = plan.brand) == null ? void 0 : _plan_brand4.name) ? name.slice(0, 40).length * 11 + 12 : 0) : Math.min(name.length, 40) * 11;
210
+ // The source's own header (AGL-4108), drawn as it builds it.
211
+ const close = [
212
+ AI_LAYOUT_CLOSE_DRAWER
213
+ ];
214
+ const drawn = source ? aiLayoutSourceHeader(tree, source, {
215
+ onBrand: band === 'brand' || band === 'dark',
216
+ close,
217
+ brandWidth
218
+ }) : null;
219
+ // Every label on one line, and the row only on a screen it fits (AGL-4108).
220
+ const pagesBreakpoint = aiLayoutNavBreakpoint({
221
+ brandWidth,
222
+ nav: pages.map((entry)=>({
223
+ label: entry.label,
224
+ menu: false
225
+ })),
226
+ ctas: []
227
+ });
228
+ const breakpoint = (_ref2 = drawn == null ? void 0 : drawn.breakpoint) != null ? _ref2 : pagesBreakpoint;
229
+ const nav = drawn ? drawn.nav : pages.length ? tree.add('muiStack', {
200
230
  component: 'nav',
201
231
  ariaLabel: 'Main',
202
232
  direction: 'row',
@@ -205,11 +235,13 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
205
235
  }, {
206
236
  display: {
207
237
  xs: 'none',
208
- md: 'flex'
209
- }
238
+ [breakpoint]: 'flex'
239
+ },
240
+ whiteSpace: 'nowrap'
210
241
  }, pages.map((entry)=>navLink(entry, 'navLink')), 'nav') : null;
211
242
  // The design's call to action: its first button, where it goes somewhere.
212
- const ctaBlock = header.blocks.find((block)=>block.kind === 'button');
243
+ // A source's header carries its own buttons instead (AGL-4108).
244
+ const ctaBlock = source ? undefined : header.blocks.find((block)=>block.kind === 'button');
213
245
  // A store's announcement: the first short line the design gave its header (AGL-3676).
214
246
  const store = !!plan.shopId;
215
247
  const noteBlock = store ? header.blocks.find((block)=>block.kind === 'note' || block.kind === 'text' || block.kind === 'lede') : undefined;
@@ -250,7 +282,7 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
250
282
  flexShrink: 0
251
283
  }, null, 'cta') : null;
252
284
  // A store's account, beside its cart and in the phone's menu (AGL-3676).
253
- const accountPath = (_ref1 = (_plan_storeLinks1 = plan.storeLinks) == null ? void 0 : _plan_storeLinks1.account) != null ? _ref1 : null;
285
+ const accountPath = (_ref3 = (_plan_storeLinks1 = plan.storeLinks) == null ? void 0 : _plan_storeLinks1.account) != null ? _ref3 : null;
254
286
  const accountLink = (role, interactions, sx)=>{
255
287
  const id = tree.add('muiScreenLink', {
256
288
  children: aiLayoutLabel('account', plan.language),
@@ -265,11 +297,23 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
265
297
  return id;
266
298
  };
267
299
  // A phone's menu: the platform's Drawer, opened by its Menu Button; a link
268
- // followed from it closes it.
269
- const close = [
270
- AI_LAYOUT_CLOSE_DRAWER
271
- ];
272
- const drawer = pages.length ? tree.add('muiDrawer', {
300
+ // followed from it closes it. A source's holds its menus, links and buttons (AGL-4108).
301
+ const drawer = (drawn == null ? void 0 : drawn.drawer.length) ? tree.add('muiDrawer', {
302
+ anchor: 'right'
303
+ }, null, [
304
+ tree.add('muiStack', {
305
+ component: 'nav',
306
+ ariaLabel: 'Menu'
307
+ }, {
308
+ display: 'flex',
309
+ flexDirection: 'column',
310
+ gap: 3,
311
+ p: 3
312
+ }, [
313
+ ...drawn.drawer,
314
+ accountPath ? accountLink('menuAccount', close) : null
315
+ ], 'menu')
316
+ ], 'drawer') : !source && pages.length ? tree.add('muiDrawer', {
273
317
  anchor: 'right'
274
318
  }, null, [
275
319
  tree.add('muiStack', {
@@ -293,13 +337,16 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
293
337
  ], 'drawer') : null;
294
338
  const toggle = drawer ? tree.add('muiDrawerToggle', {
295
339
  ariaLabel: 'Open the menu'
296
- }, {
340
+ }, // Pushed to the end of the row where no button is there to push it.
341
+ _extends({
297
342
  display: {
298
343
  xs: 'inline-flex',
299
- md: 'none'
344
+ [breakpoint]: 'none'
300
345
  },
301
346
  flexShrink: 0
302
- }, null, 'menuButton') : null;
347
+ }, drawn && !drawn.ctas ? {
348
+ ml: 'auto'
349
+ } : {}), null, 'menuButton') : null;
303
350
  const middle = nav && centeredNav ? tree.add('muiBox', null, {
304
351
  flexGrow: 1,
305
352
  display: 'flex',
@@ -317,7 +364,7 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
317
364
  const account = accountPath ? accountLink('account', undefined, {
318
365
  display: {
319
366
  xs: 'none',
320
- md: 'inline-flex'
367
+ [breakpoint]: 'inline-flex'
321
368
  },
322
369
  flexShrink: 0
323
370
  }) : null;
@@ -331,7 +378,7 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
331
378
  }, [
332
379
  brand,
333
380
  middle,
334
- cta,
381
+ drawn ? drawn.ctas : cta,
335
382
  account,
336
383
  cart,
337
384
  toggle,
@@ -347,13 +394,22 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
347
394
  }, [
348
395
  row
349
396
  ], 'toolbar');
350
- const bar = tree.add('muiAppBar', _extends({}, look.props, {
397
+ // A source's header bar on the ground it sits on (AGL-4108): the page's own, where it is the page's.
398
+ const barLook = (source == null ? void 0 : source.header) === 'page' ? {
399
+ props: {
400
+ color: 'inherit'
401
+ },
402
+ sx: {
403
+ bgcolor: 'background.default'
404
+ }
405
+ } : look;
406
+ const bar = tree.add('muiAppBar', _extends({}, barLook.props, {
351
407
  position: 'sticky',
352
408
  // Over a page that opens with a photo cover, the bar sits on the photo (AGL-3660).
353
409
  overHero: true,
354
410
  component: 'header',
355
411
  ariaLabel: 'Site header'
356
- }), look.sx, [
412
+ }), barLook.sx, [
357
413
  toolbar
358
414
  ], 'header');
359
415
  // A selling store's announcement bar, above the header, linking its shop (AGL-3676).
@@ -402,7 +458,7 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
402
458
  }, {
403
459
  flexGrow: 1
404
460
  }, null, 'slot');
405
- const footer = compileFooter(page, frame.footer, plan, name);
461
+ const footer = (source == null ? void 0 : source.footer) ? sourceFooter(page, source, name) : compileFooter(page, frame.footer, plan, name);
406
462
  // No heading with nothing under it, no column of only a heading, columns
407
463
  // top-aligned (AGL-3735): a list under a heading can compile to nothing.
408
464
  if (aiLayoutRepairFrameHollows(tree.nodes)) {
@@ -692,6 +748,41 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
692
748
  container
693
749
  ], 'footer');
694
750
  }
751
+ /**
752
+ * A source's footer (AGL-4108): its columns, words, profiles and © line, as
753
+ * the source has them, on the quiet band a footer sits on.
754
+ */ function sourceFooter(page, source, name) {
755
+ const tree = page.tree;
756
+ const drawn = aiLayoutSourceFooter(tree, source.footer, {
757
+ name
758
+ });
759
+ const stack = tree.add('muiStack', {
760
+ spacing: '6'
761
+ }, drawn.sx, [
762
+ drawn.top,
763
+ drawn.bottom
764
+ ], 'footerStack');
765
+ const container = tree.add('muiContainer', {
766
+ maxWidth: 'lg'
767
+ }, {
768
+ py: {
769
+ xs: 6,
770
+ md: 8
771
+ }
772
+ }, [
773
+ stack
774
+ ], 'footerInner');
775
+ return tree.add('section', {
776
+ element: 'footer',
777
+ ariaLabel: 'Site footer'
778
+ }, {
779
+ bgcolor: 'background.paper',
780
+ borderTop: 1,
781
+ borderColor: 'divider'
782
+ }, [
783
+ container
784
+ ], 'footer');
785
+ }
695
786
  /**
696
787
  * The header's brand drawn with the site's logo (AGL-4084), as the source's
697
788
  * header draws it: the logo alone, named by its alt text, or the logo with
@@ -700,7 +791,7 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
700
791
  const image = (alone)=>tree.add('image', _extends({
701
792
  src: input.src
702
793
  }, alone ? {
703
- alt: input.name
794
+ alt: input.alt
704
795
  } : {
705
796
  decorative: true
706
797
  }, {
@@ -711,15 +802,16 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
711
802
  }, alone && input.homeId ? {
712
803
  screenId: input.homeId
713
804
  } : {}), null, null, 'logo');
714
- const grow = input.centered ? null : {
805
+ // Never narrower than the logo (AGL-4108); it grows into the room the
806
+ // navigation leaves only where the navigation does not take it itself.
807
+ const grow = input.centered || !input.grow ? null : {
715
808
  flexGrow: 1
716
809
  };
717
810
  if (!input.withName) {
718
- if (!grow) return image(true);
719
- return tree.add('muiBox', null, _extends({}, grow, {
811
+ return tree.add('muiBox', null, _extends({}, grow != null ? grow : {}, {
720
812
  display: 'flex',
721
813
  alignItems: 'center',
722
- minWidth: 0
814
+ flexShrink: 0
723
815
  }), [
724
816
  image(true)
725
817
  ], 'brand');
@@ -746,11 +838,11 @@ import { AiLayoutTreeBuilder } from "./ai-layout-tree.js";
746
838
  }, _extends({}, grow != null ? grow : {}, {
747
839
  textDecoration: 'none',
748
840
  color: 'inherit',
749
- minWidth: 0
841
+ flexShrink: 0
750
842
  }), [
751
843
  row
752
844
  ], 'brand') : tree.add('muiBox', null, _extends({}, grow != null ? grow : {}, {
753
- minWidth: 0
845
+ flexShrink: 0
754
846
  }), [
755
847
  row
756
848
  ], 'brand');