@gradial/aci 0.1.31 → 0.1.34

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 (159) hide show
  1. package/README.md +4 -4
  2. package/bin/aci.js +89 -77
  3. package/dist/astro/assets.d.ts +46 -0
  4. package/dist/astro/assets.js +51 -0
  5. package/dist/astro/index.d.ts +2 -0
  6. package/dist/astro/index.js +8 -0
  7. package/dist/astro/page.d.ts +88 -0
  8. package/dist/astro/page.js +117 -0
  9. package/dist/dev/content-watch.d.ts +1 -0
  10. package/dist/dev/content-watch.js +1 -1
  11. package/dist/next/config.d.ts +6 -0
  12. package/dist/next/config.js +20 -13
  13. package/dist/next/content-watch.d.ts +1 -0
  14. package/dist/next/content-watch.js +2 -2
  15. package/dist/next/index.d.ts +1 -0
  16. package/dist/next/index.js +1 -0
  17. package/dist/next/middleware.d.ts +3 -2
  18. package/dist/next/middleware.js +40 -7
  19. package/dist/next/page.d.ts +13 -5
  20. package/dist/next/page.js +42 -17
  21. package/dist/next/server.d.ts +1 -1
  22. package/dist/next/server.js +7 -8
  23. package/dist/testing/conformance/checks.d.ts +12 -0
  24. package/dist/testing/conformance/checks.js +483 -0
  25. package/dist/testing/conformance/index.d.ts +3 -0
  26. package/dist/testing/conformance/index.js +2 -0
  27. package/dist/testing/conformance/preset.d.ts +14 -0
  28. package/dist/testing/conformance/preset.js +98 -0
  29. package/dist/testing/conformance/types.d.ts +45 -0
  30. package/dist/testing/conformance/types.js +7 -0
  31. package/package.json +24 -9
  32. package/src/cli/materialize-template.mjs +133 -0
  33. package/src/cli/validate-content.mjs +0 -0
  34. package/src/cli/verify-next-cdn-routes.mjs +10 -19
  35. package/templates/astro/starter-content/src/cms/contracts/components/button.contract.ts +19 -0
  36. package/templates/astro/starter-content/src/cms/contracts/components/container.contract.ts +19 -0
  37. package/templates/astro/starter-content/src/cms/contracts/components/featureCard.contract.ts +15 -0
  38. package/templates/astro/starter-content/src/cms/contracts/components/featureGrid.contract.ts +16 -0
  39. package/templates/astro/starter-content/src/cms/contracts/components/homeHero.contract.ts +36 -0
  40. package/templates/astro/starter-content/src/cms/contracts/components/index.ts +21 -0
  41. package/templates/astro/starter-content/src/cms/contracts/components/statsBar.contract.ts +19 -0
  42. package/templates/astro/starter-content/src/cms/registry.ts +28 -0
  43. package/templates/astro/template/{.aci.yaml → .aci.yaml.tmpl} +1 -1
  44. package/templates/astro/template/README.md.tmpl +53 -0
  45. package/templates/astro/template/gitignore +12 -0
  46. package/templates/astro/template/package.json.tmpl +5 -3
  47. package/templates/astro/template/src/cms/contracts/components/index.ts +3 -0
  48. package/templates/astro/template/src/cms/registry.ts +3 -26
  49. package/templates/astro/template/src/pages/[...slug].astro +13 -35
  50. package/templates/astro/template/tests/conformance.test.ts.tmpl +12 -0
  51. package/templates/common/.agents/AGENTS.md +3 -5
  52. package/templates/common/.agents/skills/aci/SKILL.md +72 -23
  53. package/templates/common/.agents/skills/authoring/SKILL.md +53 -14
  54. package/templates/common/.agents/skills/authoring/references/block-registry.md +109 -15
  55. package/templates/common/.agents/skills/authoring/references/contracts.md +23 -7
  56. package/templates/common/.agents/skills/authoring/references/repo-structure.md +35 -19
  57. package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +75 -17
  58. package/templates/common/.agents/skills/migration/SKILL.md +7 -1
  59. package/templates/common/.agents/skills/migration/references/canon-migration.md +471 -0
  60. package/templates/common/.content/config/site.json.tmpl +15 -0
  61. package/templates/common/.content/pages/home/_index.json +4 -103
  62. package/templates/common/.nvmrc +1 -0
  63. package/templates/common/README.md.tmpl +32 -11
  64. package/templates/common/contracts/components/index.ts +1 -19
  65. package/templates/common/design-system/tokens/colors.css +34 -10
  66. package/templates/common/starter-content/.content/config/robots.txt +2 -0
  67. package/templates/common/starter-content/.content/pages/home/_index.json +112 -0
  68. package/templates/common/starter-content/.content/schemas/site.schema.json +138 -0
  69. package/templates/nextjs/starter-content/src/cms/contracts/components/container.contract.ts +19 -0
  70. package/templates/nextjs/starter-content/src/cms/contracts/components/featureCard.contract.ts +15 -0
  71. package/templates/nextjs/starter-content/src/cms/contracts/components/featureGrid.contract.ts +16 -0
  72. package/templates/nextjs/starter-content/src/cms/contracts/components/index.ts +21 -0
  73. package/templates/nextjs/starter-content/src/cms/contracts/components/siteFooter.contract.ts +45 -0
  74. package/templates/nextjs/starter-content/src/cms/contracts/components/siteNavigation.contract.ts +30 -0
  75. package/templates/nextjs/starter-content/src/cms/contracts/components/statsBar.contract.ts +19 -0
  76. package/templates/nextjs/starter-content/src/cms/registry.ts +28 -0
  77. package/templates/nextjs/template/{.aci.yaml → .aci.yaml.tmpl} +1 -1
  78. package/templates/nextjs/template/README.md.tmpl +52 -0
  79. package/templates/nextjs/template/gitignore +15 -0
  80. package/templates/nextjs/template/next.config.mjs +1 -6
  81. package/templates/nextjs/template/package.json.tmpl +5 -3
  82. package/templates/nextjs/template/src/app/gradial/assets/[...path]/route.ts +1 -4
  83. package/templates/nextjs/template/src/cms/contracts/components/index.ts +1 -13
  84. package/templates/nextjs/template/src/cms/registry.ts +3 -26
  85. package/templates/nextjs/template/src/design-system/styles.css +346 -0
  86. package/templates/nextjs/template/src/design-system/tokens/colors.css +110 -0
  87. package/templates/nextjs/template/src/design-system/tokens/components.css +86 -0
  88. package/templates/nextjs/template/src/design-system/tokens/index.css +6 -0
  89. package/templates/nextjs/template/src/design-system/tokens/radii.css +5 -0
  90. package/templates/nextjs/template/src/design-system/tokens/shadows.css +9 -0
  91. package/templates/nextjs/template/src/design-system/tokens/spacing.css +26 -0
  92. package/templates/nextjs/template/src/design-system/tokens/typography.css +32 -0
  93. package/templates/nextjs/template/src/middleware.ts.tmpl +12 -0
  94. package/templates/nextjs/template/tests/conformance.test.ts.tmpl +12 -0
  95. package/bin/aci-darwin-arm64 +0 -0
  96. package/templates/nextjs/template/src/cms/contracts/components/container.contract.ts +0 -20
  97. package/templates/nextjs/template/src/middleware.ts +0 -7
  98. /package/templates/{nextjs/template → astro/starter-content}/src/cms/contracts/components/siteFooter.contract.ts +0 -0
  99. /package/templates/{nextjs/template → astro/starter-content}/src/cms/contracts/components/siteNavigation.contract.ts +0 -0
  100. /package/templates/astro/{template → starter-content}/src/components/chrome/Footer.astro +0 -0
  101. /package/templates/astro/{template → starter-content}/src/components/chrome/Header.astro +0 -0
  102. /package/templates/astro/{template → starter-content}/src/components/elements/AtomicBlock.astro +0 -0
  103. /package/templates/astro/{template → starter-content}/src/components/elements/AtomicBlocks.astro +0 -0
  104. /package/templates/astro/{template → starter-content}/src/components/elements/Button.astro +0 -0
  105. /package/templates/astro/{template → starter-content}/src/components/elements/ButtonBlock.astro +0 -0
  106. /package/templates/astro/{template → starter-content}/src/components/elements/Container.astro +0 -0
  107. /package/templates/astro/{template → starter-content}/src/components/elements/Icon.astro +0 -0
  108. /package/templates/astro/{template → starter-content}/src/components/elements/Logo.astro +0 -0
  109. /package/templates/astro/{template → starter-content}/src/components/elements/RemoteImage.astro +0 -0
  110. /package/templates/astro/{template → starter-content}/src/components/sections/ContainerSection.astro +0 -0
  111. /package/templates/astro/{template → starter-content}/src/components/sections/FeatureCard.astro +0 -0
  112. /package/templates/astro/{template → starter-content}/src/components/sections/FeatureGrid.astro +0 -0
  113. /package/templates/astro/{template → starter-content}/src/components/sections/HomeHero.astro +0 -0
  114. /package/templates/astro/{template → starter-content}/src/components/sections/StatsBar.astro +0 -0
  115. /package/templates/astro/{template → starter-content}/src/fixtures/atomicBlocks.ts +0 -0
  116. /package/templates/astro/{template → starter-content}/src/fixtures/composition.ts +0 -0
  117. /package/templates/astro/{template → starter-content}/src/fixtures/index.ts +0 -0
  118. /package/templates/astro/{template → starter-content}/src/fixtures/sections.ts +0 -0
  119. /package/templates/astro/{template → starter-content}/src/render/RenderPage.astro +0 -0
  120. /package/templates/astro/{template → starter-content}/src/stories/CompositionStoryFrame.astro +0 -0
  121. /package/templates/astro/{template → starter-content}/src/stories/HomeHero.stories.ts +0 -0
  122. /package/templates/astro/{template → starter-content}/src/stories/SectionStoryFrame.astro +0 -0
  123. /package/templates/astro/{template → starter-content}/src/stories/StoryDocFrame.astro +0 -0
  124. /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/7f/bf/7fbfc7fe230ff12688c496f660119e41d9725c4504d82e310c15665c73c09292 +0 -0
  125. /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/a0/f5/a0f506689de9b15a7055f70103a3f02cd3ba105771ae2de6754df2ede1210d3a +0 -0
  126. /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/dd/b7/ddb7e9642be08317bcd4b2bd26b58ba8d0d34dd7239e03e684a4f3634fa3845b +0 -0
  127. /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/fb/32/fb3260e8286ea8231ea1c77b9c0be92d6edd9026565731eb14cfdcfd6b1b75b3 +0 -0
  128. /package/templates/common/{.content → starter-content/.content}/config/site.json +0 -0
  129. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/asset.json +0 -0
  130. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/editorial.json +0 -0
  131. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/governance.json +0 -0
  132. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/versions/v0001.json +0 -0
  133. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/asset.json +0 -0
  134. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/editorial.json +0 -0
  135. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/governance.json +0 -0
  136. /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/versions/v0001.json +0 -0
  137. /package/templates/common/{.content → starter-content/.content}/fragments/navbar/_index.json +0 -0
  138. /package/templates/common/{.content → starter-content/.content}/fragments/site-footer/_index.json +0 -0
  139. /package/templates/common/{.content → starter-content/.content}/pages/about/_index.json +0 -0
  140. /package/templates/common/{public → starter-content/public}/assets/Dwire-model.png +0 -0
  141. /package/templates/common/{public → starter-content/public}/assets/seattle.avif +0 -0
  142. /package/templates/nextjs/{template → starter-content}/src/cms/contracts/components/button.contract.ts +0 -0
  143. /package/templates/nextjs/{template → starter-content}/src/cms/contracts/components/homeHero.contract.ts +0 -0
  144. /package/templates/nextjs/{template → starter-content}/src/components/chrome/Footer.tsx +0 -0
  145. /package/templates/nextjs/{template → starter-content}/src/components/chrome/Header.tsx +0 -0
  146. /package/templates/nextjs/{template → starter-content}/src/components/elements/AtomicBlock.tsx +0 -0
  147. /package/templates/nextjs/{template → starter-content}/src/components/elements/Button.tsx +0 -0
  148. /package/templates/nextjs/{template → starter-content}/src/components/elements/ButtonBlock.tsx +0 -0
  149. /package/templates/nextjs/{template → starter-content}/src/components/elements/Container.tsx +0 -0
  150. /package/templates/nextjs/{template → starter-content}/src/components/elements/Icon.tsx +0 -0
  151. /package/templates/nextjs/{template → starter-content}/src/components/elements/Logo.tsx +0 -0
  152. /package/templates/nextjs/{template → starter-content}/src/components/sections/ContainerSection.tsx +0 -0
  153. /package/templates/nextjs/{template → starter-content}/src/components/sections/FeatureCard.tsx +0 -0
  154. /package/templates/nextjs/{template → starter-content}/src/components/sections/FeatureGrid.tsx +0 -0
  155. /package/templates/nextjs/{template → starter-content}/src/components/sections/HomeHero.tsx +0 -0
  156. /package/templates/nextjs/{template → starter-content}/src/components/sections/StatsBar.tsx +0 -0
  157. /package/templates/nextjs/{template → starter-content}/src/stories/Button.stories.tsx +0 -0
  158. /package/templates/nextjs/{template → starter-content}/src/stories/Header.stories.tsx +0 -0
  159. /package/templates/nextjs/{template → starter-content}/src/stories/HomeHero.stories.tsx +0 -0
