Skip to content

Commit 29654b1

Browse files
Fix homepage visuals and mobile navigation (#27)
1 parent bc83ec6 commit 29654b1

5 files changed

Lines changed: 276 additions & 157 deletions

File tree

packages/components/src/header/index.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,24 @@ export function Header({
8282
? "text-zinc-900 border-zinc-200 bg-transparent hover:bg-zinc-100 hover:border-zinc-300 hover:text-zinc-900"
8383
: "text-white border-white/10 bg-transparent hover:bg-white/5 hover:border-white/20 hover:text-white"
8484
)}
85+
data-mobile-menu-trigger=""
8586
>
8687
<Icon icon={faBars} className="size-5" />
8788
<span className="sr-only">
8889
Toggle navigation menu
8990
</span>
9091
</Button>
9192
</SheetTrigger>
92-
<SheetContent side="left" className={cn("overflow-auto p-0 [&>button]:fixed [&>button]:left-[calc(100vw-4rem)] [&>button]:top-4 [&>button]:bg-black/80 [&>button]:backdrop-blur [&>button]:border [&>button]:border-white/10 [&>button]:shadow-lg [&>button]:text-white [&>button]:ring-offset-black [&>button]:focus:ring-white/20 [&>button]:hover:bg-white/5 [&>button]:hover:border-white/20", sheetClassName)}>
93-
<nav className="min-h-full text-lg font-medium h-full max-w-full">
93+
<SheetContent
94+
side="left"
95+
aria-label="Navigation menu"
96+
className={cn(
97+
"overflow-visible p-0 [&>button]:right-3 [&>button]:top-3 [&>button]:inline-flex [&>button]:size-10 [&>button]:items-center [&>button]:justify-center [&>button]:border [&>button]:border-white/10 [&>button]:bg-black/80 [&>button]:text-white [&>button]:shadow-lg [&>button]:backdrop-blur [&>button]:ring-offset-black [&>button]:hover:border-white/20 [&>button]:hover:bg-white/5 [&>button]:focus:ring-white/20",
98+
sheetClassName,
99+
)}
100+
>
101+
<nav className="h-full max-w-full overflow-y-auto overscroll-contain text-lg font-medium">
94102
<div className="flex flex-col min-h-full">
95-
<a
96-
href="/"
97-
className="hidden"
98-
>
99-
{logo}
100-
</a>
101103
<div className="flex flex-1 flex-col px-4 py-4 gap-2">
102104
{mobileBreadcrumbs}
103105
</div>

src/components/marketing/ProductMotif.tsx

Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,33 @@ const workflowLanes = [
2424
] as const;
2525

2626
// Both ends run 180 units off-canvas so the pulse dash (0.1 of the path,
27-
// ~161-169 units) sits fully off-screen at the loop's extremes.
28-
const workflowLanePath = (offset: number) => {
27+
// ~161-169 units) sits fully off-screen at the loop's extremes. The card keeps
28+
// the original turn positions; the hero pushes the turns out to sit inside the
29+
// wide field's visible center. The pulse dash math in main.css assumes the
30+
// card geometry, so heroes render rails only (see WorkflowMotif).
31+
const workflowLanePath = (offset: number, rightX = 262, leftX = 58) => {
2932
const rightRadius = 38 - offset;
3033
const leftRadius = 38 + offset;
3134
return [
3235
`M -180 ${48 + offset}`,
33-
"H 262",
36+
`H ${rightX}`,
3437
`a ${rightRadius} ${rightRadius} 0 0 1 0 ${rightRadius * 2}`,
35-
"H 58",
38+
`H ${leftX}`,
3639
`a ${leftRadius} ${leftRadius} 0 0 0 0 ${leftRadius * 2}`,
37-
"H 262",
40+
`H ${rightX}`,
3841
`a ${rightRadius} ${rightRadius} 0 0 1 0 ${rightRadius * 2}`,
3942
"H -180",
4043
].join(" ");
4144
};
4245

46+
// Card motifs draw one 320×400 cluster stretched over the 4/5 plate. Heroes
47+
// are wide and short, so slicing that same viewBox magnifies the artwork ~4×
48+
// and the center cut-out mask swallows it — the shapes stop reading as the
49+
// card imagery. Instead heroes repeat the cluster across a 1600×400 field so
50+
// the pattern stays at card scale, matching the Actors hero's tiled marks.
51+
const HERO_FIELD_VIEWBOX = "0 0 1600 400";
52+
const CARD_VIEWBOX = "0 0 320 400";
53+
4354
const agentOSCircles = [
4455
{ cx: 16, cy: 36, direction: "forward", tone: "bright", delay: 0 },
4556
{ cx: 96, cy: 108, direction: "backward", tone: "soft", delay: 0 },
@@ -253,7 +264,7 @@ const containerClassName = (
253264
const WorkflowMotif = ({ surface }: Pick<ProductMotifProps, "surface">) => (
254265
<svg
255266
className="h-full w-full"
256-
viewBox="0 0 320 400"
267+
viewBox={surface === "hero" ? HERO_FIELD_VIEWBOX : CARD_VIEWBOX}
257268
preserveAspectRatio={surface === "hero" ? "xMidYMid slice" : "none"}
258269
>
259270
{workflowLanes.map((lane) => (
@@ -268,16 +279,22 @@ const WorkflowMotif = ({ surface }: Pick<ProductMotifProps, "surface">) => (
268279
>
269280
<path
270281
className={`workflow-rail workflow-rail--${lane.tone}`}
271-
d={workflowLanePath(lane.offset)}
272-
pathLength="1"
273-
vectorEffect="non-scaling-stroke"
274-
/>
275-
<path
276-
className={`workflow-pulse workflow-pulse--${lane.lane}`}
277-
d={workflowLanePath(lane.offset)}
282+
d={
283+
surface === "hero"
284+
? workflowLanePath(lane.offset, 1150, 450)
285+
: workflowLanePath(lane.offset)
286+
}
278287
pathLength="1"
279288
vectorEffect="non-scaling-stroke"
280289
/>
290+
{surface === "card" && (
291+
<path
292+
className={`workflow-pulse workflow-pulse--${lane.lane}`}
293+
d={workflowLanePath(lane.offset)}
294+
pathLength="1"
295+
vectorEffect="non-scaling-stroke"
296+
/>
297+
)}
281298
</g>
282299
))}
283300
</svg>
@@ -322,48 +339,68 @@ const LifeRect = ({
322339
/>
323340
);
324341

342+
// Hero copies sit 13 columns apart: a three-column dead gap between 10-column
343+
// boards, so the frozen generation-0 frames never read as one merged board.
344+
const DYNAMIC_APPS_HERO_COLUMNS = [0, 13, 26, 39] as const;
345+
325346
const DynamicAppsMotif = ({ surface }: Pick<ProductMotifProps, "surface">) => (
326347
<svg
327348
className="h-full w-full"
328-
viewBox="0 0 320 400"
349+
viewBox={surface === "hero" ? HERO_FIELD_VIEWBOX : CARD_VIEWBOX}
329350
preserveAspectRatio={surface === "hero" ? "xMidYMid slice" : "none"}
330351
>
331-
{lifeBoardCells.map((cell) => (
332-
<LifeRect key={`${cell.col}-${cell.row}`} cell={cell} />
352+
{(surface === "hero" ? DYNAMIC_APPS_HERO_COLUMNS : [0]).map((colShift) => (
353+
<g key={colShift}>
354+
{lifeBoardCells.map((cell) => (
355+
<LifeRect
356+
key={`${cell.col}-${cell.row}`}
357+
cell={cell}
358+
colOffset={colShift}
359+
/>
360+
))}
361+
<g className="dynamic-app-glider">
362+
{gliderCells.map((cell) => (
363+
<LifeRect
364+
key={`glider-${cell.col}-${cell.row}`}
365+
cell={cell}
366+
colOffset={GLIDER_ORIGIN.col + colShift}
367+
rowOffset={GLIDER_ORIGIN.row}
368+
/>
369+
))}
370+
</g>
371+
</g>
333372
))}
334-
<g className="dynamic-app-glider">
335-
{gliderCells.map((cell) => (
336-
<LifeRect
337-
key={`glider-${cell.col}-${cell.row}`}
338-
cell={cell}
339-
colOffset={GLIDER_ORIGIN.col}
340-
rowOffset={GLIDER_ORIGIN.row}
341-
/>
342-
))}
343-
</g>
344373
</svg>
345374
);
346375

376+
// The circle lattice is periodic at 320 in x (80/72 staggered grid), so
377+
// hero copies at 320-unit steps continue the cluster seamlessly.
378+
const AGENTOS_HERO_COLUMNS = [0, 320, 640, 960, 1280] as const;
379+
347380
const AgentOSMotif = ({ surface }: Pick<ProductMotifProps, "surface">) => (
348381
<svg
349382
className="h-full w-full"
350-
viewBox="0 0 320 400"
383+
viewBox={surface === "hero" ? HERO_FIELD_VIEWBOX : CARD_VIEWBOX}
351384
preserveAspectRatio={surface === "hero" ? "xMidYMid slice" : "none"}
352385
>
353-
{agentOSCircles.map((circle) => (
354-
<circle
355-
key={`${circle.cx}-${circle.cy}`}
356-
className={`agentos-circle agentos-circle--${circle.direction} agentos-circle--${circle.tone}`}
357-
style={
358-
{
359-
"--agentos-circle-delay": `${circle.delay}ms`,
360-
} as CSSProperties
361-
}
362-
cx={circle.cx}
363-
cy={circle.cy}
364-
r="62"
365-
vectorEffect="non-scaling-stroke"
366-
/>
386+
{(surface === "hero" ? AGENTOS_HERO_COLUMNS : [0]).map((xShift) => (
387+
<g key={xShift}>
388+
{agentOSCircles.map((circle) => (
389+
<circle
390+
key={`${circle.cx}-${circle.cy}`}
391+
className={`agentos-circle agentos-circle--${circle.direction} agentos-circle--${circle.tone}`}
392+
style={
393+
{
394+
"--agentos-circle-delay": `${circle.delay}ms`,
395+
} as CSSProperties
396+
}
397+
cx={circle.cx + xShift}
398+
cy={circle.cy}
399+
r="62"
400+
vectorEffect="non-scaling-stroke"
401+
/>
402+
))}
403+
</g>
367404
))}
368405
</svg>
369406
);

0 commit comments

Comments
 (0)