Skip to content

Commit 839db30

Browse files
committed
docs(landing): polish preview section, features layout, and titles
- Move HyperFlow Preview above Modules for clearer flow. - Add Devtools cards with icon-and-label headers, doc links, and richer mini visuals (network log with badges and timing bars, queue chips, sparkline gradient). - Tier 2 features: cardless layout with uppercase labels and tag pills; Tier 1 BigFeatureCard optional tags. - Fix Title word spacing on Big/Medium/Small blocks (gap-x on inline-flex word spans). - CLI demo closing line: Ship it → Just use it. Made-with: Cursor
1 parent bfb63d1 commit 839db30

8 files changed

Lines changed: 110 additions & 55 deletions

File tree

documentation/src/components/landing/blocks/big-block/big-block.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ export const BigBlock = ({ title, description, img }: { title: string; descripti
5252
<div>
5353
<Title
5454
size="none"
55-
wrapperClass="inline-flex flex-wrap font-bold pb-1"
56-
className="!text-4xl !leading-tight"
55+
wrapperClass="inline-flex flex-wrap gap-x-3 font-bold pb-1"
56+
className="!text-4xl !leading-tight font-extrabold"
5757
>
5858
{title}
5959
</Title>

documentation/src/components/landing/blocks/medium-block/medium-block.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const MediumBlock = ({
3131
<div className="grid grid-cols-1 md:grid-cols-[3fr_1fr] h-full">
3232
<div className="flex flex-col justify-between md:max-w-[480px] shrink-0 order-1 md:order-none px-6 py-4 md:px-8 md:py-4 h-full">
3333
<div className="mt-4 flex-1">
34-
<Title size="none" wrapperClass="inline-flex flex-wrap font-bold pb-1" className="text-2xl">
34+
<Title size="none" wrapperClass="inline-flex flex-wrap gap-x-2 font-bold pb-1" className="text-2xl">
3535
{title}
3636
</Title>
3737
<Description size="none" className="text-zinc-400">

documentation/src/components/landing/blocks/small-block/small-block.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const SmallBlock = ({
4646
<div className="flex flex-col md:max-w-[480px] shrink-0 order-1 md:order-none px-6 py-4 md:px-8 md:py-6 h-full">
4747
<div className="flex flex-col h-full">
4848
<div className="size-12 bg-yellow-500/10 rounded-lg flex items-center justify-center mb-4">{icon}</div>
49-
<Title size="none" wrapperClass="inline-flex flex-wrap font-bold pb-1" className="text-2xl">
49+
<Title size="none" wrapperClass="inline-flex flex-wrap gap-x-2 font-bold pb-1" className="text-2xl">
5050
{title}
5151
</Title>
5252
<Description size="none" className="text-zinc-400 text-lg !mt-1 !mb-2 flex-1">

documentation/src/components/landing/features/cli-sdk-demo.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function CliSdkDemo({ bare = false }: { bare?: boolean } = {}) {
3434
{"."}
3535
</AnimatedSpan>
3636

37-
<AnimatedSpan className="!text-blue-400">🚀 Ship it.</AnimatedSpan>
37+
<AnimatedSpan className="!text-blue-400">🚀 Just use it.</AnimatedSpan>
3838
</Terminal>
3939
);
4040

documentation/src/components/landing/features/features.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const tier2ItemVariants = {
3434

3535
interface InlineFeature {
3636
icon: React.ElementType;
37+
label: string;
3738
title: string;
3839
description: string;
3940
tags: string[];
@@ -42,36 +43,42 @@ interface InlineFeature {
4243
const inlineFeatures: InlineFeature[] = [
4344
{
4445
icon: Shield,
46+
label: "Type safety",
4547
title: "End-to-end TypeScript",
4648
description: "Params inferred from URL strings. Typed responses, payloads, query params, errors. Zero any.",
4749
tags: ["URL params", "Responses", "Payloads", "Query", "Errors"],
4850
},
4951
{
5052
icon: Code2,
53+
label: "React",
5154
title: "React hooks built in",
5255
description: "useFetch for queries. useSubmit for mutations. Loading, error, and data states all managed for you.",
5356
tags: ["useFetch", "useSubmit", "loading", "error", "data"],
5457
},
5558
{
5659
icon: Activity,
60+
label: "Devtools",
5761
title: "HyperFlow DevTools",
5862
description: "Inspect every request, cache entry, queue, and event. Debug your data layer visually.",
5963
tags: ["Network", "Cache", "Queues", "Events"],
6064
},
6165
{
6266
icon: Globe,
67+
label: "Runtimes",
6368
title: "Runs everywhere",
6469
description: "Browser, Node, edge, mobile, SSR. Same client, same behavior, every runtime.",
6570
tags: ["Browser", "Node", "Edge", "Mobile", "SSR"],
6671
},
6772
{
6873
icon: Zap,
74+
label: "Mutations",
6975
title: "Optimistic updates",
7076
description: "Mutate the UI first, reconcile with the server. Smooth, race-condition-free.",
7177
tags: ["Mutate first", "Reconcile", "Race-safe", "Rollback"],
7278
},
7379
{
7480
icon: Layers3,
81+
label: "Performance",
7582
title: "Smart deduplication",
7683
description: "Five components ask for the same data. One network call fires. Automatic.",
7784
tags: ["Shared promise", "One request", "Auto"],
@@ -199,10 +206,11 @@ export function Features(): React.JSX.Element {
199206
variants={tier2ItemVariants}
200207
className="group relative flex h-full flex-col"
201208
>
202-
<div className="flex size-10 items-center justify-center rounded-lg bg-yellow-500/[0.08]">
203-
<feature.icon className="size-5 text-yellow-500" />
204-
</div>
205-
<h4 className="mt-4 text-lg font-semibold tracking-tight text-zinc-100">{feature.title}</h4>
209+
<span className="inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-widest text-zinc-500">
210+
<feature.icon className="size-3.5" />
211+
{feature.label}
212+
</span>
213+
<h4 className="mt-2 text-xl font-extrabold tracking-tight text-zinc-100">{feature.title}</h4>
206214
<p className="mt-2 text-[15px] leading-relaxed text-zinc-400">{feature.description}</p>
207215
<div className="mt-auto flex flex-wrap gap-1.5 pt-5">
208216
{feature.tags.map((tag) => (

documentation/src/components/landing/landing.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import { useState } from "react";
21
import { useDidMount } from "@better-hooks/lifecycle";
32
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
4-
import Layout from "@theme/Layout";
53
import { useWindowEvent } from "@site/src/hooks/use-window-event";
4+
import Layout from "@theme/Layout";
5+
import { useState } from "react";
66

7-
import { Hero } from "./hero";
8-
import { Clients } from "./clients";
7+
import { Cookies } from "../cookies/cookies";
8+
import { About } from "./about/about";
99
import { Blocks } from "./blocks";
1010
import { CallToAction } from "./call-to-action";
11-
import { Modules } from "./modules/modules";
11+
import { Clients } from "./clients";
12+
import { CodePreview } from "./code/code";
1213
// import { Integrations } from "./integrations/integrations";
1314
import { Features } from "./features/features";
15+
import { Hero } from "./hero";
16+
import { Modules } from "./modules/modules";
1417
// import { Example } from "./example/example";
1518
import { Preview } from "./preview/preview";
1619
import { Sponsors } from "./sponsors/sponsors";
17-
import { About } from "./about/about";
18-
import { Cookies } from "../cookies/cookies";
19-
import { CodePreview } from "./code/code";
2020

2121
export const Landing = () => {
2222
const { siteConfig } = useDocusaurusContext();
@@ -47,10 +47,10 @@ export const Landing = () => {
4747
<Clients />
4848
<About />
4949
<Features />
50+
<Preview />
5051
<Modules />
5152
<Blocks />
5253
{/* <Integrations /> */}
53-
<Preview />
5454
{/* <Example /> */}
5555
<Sponsors />
5656
<CallToAction />

documentation/src/components/landing/preview/devtools-visuals.tsx

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import React, { Fragment } from "react";
22

3-
/* ─── Network Inspector — mini request log ───────────────────────── */
3+
/* ─── Network Inspector — request log with timing bars ───────────── */
44

55
interface LogRow {
66
method: "GET" | "POST" | "PUT" | "DELETE";
77
path: string;
88
status: number;
9-
time: string;
9+
time: number;
1010
}
1111

1212
const networkLog: LogRow[] = [
13-
{ method: "GET", path: "/users", status: 200, time: "142ms" },
14-
{ method: "POST", path: "/users/42", status: 201, time: "89ms" },
15-
{ method: "GET", path: "/posts/12", status: 304, time: "12ms" },
13+
{ method: "GET", path: "/users", status: 200, time: 142 },
14+
{ method: "POST", path: "/users/42", status: 201, time: 89 },
15+
{ method: "GET", path: "/posts/12", status: 304, time: 12 },
1616
];
1717

18-
const methodTones: Record<LogRow["method"], string> = {
19-
GET: "text-emerald-300",
20-
POST: "text-violet-300",
21-
PUT: "text-amber-300",
22-
DELETE: "text-rose-300",
18+
const methodBadgeTones: Record<LogRow["method"], string> = {
19+
GET: "border-emerald-400/30 bg-emerald-400/[0.08] text-emerald-300",
20+
POST: "border-violet-400/30 bg-violet-400/[0.08] text-violet-300",
21+
PUT: "border-amber-400/30 bg-amber-400/[0.08] text-amber-300",
22+
DELETE: "border-rose-400/30 bg-rose-400/[0.08] text-rose-300",
2323
};
2424

2525
function statusTone(status: number) {
@@ -29,17 +29,37 @@ function statusTone(status: number) {
2929
return "text-emerald-300";
3030
}
3131

32+
function timingBarTone(time: number) {
33+
if (time > 150) return "bg-amber-400/70";
34+
if (time > 60) return "bg-emerald-400/70";
35+
return "bg-sky-400/70";
36+
}
37+
38+
const TIMING_CAP = 180;
39+
3240
export function NetworkLogVisual() {
3341
return (
34-
<div className="grid grid-cols-[auto_1fr_auto_auto] items-center gap-x-3 gap-y-1 font-mono text-[11px] leading-none">
35-
{networkLog.map((row) => (
36-
<Fragment key={`${row.method}-${row.path}`}>
37-
<span className={`whitespace-nowrap font-semibold ${methodTones[row.method]}`}>{row.method}</span>
38-
<span className="min-w-0 truncate text-zinc-300">{row.path}</span>
39-
<span className={`whitespace-nowrap tabular-nums ${statusTone(row.status)}`}>{row.status}</span>
40-
<span className="whitespace-nowrap tabular-nums text-zinc-500">{row.time}</span>
41-
</Fragment>
42-
))}
42+
<div className="grid grid-cols-[auto_1fr_auto_auto_auto] items-center gap-x-2.5 gap-y-2 font-mono text-[11px] leading-none">
43+
{networkLog.map((row) => {
44+
const widthPct = Math.min(100, (row.time / TIMING_CAP) * 100);
45+
return (
46+
<Fragment key={`${row.method}-${row.path}`}>
47+
<span
48+
className={`whitespace-nowrap rounded border px-1.5 py-1 text-[10px] font-bold uppercase leading-none ${methodBadgeTones[row.method]}`}
49+
>
50+
{row.method}
51+
</span>
52+
<span className="min-w-0 truncate text-zinc-300">{row.path}</span>
53+
<span className={`whitespace-nowrap tabular-nums font-semibold ${statusTone(row.status)}`}>
54+
{row.status}
55+
</span>
56+
<div className="h-1 w-14 overflow-hidden rounded-full bg-white/[0.06]">
57+
<div style={{ width: `${widthPct}%` }} className={`h-full rounded-full ${timingBarTone(row.time)}`} />
58+
</div>
59+
<span className="whitespace-nowrap tabular-nums text-zinc-500">{row.time}ms</span>
60+
</Fragment>
61+
);
62+
})}
4363
</div>
4464
);
4565
}
@@ -71,37 +91,60 @@ export function CacheHitRateVisual() {
7191
);
7292
}
7393

74-
/* ─── Queue Manager — flow rows ──────────────────────────────────── */
94+
/* ─── Queue Manager — chip rows ──────────────────────────────────── */
7595

7696
interface QueueRow {
7797
label: string;
7898
count: number;
79-
dots: number;
99+
chips: number;
100+
chipClass: string;
80101
dotClass: string;
81102
pulseAt?: number;
82103
}
83104

84105
const queueRows: QueueRow[] = [
85-
{ label: "In-flight", count: 2, dots: 2, dotClass: "bg-amber-400", pulseAt: 1 },
86-
{ label: "Pending", count: 5, dots: 5, dotClass: "bg-white/20" },
87-
{ label: "Done", count: 128, dots: 8, dotClass: "bg-emerald-400/50" },
106+
{
107+
label: "In-flight",
108+
count: 2,
109+
chips: 2,
110+
chipClass: "bg-gradient-to-b from-amber-400 to-amber-500 shadow-[0_0_6px_rgba(251,191,36,0.45)]",
111+
dotClass: "bg-amber-400",
112+
pulseAt: 1,
113+
},
114+
{
115+
label: "Pending",
116+
count: 5,
117+
chips: 5,
118+
chipClass: "bg-white/[0.04] border border-white/[0.12]",
119+
dotClass: "bg-white/30",
120+
},
121+
{
122+
label: "Done",
123+
count: 128,
124+
chips: 8,
125+
chipClass: "bg-gradient-to-b from-emerald-500/50 to-emerald-600/40",
126+
dotClass: "bg-emerald-400/70",
127+
},
88128
];
89129

90130
export function QueueFlowVisual() {
91131
return (
92-
<div className="grid grid-cols-[auto_1fr_auto] items-center gap-x-3 gap-y-1.5 font-mono text-[11px] leading-none">
132+
<div className="grid grid-cols-[auto_1fr_auto] items-center gap-x-6 gap-y-4 font-mono text-[11px] leading-none">
93133
{queueRows.map((row) => (
94134
<Fragment key={row.label}>
95-
<span className="whitespace-nowrap text-zinc-500">{row.label}</span>
135+
<span className="inline-flex items-center gap-2 whitespace-nowrap text-zinc-400">
136+
<span className={`size-1.5 rounded-full ${row.dotClass}`} />
137+
{row.label}
138+
</span>
96139
<div className="flex gap-1">
97-
{Array.from({ length: row.dots }).map((_, i) => (
140+
{Array.from({ length: row.chips }).map((_, i) => (
98141
<span
99142
key={`${row.label}-${i.toString()}`}
100-
className={`size-1.5 rounded-full ${row.dotClass} ${row.pulseAt === i ? "animate-pulse" : ""}`}
143+
className={`h-3 w-3.5 rounded-[3px] ${row.chipClass} ${row.pulseAt === i ? "animate-pulse" : ""}`}
101144
/>
102145
))}
103146
</div>
104-
<span className="whitespace-nowrap tabular-nums text-zinc-500">{row.count}</span>
147+
<span className="whitespace-nowrap tabular-nums text-zinc-400">{row.count}</span>
105148
</Fragment>
106149
))}
107150
</div>

documentation/src/components/landing/preview/preview.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { CacheHitRateVisual, MetricsSparklineVisual, NetworkLogVisual, QueueFlow
1212

1313
interface DevtoolsFeature {
1414
icon: React.ElementType;
15+
label: string;
1516
title: string;
1617
description: string;
1718
link: string;
@@ -21,27 +22,31 @@ interface DevtoolsFeature {
2122
const devtoolsFeatures: DevtoolsFeature[] = [
2223
{
2324
icon: Network,
25+
label: "Network",
2426
title: "Network Inspector",
2527
description: "Stream every request as it fires. Headers, payload, response, and per-phase timings.",
2628
link: "/docs/hyper-flow/features/network",
2729
visual: <NetworkLogVisual />,
2830
},
2931
{
3032
icon: Database,
33+
label: "Cache",
3134
title: "Cache Inspector",
3235
description: "Browse cached entries with hit rates, size, and last update. Drill into any key to debug stale data.",
3336
link: "/docs/hyper-flow/features/cache",
3437
visual: <CacheHitRateVisual />,
3538
},
3639
{
3740
icon: Workflow,
41+
label: "Queues",
3842
title: "Queue Manager",
3943
description: "Live view of every queue. Track pending, in-flight, and stuck requests across your app.",
4044
link: "/docs/hyper-flow/features/queues",
4145
visual: <QueueFlowVisual />,
4246
},
4347
{
4448
icon: Gauge,
49+
label: "Metrics",
4550
title: "Performance Dashboard",
4651
description:
4752
"Network, cache, and queue metrics in one view. Success rates, hit ratios, throughput, slow endpoints.",
@@ -129,7 +134,7 @@ export function Preview(): React.JSX.Element {
129134
</section>
130135

131136
{/* Feature cards — emerge from the dashboard fade */}
132-
<div className="relative z-10 max-w-6xl mx-auto px-4 mt-20 md:mt-40 mb-20">
137+
<div className="relative z-10 max-w-6xl mx-auto px-4 mt-40 mb-20">
133138
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 md:gap-8">
134139
{devtoolsFeatures.map((feature, index) => (
135140
<motion.div
@@ -147,13 +152,12 @@ export function Preview(): React.JSX.Element {
147152
>
148153
<Noise visibility="medium" />
149154
<Link to={feature.link} className="!no-underline relative z-10 flex h-full flex-col">
150-
<div className="flex items-center gap-3">
151-
<div className="flex size-10 items-center justify-center rounded-lg bg-yellow-500/10">
152-
<feature.icon className="size-5 text-yellow-500" />
153-
</div>
154-
<h4 className="text-lg font-semibold tracking-tight text-zinc-100">{feature.title}</h4>
155-
</div>
156-
<p className="mt-3 text-[15px] leading-relaxed text-zinc-400">{feature.description}</p>
155+
<span className="inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-widest text-zinc-500">
156+
<feature.icon className="size-3.5" />
157+
{feature.label}
158+
</span>
159+
<h4 className="mt-2 text-2xl font-extrabold tracking-tight text-zinc-100">{feature.title}</h4>
160+
<p className="mt-2 text-[15px] leading-relaxed text-zinc-400">{feature.description}</p>
157161
<div className="mt-5">{feature.visual}</div>
158162
<span className="mt-auto inline-flex items-center gap-1 pt-5 text-xs font-medium text-zinc-500 transition-colors group-hover/card:text-zinc-300">
159163
Open in docs

0 commit comments

Comments
 (0)