@@ -1,112 +1,13 @@
1
1
  {
2
2
  "$type": "page",
3
- "id": "meridian-home",
3
+ "id": "home",
4
4
  "status": "published",
5
5
  "layout": "default",
6
6
  "metadata": {
7
- "title": "Meridian — Global Satellite Internet",
8
- "description": "Connect from anywhere on Earth. Low-latency satellite internet for homes, businesses, and beyond.",
9
- "canonical": "https://www.meridian.local/"
7
+ "title": "Home",
8
+ "description": "Welcome to your new ACI site."
10
9
  },
11
10
  "regions": {
12
- "main": [
13
- {
14
- "id": "hero",
15
- "component": "home_hero",
16
- "props": {
17
- "eyebrow": "Global satellite internet",
18
- "headline": "Connect from anywhere on Earth.",
19
- "description": "Meridian delivers low-latency broadband to homes, businesses, and remote operations in over 40 countries. No ground infrastructure required.",
20
- "ctaLabel": "Explore plans",
21
- "ctaHref": "/plans/",
22
- "image": {
23
- "$type": "dam.assetRef",
24
- "assetId": "ast_site_home_hero",
25
- "alt": "Light abstract hero background with satellite constellation"
26
- }
27
- }
28
- },
29
- {
30
- "id": "why-meridian",
31
- "component": "feature_grid",
32
- "props": {
33
- "title": "Why Meridian",
34
- "subtitle": "Engineered for the edges of the world.",
35
- "features": [
36
- {
37
- "id": "global-coverage",
38
- "component": "feature_card",
39
- "props": {
40
- "icon": "globe",
41
- "title": "Global coverage",
42
- "description": "A constellation of low-orbit satellites keeps you connected across continents, oceans, and remote terrain."
43
- }
44
- },
45
- {
46
- "id": "low-latency",
47
- "component": "feature_card",
48
- "props": {
49
- "icon": "speed",
50
- "title": "Low latency",
51
- "description": "Sub-50ms latency means video calls, gaming, and real-time control feel local, even in the middle of nowhere."
52
- }
53
- },
54
- {
55
- "id": "easy-setup",
56
- "component": "feature_card",
57
- "props": {
58
- "icon": "setup",
59
- "title": "Easy setup",
60
- "description": "A compact terminal and a phone app. Point at the sky, power on, and get online in minutes."
61
- }
62
- }
63
- ]
64
- }
65
- },
66
- {
67
- "id": "stats",
68
- "component": "stats_bar",
69
- "props": {
70
- "stats": [
71
- { "label": "Network uptime", "value": "99.9", "suffix": "%" },
72
- { "label": "Average latency", "value": "<50", "suffix": "ms" },
73
- { "label": "Countries covered", "value": "40", "suffix": "+" },
74
- { "label": "Orbital satellites", "value": "2,400", "suffix": "" }
75
- ]
76
- }
77
- },
78
- {
79
- "id": "cta",
80
- "component": "container",
81
- "props": {
82
- "theme": "light",
83
- "className": "items-center justify-center text-center",
84
- "content": [
85
- {
86
- "id": "cta-primary",
87
- "component": "button",
88
- "props": {
89
- "label": "Explore plans",
90
- "href": "/plans/",
91
- "variant": "primary",
92
- "icon": "arrow_forward",
93
- "iconPosition": "after"
94
- }
95
- },
96
- {
97
- "id": "cta-secondary",
98
- "component": "button",
99
- "props": {
100
- "label": "Contact sales",
101
- "href": "/contact-sales/",
102
- "variant": "outline",
103
- "icon": "arrow_forward",
104
- "iconPosition": "after"
105
- }
106
- }
107
- ]
108
- }
109
- }
110
- ]
11
+ "main": []
111
12
  }
112
13
  }
