@rizom/site-rizom-ai 0.2.0-alpha.142
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 +42 -0
- package/src/index.ts +3 -0
- package/src/layout.tsx +84 -0
- package/src/routes.ts +27 -0
- package/src/sections/answer/layout.tsx +40 -0
- package/src/sections/answer/scales-diagram.tsx +254 -0
- package/src/sections/answer/schema.ts +7 -0
- package/src/sections/ecosystem.tsx +3 -0
- package/src/sections/hero/layout.tsx +45 -0
- package/src/sections/hero/schema.ts +13 -0
- package/src/sections/mission/layout.tsx +44 -0
- package/src/sections/mission/schema.ts +9 -0
- package/src/sections/ownership/layout.tsx +45 -0
- package/src/sections/ownership/schema.ts +11 -0
- package/src/sections/problem/layout.tsx +56 -0
- package/src/sections/problem/schema.ts +9 -0
- package/src/sections/products/ProductCard.tsx +137 -0
- package/src/sections/products/ProductIllustration.tsx +690 -0
- package/src/sections/products/layout.tsx +21 -0
- package/src/sections/products/schema.ts +15 -0
- package/src/sections/quickstart/layout.tsx +53 -0
- package/src/sections/quickstart/schema.ts +9 -0
- package/src/site-content.ts +190 -0
- package/src/site.ts +15 -0
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rizom/site-rizom-ai",
|
|
3
|
+
"version": "0.2.0-alpha.142",
|
|
4
|
+
"description": "Rizom AI site package for hosted Rover deployments",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"test": "bun test",
|
|
15
|
+
"lint": "eslint . --max-warnings 0",
|
|
16
|
+
"lint:fix": "eslint . --max-warnings 0 --fix",
|
|
17
|
+
"postpack": "publish-manifest restore",
|
|
18
|
+
"prepack": "publish-manifest prepare"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@rizom/site": "0.2.0-alpha.142",
|
|
22
|
+
"@rizom/site-rizom": "0.2.0-alpha.142",
|
|
23
|
+
"preact": "^10.27.2"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/rizom-ai/brains.git",
|
|
31
|
+
"directory": "sites/rizom-ai"
|
|
32
|
+
},
|
|
33
|
+
"license": "Apache-2.0",
|
|
34
|
+
"author": "Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",
|
|
35
|
+
"homepage": "https://github.com/rizom-ai/brains/tree/main/sites/rizom-ai#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/rizom-ai/brains/issues"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"bun": ">=1.3.3"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.ts
ADDED
package/src/layout.tsx
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { ComponentChildren, JSX } from "preact";
|
|
3
|
+
import type { SiteLayoutInfo } from "@rizom/site";
|
|
4
|
+
import {
|
|
5
|
+
Footer,
|
|
6
|
+
Header,
|
|
7
|
+
RizomFrame,
|
|
8
|
+
SideNav,
|
|
9
|
+
socialLinksToRizomLinks,
|
|
10
|
+
} from "@rizom/site-rizom";
|
|
11
|
+
|
|
12
|
+
interface AiSiteInfo extends Pick<SiteLayoutInfo, "socialLinks"> {
|
|
13
|
+
cta?: {
|
|
14
|
+
buttonLink: string;
|
|
15
|
+
buttonText: string;
|
|
16
|
+
};
|
|
17
|
+
copyright: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface AiLayoutProps {
|
|
21
|
+
sections: ComponentChildren[];
|
|
22
|
+
title: string;
|
|
23
|
+
description: string;
|
|
24
|
+
path: string;
|
|
25
|
+
siteInfo: AiSiteInfo;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const NAV_LINKS = [
|
|
29
|
+
{ href: "#problem", label: "Platform" },
|
|
30
|
+
{ href: "#quickstart", label: "Docs" },
|
|
31
|
+
{ href: "#ecosystem", label: "Network" },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const PRIMARY_CTA = {
|
|
35
|
+
href: "#quickstart",
|
|
36
|
+
label: "Get Started",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const FOOTER_LINKS = [
|
|
40
|
+
{
|
|
41
|
+
href: "https://github.com/rizom-ai/brains/tree/main/docs",
|
|
42
|
+
label: "Documentation",
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const SIDE_NAV_ITEMS = [
|
|
47
|
+
{ href: "#hero", label: "Intro" },
|
|
48
|
+
{ href: "#problem", label: "Problem" },
|
|
49
|
+
{ href: "#answer", label: "Answer" },
|
|
50
|
+
{ href: "#ownership", label: "Open" },
|
|
51
|
+
{ href: "#quickstart", label: "Start" },
|
|
52
|
+
{ href: "#mission", label: "Vision" },
|
|
53
|
+
{ href: "#ecosystem", label: "Network" },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
export const AiLayout = ({
|
|
57
|
+
sections,
|
|
58
|
+
siteInfo,
|
|
59
|
+
}: AiLayoutProps): JSX.Element => (
|
|
60
|
+
<RizomFrame>
|
|
61
|
+
<Header
|
|
62
|
+
brandSuffix="ai"
|
|
63
|
+
navLinks={NAV_LINKS}
|
|
64
|
+
primaryCta={
|
|
65
|
+
siteInfo.cta
|
|
66
|
+
? {
|
|
67
|
+
href: siteInfo.cta.buttonLink,
|
|
68
|
+
label: siteInfo.cta.buttonText,
|
|
69
|
+
}
|
|
70
|
+
: PRIMARY_CTA
|
|
71
|
+
}
|
|
72
|
+
/>
|
|
73
|
+
<SideNav items={SIDE_NAV_ITEMS} />
|
|
74
|
+
<main>{sections}</main>
|
|
75
|
+
<Footer
|
|
76
|
+
brandSuffix="ai"
|
|
77
|
+
metaLabel={siteInfo.copyright}
|
|
78
|
+
links={[
|
|
79
|
+
...FOOTER_LINKS,
|
|
80
|
+
...socialLinksToRizomLinks(siteInfo, ["github", "linkedin"]),
|
|
81
|
+
]}
|
|
82
|
+
/>
|
|
83
|
+
</RizomFrame>
|
|
84
|
+
);
|
package/src/routes.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RouteDefinitionInput } from "@rizom/site";
|
|
2
|
+
|
|
3
|
+
export const aiRoutes: RouteDefinitionInput[] = [
|
|
4
|
+
{
|
|
5
|
+
id: "home",
|
|
6
|
+
path: "/",
|
|
7
|
+
layout: "default",
|
|
8
|
+
navigation: {
|
|
9
|
+
show: false,
|
|
10
|
+
slot: "secondary",
|
|
11
|
+
priority: 10,
|
|
12
|
+
},
|
|
13
|
+
sections: [
|
|
14
|
+
{ id: "hero", template: "landing-page:hero", content: {} },
|
|
15
|
+
{ id: "problem", template: "landing-page:problem", content: {} },
|
|
16
|
+
{ id: "answer", template: "landing-page:answer", content: {} },
|
|
17
|
+
{ id: "products", template: "landing-page:products", content: {} },
|
|
18
|
+
{ id: "ownership", template: "landing-page:ownership", content: {} },
|
|
19
|
+
{ id: "quickstart", template: "landing-page:quickstart", content: {} },
|
|
20
|
+
{ id: "mission", template: "landing-page:mission", content: {} },
|
|
21
|
+
{
|
|
22
|
+
id: "ecosystem",
|
|
23
|
+
template: "landing-page:ecosystem",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
import type { AnswerContent } from "./schema";
|
|
4
|
+
import {
|
|
5
|
+
Badge,
|
|
6
|
+
Divider,
|
|
7
|
+
Section,
|
|
8
|
+
renderHighlightedText,
|
|
9
|
+
} from "@rizom/site-rizom";
|
|
10
|
+
import { ScalesDiagram } from "./scales-diagram";
|
|
11
|
+
|
|
12
|
+
const HIGHLIGHT_CLS = "italic text-accent font-normal";
|
|
13
|
+
|
|
14
|
+
export const AnswerLayout = ({
|
|
15
|
+
badge,
|
|
16
|
+
headline,
|
|
17
|
+
subhead,
|
|
18
|
+
scalesHeadline,
|
|
19
|
+
scalesSubhead,
|
|
20
|
+
}: AnswerContent): JSX.Element => {
|
|
21
|
+
return (
|
|
22
|
+
<Section id="answer" className="reveal text-center py-section">
|
|
23
|
+
<Badge className="mb-7">{badge}</Badge>
|
|
24
|
+
<h2 className="font-display font-normal text-display-md max-w-[900px] mx-auto mb-6 mt-7">
|
|
25
|
+
{renderHighlightedText(headline, HIGHLIGHT_CLS)}
|
|
26
|
+
</h2>
|
|
27
|
+
<p className="text-body-md md:text-body-xl text-theme-muted max-w-[640px] mx-auto">
|
|
28
|
+
{subhead}
|
|
29
|
+
</p>
|
|
30
|
+
<Divider className="my-10 md:my-12" />
|
|
31
|
+
<div className="font-display font-normal text-display-sm mb-3.5 md:mb-4">
|
|
32
|
+
{scalesHeadline}
|
|
33
|
+
</div>
|
|
34
|
+
<ScalesDiagram />
|
|
35
|
+
<p className="text-body-xs md:text-body-md text-theme-light max-w-[600px] mx-auto">
|
|
36
|
+
{scalesSubhead}
|
|
37
|
+
</p>
|
|
38
|
+
</Section>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Three-layer scales diagram — renders the "personal → team → network"
|
|
6
|
+
* claim by giving each stage its own structural visual:
|
|
7
|
+
*
|
|
8
|
+
* You → a node inside two concentric rings (a lone agent)
|
|
9
|
+
* Team → a hub with four satellites connected by spokes
|
|
10
|
+
* Network → a 7-node hex mesh with no center, triangulated +
|
|
11
|
+
* cross-linked (peer-to-peer)
|
|
12
|
+
*
|
|
13
|
+
* Each stage *shows* its structure, not just its scale. All three
|
|
14
|
+
* visualizations share a horizontal baseline (BAND_CENTER) and the
|
|
15
|
+
* labels/descriptions all anchor to the same two Y-values so the
|
|
16
|
+
* typographic row below the graphics is straight regardless of which
|
|
17
|
+
* stage is tallest.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const LABEL_CLASS =
|
|
21
|
+
"fill-accent [font-family:var(--font-label)] text-[11px] font-semibold uppercase tracking-[0.22em]";
|
|
22
|
+
const DESC_CLASS =
|
|
23
|
+
"fill-[var(--color-text-muted)] [font-family:var(--font-body)] text-[12px]";
|
|
24
|
+
const CONNECTOR_CLASS = "stroke-accent";
|
|
25
|
+
const NODE_CLASS = "fill-accent";
|
|
26
|
+
const RING_CLASS = "stroke-accent";
|
|
27
|
+
|
|
28
|
+
const BAND_CENTER = 65;
|
|
29
|
+
const LABEL_Y = 135;
|
|
30
|
+
const DESC_Y = 158;
|
|
31
|
+
|
|
32
|
+
export const ScalesDiagram = ({
|
|
33
|
+
className,
|
|
34
|
+
showLabels = true,
|
|
35
|
+
decorative = false,
|
|
36
|
+
}: {
|
|
37
|
+
className?: string;
|
|
38
|
+
showLabels?: boolean;
|
|
39
|
+
decorative?: boolean;
|
|
40
|
+
} = {}): JSX.Element => {
|
|
41
|
+
const colX = { you: 110, team: 340, network: 570 };
|
|
42
|
+
|
|
43
|
+
// Stage 2 — Team: one hub + four satellites on a rotated square
|
|
44
|
+
const teamRadius = 24;
|
|
45
|
+
const teamSatellites = [
|
|
46
|
+
{ cx: colX.team - teamRadius, cy: BAND_CENTER - teamRadius },
|
|
47
|
+
{ cx: colX.team + teamRadius, cy: BAND_CENTER - teamRadius },
|
|
48
|
+
{ cx: colX.team + teamRadius, cy: BAND_CENTER + teamRadius },
|
|
49
|
+
{ cx: colX.team - teamRadius, cy: BAND_CENTER + teamRadius },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Stage 3 — Network: 7 nodes in a hexagonal mesh (no single center).
|
|
53
|
+
// Hex perimeter + one interior node to seed cross-connections. Sized
|
|
54
|
+
// so the vertical extent stays close to the team's — growth reads as
|
|
55
|
+
// connective, not oversized.
|
|
56
|
+
const netRadius = 32;
|
|
57
|
+
const netHalf = netRadius * 0.87; // hex side-to-side (cos 30°)
|
|
58
|
+
const netMidY = BAND_CENTER;
|
|
59
|
+
const net = [
|
|
60
|
+
{ cx: colX.network, cy: netMidY - netRadius }, // 0 top
|
|
61
|
+
{ cx: colX.network + netHalf, cy: netMidY - netRadius / 2 }, // 1 upper right
|
|
62
|
+
{ cx: colX.network + netHalf, cy: netMidY + netRadius / 2 }, // 2 lower right
|
|
63
|
+
{ cx: colX.network, cy: netMidY + netRadius }, // 3 bottom
|
|
64
|
+
{ cx: colX.network - netHalf, cy: netMidY + netRadius / 2 }, // 4 lower left
|
|
65
|
+
{ cx: colX.network - netHalf, cy: netMidY - netRadius / 2 }, // 5 upper left
|
|
66
|
+
{ cx: colX.network, cy: netMidY }, // 6 interior seed
|
|
67
|
+
];
|
|
68
|
+
const netEdges: Array<[number, number]> = [
|
|
69
|
+
[0, 1],
|
|
70
|
+
[1, 2],
|
|
71
|
+
[2, 3],
|
|
72
|
+
[3, 4],
|
|
73
|
+
[4, 5],
|
|
74
|
+
[5, 0], // hexagon perimeter
|
|
75
|
+
[0, 6],
|
|
76
|
+
[2, 6],
|
|
77
|
+
[4, 6], // interior triangulation
|
|
78
|
+
[1, 4],
|
|
79
|
+
[5, 2], // long-range cross-links
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<svg
|
|
84
|
+
viewBox="0 0 680 180"
|
|
85
|
+
className={`mx-auto my-8 md:my-10 block w-full max-w-[600px] md:max-w-[680px]${className ? ` ${className}` : ""}`}
|
|
86
|
+
role={decorative ? undefined : "img"}
|
|
87
|
+
aria-hidden={decorative ? true : undefined}
|
|
88
|
+
aria-label={
|
|
89
|
+
decorative
|
|
90
|
+
? undefined
|
|
91
|
+
: "Three layers of intelligence: personal brain, team, distributed network"
|
|
92
|
+
}
|
|
93
|
+
>
|
|
94
|
+
{/* Subtle rails between stages — continuity cue, not decoration */}
|
|
95
|
+
<line
|
|
96
|
+
x1="140"
|
|
97
|
+
y1={BAND_CENTER}
|
|
98
|
+
x2="304"
|
|
99
|
+
y2={BAND_CENTER}
|
|
100
|
+
className={CONNECTOR_CLASS}
|
|
101
|
+
strokeWidth="1"
|
|
102
|
+
opacity="0.22"
|
|
103
|
+
/>
|
|
104
|
+
<line
|
|
105
|
+
x1="378"
|
|
106
|
+
y1={BAND_CENTER}
|
|
107
|
+
x2="534"
|
|
108
|
+
y2={BAND_CENTER}
|
|
109
|
+
className={CONNECTOR_CLASS}
|
|
110
|
+
strokeWidth="1"
|
|
111
|
+
opacity="0.22"
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
{/* Stage 1 — You */}
|
|
115
|
+
<g>
|
|
116
|
+
<circle
|
|
117
|
+
cx={colX.you}
|
|
118
|
+
cy={BAND_CENTER}
|
|
119
|
+
r="26"
|
|
120
|
+
fill="none"
|
|
121
|
+
className={RING_CLASS}
|
|
122
|
+
strokeWidth="1.25"
|
|
123
|
+
opacity="0.4"
|
|
124
|
+
/>
|
|
125
|
+
<circle
|
|
126
|
+
cx={colX.you}
|
|
127
|
+
cy={BAND_CENTER}
|
|
128
|
+
r="16"
|
|
129
|
+
fill="none"
|
|
130
|
+
className={RING_CLASS}
|
|
131
|
+
strokeWidth="1"
|
|
132
|
+
opacity="0.65"
|
|
133
|
+
/>
|
|
134
|
+
<circle cx={colX.you} cy={BAND_CENTER} r="7" className={NODE_CLASS} />
|
|
135
|
+
{showLabels ? (
|
|
136
|
+
<>
|
|
137
|
+
<text
|
|
138
|
+
x={colX.you}
|
|
139
|
+
y={LABEL_Y}
|
|
140
|
+
textAnchor="middle"
|
|
141
|
+
className={LABEL_CLASS}
|
|
142
|
+
>
|
|
143
|
+
You
|
|
144
|
+
</text>
|
|
145
|
+
<text
|
|
146
|
+
x={colX.you}
|
|
147
|
+
y={DESC_Y}
|
|
148
|
+
textAnchor="middle"
|
|
149
|
+
className={DESC_CLASS}
|
|
150
|
+
>
|
|
151
|
+
Personal brain
|
|
152
|
+
</text>
|
|
153
|
+
</>
|
|
154
|
+
) : null}
|
|
155
|
+
</g>
|
|
156
|
+
|
|
157
|
+
{/* Stage 2 — Team */}
|
|
158
|
+
<g>
|
|
159
|
+
{teamSatellites.map((sat) => (
|
|
160
|
+
<line
|
|
161
|
+
key={`spoke-${sat.cx}-${sat.cy}`}
|
|
162
|
+
x1={colX.team}
|
|
163
|
+
y1={BAND_CENTER}
|
|
164
|
+
x2={sat.cx}
|
|
165
|
+
y2={sat.cy}
|
|
166
|
+
className={CONNECTOR_CLASS}
|
|
167
|
+
strokeWidth="1"
|
|
168
|
+
opacity="0.55"
|
|
169
|
+
/>
|
|
170
|
+
))}
|
|
171
|
+
<circle cx={colX.team} cy={BAND_CENTER} r="6" className={NODE_CLASS} />
|
|
172
|
+
{teamSatellites.map((sat) => (
|
|
173
|
+
<circle
|
|
174
|
+
key={`sat-${sat.cx}-${sat.cy}`}
|
|
175
|
+
cx={sat.cx}
|
|
176
|
+
cy={sat.cy}
|
|
177
|
+
r="4.5"
|
|
178
|
+
className={NODE_CLASS}
|
|
179
|
+
/>
|
|
180
|
+
))}
|
|
181
|
+
{showLabels ? (
|
|
182
|
+
<>
|
|
183
|
+
<text
|
|
184
|
+
x={colX.team}
|
|
185
|
+
y={LABEL_Y}
|
|
186
|
+
textAnchor="middle"
|
|
187
|
+
className={LABEL_CLASS}
|
|
188
|
+
>
|
|
189
|
+
Team
|
|
190
|
+
</text>
|
|
191
|
+
<text
|
|
192
|
+
x={colX.team}
|
|
193
|
+
y={DESC_Y}
|
|
194
|
+
textAnchor="middle"
|
|
195
|
+
className={DESC_CLASS}
|
|
196
|
+
>
|
|
197
|
+
Shared intelligence
|
|
198
|
+
</text>
|
|
199
|
+
</>
|
|
200
|
+
) : null}
|
|
201
|
+
</g>
|
|
202
|
+
|
|
203
|
+
{/* Stage 3 — Network */}
|
|
204
|
+
<g>
|
|
205
|
+
{netEdges.map(([a, b]) => {
|
|
206
|
+
const pa = net[a];
|
|
207
|
+
const pb = net[b];
|
|
208
|
+
if (!pa || !pb) return null;
|
|
209
|
+
return (
|
|
210
|
+
<line
|
|
211
|
+
key={`edge-${a}-${b}`}
|
|
212
|
+
x1={pa.cx}
|
|
213
|
+
y1={pa.cy}
|
|
214
|
+
x2={pb.cx}
|
|
215
|
+
y2={pb.cy}
|
|
216
|
+
className={CONNECTOR_CLASS}
|
|
217
|
+
strokeWidth="0.9"
|
|
218
|
+
opacity="0.45"
|
|
219
|
+
/>
|
|
220
|
+
);
|
|
221
|
+
})}
|
|
222
|
+
{net.map((node, idx) => (
|
|
223
|
+
<circle
|
|
224
|
+
key={`node-${idx}`}
|
|
225
|
+
cx={node.cx}
|
|
226
|
+
cy={node.cy}
|
|
227
|
+
r={idx === 6 ? "5" : "4.5"}
|
|
228
|
+
className={NODE_CLASS}
|
|
229
|
+
/>
|
|
230
|
+
))}
|
|
231
|
+
{showLabels ? (
|
|
232
|
+
<>
|
|
233
|
+
<text
|
|
234
|
+
x={colX.network}
|
|
235
|
+
y={LABEL_Y}
|
|
236
|
+
textAnchor="middle"
|
|
237
|
+
className={LABEL_CLASS}
|
|
238
|
+
>
|
|
239
|
+
Network
|
|
240
|
+
</text>
|
|
241
|
+
<text
|
|
242
|
+
x={colX.network}
|
|
243
|
+
y={DESC_Y}
|
|
244
|
+
textAnchor="middle"
|
|
245
|
+
className={DESC_CLASS}
|
|
246
|
+
>
|
|
247
|
+
Distributed expertise
|
|
248
|
+
</text>
|
|
249
|
+
</>
|
|
250
|
+
) : null}
|
|
251
|
+
</g>
|
|
252
|
+
</svg>
|
|
253
|
+
);
|
|
254
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
import type { HeroContent } from "./schema";
|
|
4
|
+
import { Button, Section, renderHighlightedText } from "@rizom/site-rizom";
|
|
5
|
+
|
|
6
|
+
const HIGHLIGHT_CLS = "italic text-accent font-normal";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hero section — full-viewport intro with animated rise-in headline,
|
|
10
|
+
* subhead, and CTA row. All copy is content-driven via app-owned
|
|
11
|
+
* site-content definitions; there are no hardcoded fallbacks.
|
|
12
|
+
* Instances ship their own copy in brain-data/site-content/home/hero.md.
|
|
13
|
+
*/
|
|
14
|
+
export const HeroLayout = ({
|
|
15
|
+
headline,
|
|
16
|
+
subhead,
|
|
17
|
+
primaryCtaLabel,
|
|
18
|
+
primaryCtaHref,
|
|
19
|
+
secondaryCtaLabel,
|
|
20
|
+
secondaryCtaHref,
|
|
21
|
+
}: HeroContent): JSX.Element => {
|
|
22
|
+
return (
|
|
23
|
+
<Section
|
|
24
|
+
id="hero"
|
|
25
|
+
className="flex items-center overflow-hidden min-h-[100dvh]"
|
|
26
|
+
>
|
|
27
|
+
<div className="relative z-[2] w-full md:w-[55%] pt-0 md:pt-20">
|
|
28
|
+
<h1 className="font-display font-normal text-[38px] tracking-[-1.5px] leading-[1.05] md:text-display-lg mb-6 opacity-0 animate-hero-rise [animation-delay:0.2s]">
|
|
29
|
+
{renderHighlightedText(headline, HIGHLIGHT_CLS)}
|
|
30
|
+
</h1>
|
|
31
|
+
<p className="font-body text-body-md md:text-body-lg text-theme-muted max-w-full md:max-w-[480px] mb-9 md:mb-10 opacity-0 animate-hero-rise [animation-delay:0.4s]">
|
|
32
|
+
{subhead}
|
|
33
|
+
</p>
|
|
34
|
+
<div className="flex flex-col md:flex-row gap-3 md:gap-4 md:flex-wrap opacity-0 animate-hero-rise [animation-delay:0.6s]">
|
|
35
|
+
<Button href={primaryCtaHref} variant="primary" block>
|
|
36
|
+
{primaryCtaLabel}
|
|
37
|
+
</Button>
|
|
38
|
+
<Button href={secondaryCtaHref} variant="secondary" block>
|
|
39
|
+
{secondaryCtaLabel}
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</Section>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime schema/formatter for hero now live in `src/site-content.ts`.
|
|
3
|
+
* Keep the props type local to the layout so app code does not depend on
|
|
4
|
+
* low-level template authoring primitives here.
|
|
5
|
+
*/
|
|
6
|
+
export interface HeroContent {
|
|
7
|
+
headline: string;
|
|
8
|
+
subhead: string;
|
|
9
|
+
primaryCtaLabel: string;
|
|
10
|
+
primaryCtaHref: string;
|
|
11
|
+
secondaryCtaLabel: string;
|
|
12
|
+
secondaryCtaHref: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
import type { MissionContent } from "./schema";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Divider,
|
|
7
|
+
Section,
|
|
8
|
+
renderHighlightedText,
|
|
9
|
+
} from "@rizom/site-rizom";
|
|
10
|
+
|
|
11
|
+
const HIGHLIGHT_CLS = "italic text-accent font-normal";
|
|
12
|
+
|
|
13
|
+
export const MissionLayout = ({
|
|
14
|
+
preamble,
|
|
15
|
+
headline,
|
|
16
|
+
post,
|
|
17
|
+
primaryCtaLabel,
|
|
18
|
+
primaryCtaHref,
|
|
19
|
+
secondaryCtaLabel,
|
|
20
|
+
secondaryCtaHref,
|
|
21
|
+
}: MissionContent): JSX.Element => {
|
|
22
|
+
return (
|
|
23
|
+
<Section id="mission" className="reveal py-section text-center">
|
|
24
|
+
<Divider className="mb-10 md:mb-12" />
|
|
25
|
+
<p className="font-body text-body-sm md:text-body-lg text-theme-light max-w-[520px] mx-auto mb-8 md:mb-10">
|
|
26
|
+
{preamble}
|
|
27
|
+
</p>
|
|
28
|
+
<h2 className="font-display font-normal text-display-xl">
|
|
29
|
+
{renderHighlightedText(headline, HIGHLIGHT_CLS)}
|
|
30
|
+
</h2>
|
|
31
|
+
<p className="font-body text-body-sm md:text-body-lg text-theme-light max-w-[500px] mx-auto mt-8">
|
|
32
|
+
{post}
|
|
33
|
+
</p>
|
|
34
|
+
<div className="flex flex-col md:flex-row gap-3 md:gap-5 md:justify-center items-stretch md:items-center mt-9 md:mt-16">
|
|
35
|
+
<Button href={primaryCtaHref} variant="primary-strong" size="lg" block>
|
|
36
|
+
{primaryCtaLabel}
|
|
37
|
+
</Button>
|
|
38
|
+
<Button href={secondaryCtaHref} variant="secondary" size="lg" block>
|
|
39
|
+
{secondaryCtaLabel}
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</Section>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { JSX } from "preact";
|
|
3
|
+
import type { OwnershipContent } from "./schema";
|
|
4
|
+
import { Badge, Section, renderHighlightedText } from "@rizom/site-rizom";
|
|
5
|
+
|
|
6
|
+
const HIGHLIGHT_CLS = "italic text-accent font-normal";
|
|
7
|
+
|
|
8
|
+
export const OwnershipLayout = ({
|
|
9
|
+
badge,
|
|
10
|
+
headline,
|
|
11
|
+
features,
|
|
12
|
+
}: OwnershipContent): JSX.Element => {
|
|
13
|
+
return (
|
|
14
|
+
<Section id="ownership" className="reveal py-section">
|
|
15
|
+
<div className="flex flex-col items-start gap-9 md:flex-row md:gap-20">
|
|
16
|
+
<div className="w-full md:w-[45%]">
|
|
17
|
+
<Badge>{badge}</Badge>
|
|
18
|
+
<h2 className="font-display font-normal text-[28px] tracking-[-1px] leading-[1.1] md:text-display-md mt-4 md:mt-6">
|
|
19
|
+
{renderHighlightedText(headline, HIGHLIGHT_CLS)}
|
|
20
|
+
</h2>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="flex w-full flex-col gap-8 md:w-[55%] md:pt-[60px]">
|
|
23
|
+
{features.map((row, i) => (
|
|
24
|
+
<div
|
|
25
|
+
key={row.icon + row.title}
|
|
26
|
+
className={`reveal reveal-delay-${i + 1} flex items-start gap-4 md:gap-5`}
|
|
27
|
+
>
|
|
28
|
+
<div className="shrink-0 min-w-[44px] md:min-w-[48px] h-11 md:h-12 flex items-center justify-center border border-accent rounded-lg font-nav text-[18px] md:text-heading-md font-bold text-accent">
|
|
29
|
+
{row.icon}
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
<div className="font-nav text-heading-sm md:text-heading-md font-bold mb-1.5">
|
|
33
|
+
{row.title}
|
|
34
|
+
</div>
|
|
35
|
+
<p className="text-body-xs md:text-body-sm text-theme-muted">
|
|
36
|
+
{row.body}
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
))}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</Section>
|
|
44
|
+
);
|
|
45
|
+
};
|