@@ -0,0 +1 @@
1
+ 22
@@ -1,12 +1,27 @@
1
1
  # {{siteName}}
2
2
 
3
+ A CMS-driven {{frameworkName}} site built on the **Gradial ACI** content
4
+ platform, seeded with the Meridian sample site.
5
+
6
+ ## Prerequisites
7
+
8
+ - **Node 22** (see `.nvmrc`)
9
+ - **npm 10+** (ships with Node 22)
10
+
11
+ No environment variables, accounts, or API tokens are required for local
12
+ development.
13
+
3
14
  ## Quick Start
4
15
 
5
16
  ```bash
6
17
  npm install
7
- npm run dev
18
+ npm run dev # → {{devUrl}}/
8
19
  ```
9
20
 
21
+ The sample site serves the home page at `/` and an about page at `/about/`.
22
+ The dev server compiles `.content/` into `.aci/compiled/` on startup and
23
+ recompiles (with browser refresh) whenever content changes.
24
+
10
25
  ## Skills
11
26
 
12
27
  This project uses progressive disclosure skills for both humans and agents.
@@ -23,27 +38,33 @@ Agents: load skills from `.agents/skills/`. See `.agents/AGENTS.md`.
23
38
  ## Commands
24
39
 
25
40
  ```bash
26
- npm run dev # Start dev server
27
- npm run build # Build for production
28
- npm run typecheck # TypeScript type checking
29
- npm run aci:validate # Validate content against schemas
30
- npm run aci:compile # Compile contract registry
31
- npm run content:compile # Compile content into .aci/compiled/
32
- npm run aci:doctor # Check project health
33
- npm run aci:build # Full build (contracts + content + framework)
41
+ npm run dev # Start dev server at {{devUrl}}
42
+ npm run build # Production build
43
+ npm run content:compile # Compile content from .content/ into .aci/
44
+ npm run typecheck # TypeScript validation
45
+ npm run storybook # Component development (http://localhost:6006)
46
+ npm run build:storybook # Build Storybook for deployment
34
47
  ```
35
48
 
36
49
  ## Project Structure
37
50
 
38
51
  ```
39
- .content/ Content source (JSON)
52
+ .content/ Content source (JSON pages, fragments, site config)
40
53
  src/cms/ Contracts and component registry
41
54
  src/components/ Runtime components (elements, sections, chrome)
42
55
  src/design-system/ Design tokens and global styles
43
56
  .agents/skills/ Skills for humans and agents
44
- .aci/ Generated artifacts (compiled, schemas)
57
+ .aci/ Generated artifacts (compiled content, schemas) — git-ignored
45
58
  ```
46
59
 
60
+ ## How It Works
61
+
62
+ Pages are JSON files in `.content/pages/{slug}/_index.json`. Each page lists
63
+ content blocks in `regions.main`; a block names a component and passes props.
64
+ Components are defined by **contracts** (Zod schemas in
65
+ `src/cms/contracts/components/`) and mapped to rendered components in
66
+ `src/cms/registry.ts`.
67
+
47
68
  ## Personalization
48
69
 
49
70
  The `personalization` block in `.content/config/site.json` controls the
@@ -1,21 +1,3 @@
1
- import { buttonContract } from './button.contract';
2
- import { containerContract } from './container.contract';
3
- import { featureCardContract } from './featureCard.contract';
4
- import { featureGridContract } from './featureGrid.contract';
5
- import { homeHeroContract } from './homeHero.contract';
6
- import { siteNavigationContract } from './siteNavigation.contract';
7
- import { siteFooterContract } from './siteFooter.contract';
8
- import { statsBarContract } from './statsBar.contract';
9
-
10
- const componentContracts = [
11
- homeHeroContract,
12
- containerContract,
13
- buttonContract,
14
- siteNavigationContract,
15
- siteFooterContract,
16
- featureGridContract,
17
- featureCardContract,
18
- statsBarContract,
19
- ];
1
+ const componentContracts: readonly unknown[] = [];
20
2
 
21
3
  export default componentContracts;
@@ -39,6 +39,24 @@
39
39
  /* Focus */
40
40
  --color-focus: var(--color-brand-600);
41
41
 
42
+ /* Extended surface palette */
43
+ --color-surface-500: #64748b;
44
+ --color-surface-600: #475569;
45
+ --color-surface-700: #334155;
46
+ --color-surface-800: #1e293b;
47
+
48
+ /* "Space" dark section palette — used by FeatureGrid, StatsBar, FeatureCard */
49
+ --color-space-deep: #080e1e;
50
+ --color-space-surface: #0f1829;
51
+ --color-space-raised: #162036;
52
+ --color-edge-space: rgba(255, 255, 255, 0.06);
53
+ --color-edge-space-strong: rgba(255, 255, 255, 0.12);
54
+ --color-fg-space-muted: #94a3b8;
55
+ --color-fg-secondary: #64748b;
56
+ --color-brand-blue: #0ea5e9;
57
+ --color-brand-blue-light: #38bdf8;
58
+ --color-launch-orange: #f97316;
59
+
42
60
  /* Semantic aliases — light theme default */
43
61
  --color-page: var(--color-white);
44
62
  --color-page-inverse: var(--color-surface-900);
@@ -76,27 +94,33 @@
76
94
 
77
95
  /* Gradients */
78
96
  --gradient-hero-base: radial-gradient(
79
- ellipse 80% 60% at 50% 0%,
80
- rgba(14, 165, 233, 0.12) 0%,
81
- rgba(14, 165, 233, 0.04) 40%,
97
+ ellipse 120% 80% at 60% 10%,
98
+ rgba(14, 165, 233, 0.22) 0%,
99
+ rgba(14, 165, 233, 0.08) 40%,
82
100
  transparent 70%
83
101
  );
84
102
  --gradient-hero-overlay: linear-gradient(
85
103
  180deg,
86
- rgba(255, 255, 255, 0.2) 0%,
87
- rgba(255, 255, 255, 0.7) 60%,
104
+ rgba(6, 10, 26, 0.70) 0%,
105
+ rgba(6, 10, 26, 0.65) 30%,
106
+ rgba(6, 10, 26, 0.55) 55%,
107
+ rgba(6, 10, 26, 0.40) 75%,
108
+ rgba(30, 40, 60, 0.25) 90%,
88
109
  rgba(255, 255, 255, 0.95) 100%
89
110
  );
90
111
  --gradient-hero-overlay-rtl: linear-gradient(
91
112
  180deg,
92
113
  rgba(255, 255, 255, 0.95) 0%,
93
- rgba(255, 255, 255, 0.7) 60%,
94
- rgba(255, 255, 255, 0.2) 100%
114
+ rgba(30, 40, 60, 0.25) 10%,
115
+ rgba(6, 10, 26, 0.40) 25%,
116
+ rgba(6, 10, 26, 0.55) 45%,
117
+ rgba(6, 10, 26, 0.65) 70%,
118
+ rgba(6, 10, 26, 0.70) 100%
95
119
  );
96
120
  --gradient-hero-radial: radial-gradient(
97
- ellipse 60% 40% at 80% 20%,
98
- rgba(249, 115, 22, 0.06) 0%,
99
- transparent 60%
121
+ ellipse 80% 60% at 70% 20%,
122
+ rgba(14, 165, 233, 0.10) 0%,
123
+ transparent 55%
100
124
  );
101
125
  --gradient-card: linear-gradient(
102
126
  180deg,
@@ -0,0 +1,2 @@
1
+ User-agent: *
2
+ Allow: /
@@ -0,0 +1,112 @@
1
+ {
2
+ "$type": "page",
3
+ "id": "meridian-home",
4
+ "status": "published",
5
+ "layout": "default",
6
+ "metadata": {
7
+ "title": "Meridian — Global Satellite Internet",
8
+ "description": "Connect from anywhere on Earth. Low-latency satellite internet for homes, businesses, and beyond.",
9
+ "canonical": "https://www.meridian.local/"
10
+ },
11
+ "regions": {
12
+ "main": [
13
+ {
14
+ "id": "hero",
15
+ "component": "home_hero",
16
+ "props": {
17
+ "eyebrow": "Global satellite internet",
18
+ "headline": "Connect from anywhere on Earth.",
19
+ "description": "Meridian delivers low-latency broadband to homes, businesses, and remote operations in over 40 countries. No ground infrastructure required.",
20
+ "ctaLabel": "Explore plans",
21
+ "ctaHref": "/plans/",
22
+ "image": {
23
+ "$type": "dam.assetRef",
24
+ "assetId": "ast_site_home_hero",
25
+ "alt": "Light abstract hero background with satellite constellation"
26
+ }
27
+ }
28
+ },
29
+ {
30
+ "id": "why-meridian",
31
+ "component": "feature_grid",
32
+ "props": {
33
+ "title": "Why Meridian",
34
+ "subtitle": "Engineered for the edges of the world.",
35
+ "features": [
36
+ {
37
+ "id": "global-coverage",
38
+ "component": "feature_card",
39
+ "props": {
40
+ "icon": "globe",
41
+ "title": "Global coverage",
42
+ "description": "A constellation of low-orbit satellites keeps you connected across continents, oceans, and remote terrain."
43
+ }
44
+ },
45
+ {
46
+ "id": "low-latency",
47
+ "component": "feature_card",
48
+ "props": {
49
+ "icon": "speed",
50
+ "title": "Low latency",
51
+ "description": "Sub-50ms latency means video calls, gaming, and real-time control feel local, even in the middle of nowhere."
52
+ }
53
+ },
54
+ {
55
+ "id": "easy-setup",
56
+ "component": "feature_card",
57
+ "props": {
58
+ "icon": "setup",
59
+ "title": "Easy setup",
60
+ "description": "A compact terminal and a phone app. Point at the sky, power on, and get online in minutes."
61
+ }
62
+ }
63
+ ]
64
+ }
65
+ },
66
+ {
67
+ "id": "stats",
68
+ "component": "stats_bar",
69
+ "props": {
70
+ "stats": [
71
+ { "label": "Network uptime", "value": "99.9", "suffix": "%" },
72
+ { "label": "Average latency", "value": "<50", "suffix": "ms" },
73
+ { "label": "Countries covered", "value": "40", "suffix": "+" },
74
+ { "label": "Orbital satellites", "value": "2,400", "suffix": "" }
75
+ ]
76
+ }
77
+ },
78
+ {
79
+ "id": "cta",
80
+ "component": "container",
81
+ "props": {
82
+ "theme": "light",
83
+ "className": "items-center justify-center text-center",
84
+ "content": [
85
+ {
86
+ "id": "cta-primary",
87
+ "component": "button",
88
+ "props": {
89
+ "label": "Explore plans",
90
+ "href": "/plans/",
91
+ "variant": "primary",
92
+ "icon": "arrow_forward",
93
+ "iconPosition": "after"
94
+ }
95
+ },
96
+ {
97
+ "id": "cta-secondary",
98
+ "component": "button",
99
+ "props": {
100
+ "label": "Contact sales",
101
+ "href": "/contact-sales/",
102
+ "variant": "outline",
103
+ "icon": "arrow_forward",
104
+ "iconPosition": "after"
105
+ }
106
+ }
107
+ ]
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ }
@@ -0,0 +1,138 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://baremetal.local/schemas/site.schema.json",
4
+ "title": "bare-metal Site Config",
5
+ "type": "object",
6
+ "required": ["$type", "id", "status", "title", "domain", "defaultLocale", "overlayResolution"],
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "$type": { "const": "site" },
10
+ "id": { "type": "string", "minLength": 1 },
11
+ "status": { "type": "string", "minLength": 1 },
12
+ "title": { "type": "string", "minLength": 1 },
13
+ "domain": { "type": "string", "minLength": 1 },
14
+ "defaultLocale": { "type": "string", "minLength": 1 },
15
+ "locales": {
16
+ "type": "array",
17
+ "items": { "type": "string", "minLength": 1 }
18
+ },
19
+ "overlayResolution": {
20
+ "type": "array",
21
+ "items": { "enum": ["locale", "audience"] }
22
+ },
23
+ "brandHref": { "type": "string" },
24
+ "brandLogo": {
25
+ "type": "object",
26
+ "additionalProperties": true,
27
+ "properties": {
28
+ "src": { "type": "string", "minLength": 1 },
29
+ "alt": { "type": "string" }
30
+ }
31
+ },
32
+ "navigation": {
33
+ "type": "array",
34
+ "items": { "$ref": "#/$defs/link" }
35
+ },
36
+ "utilities": {
37
+ "type": "array",
38
+ "items": {
39
+ "allOf": [
40
+ { "$ref": "#/$defs/link" },
41
+ {
42
+ "type": "object",
43
+ "properties": {
44
+ "variant": {
45
+ "enum": ["primary", "secondary", "outline", "ghost"]
46
+ }
47
+ }
48
+ }
49
+ ]
50
+ }
51
+ },
52
+ "footer": {
53
+ "type": "object",
54
+ "additionalProperties": true,
55
+ "properties": {
56
+ "columns": {
57
+ "type": "array",
58
+ "items": { "$ref": "#/$defs/footerColumn" }
59
+ },
60
+ "social": {
61
+ "type": "array",
62
+ "items": { "$ref": "#/$defs/link" }
63
+ },
64
+ "legalLinks": {
65
+ "type": "array",
66
+ "items": { "$ref": "#/$defs/link" }
67
+ },
68
+ "copyright": { "type": "string" }
69
+ }
70
+ },
71
+ "seo": {
72
+ "type": "object",
73
+ "additionalProperties": true,
74
+ "properties": {
75
+ "title": { "type": "string" },
76
+ "description": { "type": "string" },
77
+ "siteName": { "type": "string" }
78
+ }
79
+ },
80
+ "personalization": {
81
+ "type": "object",
82
+ "additionalProperties": true,
83
+ "properties": {
84
+ "collect": { "type": "boolean" },
85
+ "consentPreset": {
86
+ "enum": ["c15t", "onetrust", "cookiebot", "trustarc", "manual"]
87
+ },
88
+ "consentCategories": {
89
+ "type": "string",
90
+ "pattern": "^\\s*[A-Za-z0-9._-]+(\\s*,\\s*[A-Za-z0-9._-]+)*\\s*$"
91
+ },
92
+ "debug": { "type": "boolean" }
93
+ }
94
+ }
95
+ },
96
+ "$defs": {
97
+ "link": {
98
+ "type": "object",
99
+ "required": ["id", "label", "href"],
100
+ "additionalProperties": true,
101
+ "properties": {
102
+ "id": { "type": "string", "minLength": 1 },
103
+ "label": { "type": "string", "minLength": 1 },
104
+ "href": { "type": "string", "minLength": 1 }
105
+ }
106
+ },
107
+ "footerGroup": {
108
+ "type": "object",
109
+ "required": ["id", "title", "links"],
110
+ "additionalProperties": true,
111
+ "properties": {
112
+ "id": { "type": "string", "minLength": 1 },
113
+ "title": { "type": "string" },
114
+ "links": {
115
+ "type": "array",
116
+ "items": { "$ref": "#/$defs/link" }
117
+ }
118
+ }
119
+ },
120
+ "footerColumn": {
121
+ "type": "object",
122
+ "required": ["id"],
123
+ "additionalProperties": true,
124
+ "properties": {
125
+ "id": { "type": "string", "minLength": 1 },
126
+ "title": { "type": "string" },
127
+ "groups": {
128
+ "type": "array",
129
+ "items": { "$ref": "#/$defs/footerGroup" }
130
+ },
131
+ "links": {
132
+ "type": "array",
133
+ "items": { "$ref": "#/$defs/link" }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
@@ -0,0 +1,19 @@
1
+ import { defineComponentContract, blockRefArray } from '@gradial/aci';
2
+ import { z } from 'zod';
3
+ import { buttonContract } from './button.contract';
4
+ import { featureGridContract } from './featureGrid.contract';
5
+ import { featureCardContract } from './featureCard.contract';
6
+ import { statsBarContract } from './statsBar.contract';
7
+
8
+ export const schema = z.object({
9
+ theme: z.enum(['auto', 'light', 'dark']).optional(),
10
+ className: z.string().optional(),
11
+ content: blockRefArray([buttonContract, featureGridContract, featureCardContract, statsBarContract]).optional(),
12
+ });
13
+
14
+ export type ContentProps = z.infer<typeof schema>;
15
+
16
+ export const containerContract = defineComponentContract({
17
+ id: 'container',
18
+ props: schema,
19
+ });
@@ -0,0 +1,15 @@
1
+ import { defineComponentContract } from '@gradial/aci';
2
+ import { z } from 'zod';
3
+
4
+ export const schema = z.object({
5
+ icon: z.string().optional(),
6
+ title: z.string().min(1),
7
+ description: z.string().optional(),
8
+ });
9
+
10
+ export type ContentProps = z.infer<typeof schema>;
11
+
12
+ export const featureCardContract = defineComponentContract({
13
+ id: 'feature_card',
14
+ props: schema,
15
+ });
@@ -0,0 +1,16 @@
1
+ import { defineComponentContract, blockRefArray } from '@gradial/aci';
2
+ import { z } from 'zod';
3
+ import { featureCardContract } from './featureCard.contract';
4
+
5
+ export const schema = z.object({
6
+ title: z.string().optional(),
7
+ subtitle: z.string().optional(),
8
+ features: blockRefArray([featureCardContract]).optional(),
9
+ });
10
+
11
+ export type ContentProps = z.infer<typeof schema>;
12
+
13
+ export const featureGridContract = defineComponentContract({
14
+ id: 'feature_grid',
15
+ props: schema,
16
+ });
@@ -0,0 +1,21 @@
1
+ import { buttonContract } from './button.contract';
2
+ import { containerContract } from './container.contract';
3
+ import { featureCardContract } from './featureCard.contract';
4
+ import { featureGridContract } from './featureGrid.contract';
5
+ import { homeHeroContract } from './homeHero.contract';
6
+ import { siteFooterContract } from './siteFooter.contract';
7
+ import { siteNavigationContract } from './siteNavigation.contract';
8
+ import { statsBarContract } from './statsBar.contract';
9
+
10
+ const componentContracts = [
11
+ homeHeroContract,
12
+ containerContract,
13
+ buttonContract,
14
+ siteNavigationContract,
15
+ siteFooterContract,
16
+ featureGridContract,
17
+ featureCardContract,
18
+ statsBarContract,
19
+ ];
20
+
21
+ export default componentContracts;
@@ -0,0 +1,45 @@
1
+ import { defineComponentContract } from '@gradial/aci';
2
+ import { z } from 'zod';
3
+
4
+ const linkSchema = z.object({
5
+ id: z.string().min(1),
6
+ label: z.string().min(1),
7
+ href: z.string().min(1),
8
+ });
9
+
10
+ const groupSchema = z.object({
11
+ id: z.string().min(1),
12
+ title: z.string(),
13
+ links: z.array(linkSchema),
14
+ });
15
+
16
+ const columnSchema = z.object({
17
+ id: z.string().min(1),
18
+ title: z.string().optional(),
19
+ links: z.array(linkSchema).optional(),
20
+ groups: z.array(groupSchema).optional(),
21
+ });
22
+
23
+ const socialSchema = linkSchema.extend({
24
+ icon: z.string().optional(),
25
+ });
26
+
27
+ export const schema = z.object({
28
+ brandHref: z.string().min(1),
29
+ brandLabel: z.string().min(1),
30
+ brandLogo: z.object({
31
+ src: z.string(),
32
+ alt: z.string(),
33
+ }).nullable().optional(),
34
+ columns: z.array(columnSchema),
35
+ social: z.array(socialSchema).optional(),
36
+ legalLinks: z.array(linkSchema).optional(),
37
+ copyright: z.string().optional(),
38
+ });
39
+
40
+ export type ContentProps = z.infer<typeof schema>;
41
+
42
+ export const siteFooterContract = defineComponentContract({
43
+ id: 'site-footer',
44
+ props: schema,
45
+ });