-
Notifications
You must be signed in to change notification settings - Fork 0
feat(docs): add Next.js-style landing page to the docs site #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
3fc1e2b
docs: add landing page design spec
ZingerLittleBee 0c1a8f7
docs: add landing page implementation plan
ZingerLittleBee 1392c13
feat(docs): scaffold landing page with i18n and scoped dark styles
ZingerLittleBee 4e16188
feat(docs): add landing primitives — section, gradient heading, code-…
ZingerLittleBee 8f8878a
feat(docs): add landing hero with mini-dashboard animation
ZingerLittleBee 8cfc3d3
feat(docs): add trust strip and three-pillar section with animations
ZingerLittleBee 0a17e4d
feat(docs): add 8-tile bento grid with feature animations
ZingerLittleBee 9aa9652
feat(docs): add how-it-works and final CTA sections
ZingerLittleBee ff36df4
fix(docs): polish landing layout — wrap install command, richer bento…
ZingerLittleBee 00feeca
fix(docs): stream/light-band travel full width, orbit icons sit on ri…
ZingerLittleBee 038d752
fix(docs): redesign orbit-icons with dashed ring path and circular beads
ZingerLittleBee 92135d5
fix(docs): keep orbit icons upright while their centers travel along …
ZingerLittleBee ac676e1
fix(docs): prevent file-tree overflow colliding with card heading
ZingerLittleBee b85e2f9
feat(docs): hide theme switch on the dark-only landing page
ZingerLittleBee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
apps/docs/src/components/landing/animations/alert-bell.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { Bell } from 'lucide-react' | ||
|
|
||
| export function AlertBellAnim() { | ||
| const channels = ['Webhook', 'Telegram', 'Bark', 'Email', 'APNs'] | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of multi-channel alerts" | ||
| className="flex h-full flex-col items-center justify-center gap-3" | ||
| role="img" | ||
| > | ||
| <div className="relative"> | ||
| <Bell className="bell-shake h-9 w-9 text-amber-300" /> | ||
| <span className="absolute -top-0.5 -right-0.5 h-2.5 w-2.5 rounded-full bg-red-500 ring-2 ring-zinc-950" /> | ||
| </div> | ||
| <div className="flex flex-wrap justify-center gap-1.5"> | ||
| {channels.map((c, i) => ( | ||
| <span | ||
| className="fade-cycle rounded-full border border-white/10 bg-white/[0.04] px-2 py-0.5 font-mono text-[10px] text-zinc-300" | ||
| key={c} | ||
| style={{ animationDelay: `${i * 0.3}s` }} | ||
| > | ||
| {c} | ||
| </span> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
20 changes: 20 additions & 0 deletions
20
apps/docs/src/components/landing/animations/color-ring.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| export function ColorRingAnim() { | ||
| const stops = ['#ffb300', '#4cc9f0', '#22c55e', '#a855f7', '#ef4444', '#ffb300'] | ||
| const gradient = stops.map((c, i) => `${c} ${(i / (stops.length - 1)) * 360}deg`).join(', ') | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of theme customization" | ||
| className="flex h-full items-center justify-center" | ||
| role="img" | ||
| > | ||
| <div className="relative"> | ||
| <div className="orbit-anim h-28 w-28 rounded-full" style={{ background: `conic-gradient(${gradient})` }} /> | ||
| <div className="absolute inset-2 rounded-full bg-zinc-950" /> | ||
| <div className="fade-cycle absolute inset-4 rounded-full bg-amber-400 shadow-[0_0_30px_-6px_rgba(255,179,0,0.7)]" /> | ||
| <div className="absolute -bottom-1 left-1/2 -translate-x-1/2 rounded-full bg-zinc-900/80 px-2 py-0.5 font-mono text-[10px] text-amber-300"> | ||
| OKLCH | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
40 changes: 40 additions & 0 deletions
40
apps/docs/src/components/landing/animations/data-stream.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| export function DataStreamAnim() { | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of real-time WebSocket streaming" | ||
| className="relative flex h-40 items-center justify-between px-6" | ||
| role="img" | ||
| > | ||
| <Endpoint color="#ffb300" label="Server" /> | ||
| <div className="relative mx-3 h-px flex-1 bg-gradient-to-r from-amber-400/30 via-cyan-300/30 to-amber-400/30"> | ||
| <Particle colorClass="bg-amber-300" delay="0s" /> | ||
| <Particle colorClass="bg-cyan-300" delay="0.6s" reverse /> | ||
| <Particle colorClass="bg-amber-300" delay="1.2s" /> | ||
| <Particle colorClass="bg-cyan-300" delay="1.8s" reverse /> | ||
| </div> | ||
| <Endpoint color="#4cc9f0" label="Agent" /> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Endpoint({ label, color }: { label: string; color: string }) { | ||
| return ( | ||
| <div className="flex flex-col items-center gap-1"> | ||
| <div | ||
| className="h-10 w-10 rounded-lg border border-white/10 bg-white/[0.04]" | ||
| style={{ boxShadow: `0 0 24px -6px ${color}` }} | ||
| /> | ||
| <span className="font-mono text-[10px] text-zinc-400 uppercase tracking-wider">{label}</span> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Particle({ delay, colorClass, reverse }: { delay: string; colorClass: string; reverse?: boolean }) { | ||
| return ( | ||
| <span | ||
| aria-hidden | ||
| className={`stream-particle absolute top-1/2 h-1.5 w-3 -translate-y-1/2 rounded-full ${colorClass}`} | ||
| style={{ animationDelay: delay, animationDirection: reverse ? 'reverse' : 'normal' }} | ||
| /> | ||
| ) | ||
| } |
34 changes: 34 additions & 0 deletions
34
apps/docs/src/components/landing/animations/docker-stack.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { Box } from 'lucide-react' | ||
|
|
||
| export function DockerStackAnim() { | ||
| const containers = [ | ||
| { name: 'web', tag: 'caddy:2', cpu: '0.4%', delay: '0s' }, | ||
| { name: 'api', tag: 'rust:1.84', cpu: '1.2%', delay: '0.4s' }, | ||
| { name: 'cache', tag: 'redis:7', cpu: '0.1%', delay: '0.8s' } | ||
| ] | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of Docker container management" | ||
| className="flex h-full flex-col justify-center gap-1.5" | ||
| role="img" | ||
| > | ||
| {containers.map((c) => ( | ||
| <div | ||
| className="flex items-center gap-2 rounded-lg border border-white/10 bg-white/[0.04] px-2.5 py-1.5 font-mono text-[11px]" | ||
| key={c.name} | ||
| > | ||
| <Box className="h-3.5 w-3.5 shrink-0 text-cyan-300" /> | ||
| <span className="truncate text-zinc-200">{c.name}</span> | ||
| <span className="truncate text-[10px] text-zinc-500">{c.tag}</span> | ||
| <span className="ml-auto inline-flex items-center gap-1.5 text-[10px] text-emerald-300"> | ||
| <span | ||
| className="pulse-dot inline-block h-1.5 w-1.5 rounded-full bg-emerald-400" | ||
| style={{ animationDelay: c.delay }} | ||
| /> | ||
| {c.cpu} | ||
| </span> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| ) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { File, FolderOpen, FolderTree, Upload } from 'lucide-react' | ||
| import type { ComponentType } from 'react' | ||
|
|
||
| export function FileTreeAnim() { | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of the file manager" | ||
| className="flex h-full flex-col gap-2 font-mono text-xs" | ||
| role="img" | ||
| > | ||
| <div className="min-h-0 flex-1 space-y-0.5 overflow-hidden rounded-lg border border-white/10 bg-black/30 px-3 py-2 text-zinc-300"> | ||
| <Row Icon={FolderTree} label="/var/log" /> | ||
| <Row Icon={FolderOpen} indent label="nginx" /> | ||
| <Row Icon={File} indent2 label="access.log" muted="2.4 MB" /> | ||
| <Row Icon={File} indent2 label="error.log" muted="312 KB" /> | ||
| </div> | ||
| <div className="flex shrink-0 items-center gap-2.5"> | ||
| <Upload aria-hidden className="h-3 w-3 shrink-0 text-amber-300" /> | ||
| <span className="shrink-0 text-[10px] text-zinc-400">access.log → uploading</span> | ||
| <div className="relative h-1.5 flex-1 overflow-hidden rounded-full bg-white/5"> | ||
| <span className="light-band absolute inset-y-0 left-0 w-1/2 bg-gradient-to-r from-amber-400 via-amber-300 to-amber-400" /> | ||
| </div> | ||
| <span className="shrink-0 font-mono text-[10px] text-amber-300">64%</span> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Row({ | ||
| Icon, | ||
| label, | ||
| indent, | ||
| indent2, | ||
| muted | ||
| }: { | ||
| Icon: ComponentType<{ className?: string }> | ||
| label: string | ||
| indent?: boolean | ||
| indent2?: boolean | ||
| muted?: string | ||
| }) { | ||
| let pad = '' | ||
| if (indent2) { | ||
| pad = 'pl-6' | ||
| } else if (indent) { | ||
| pad = 'pl-3' | ||
| } | ||
| return ( | ||
| <div className={`flex items-center gap-2 ${pad}`}> | ||
| <Icon className="h-3.5 w-3.5 text-amber-300" /> | ||
| <span className="text-zinc-300">{label}</span> | ||
| {muted ? <span className="ml-auto text-[10px] text-zinc-500">{muted}</span> : null} | ||
| </div> | ||
| ) | ||
| } |
28 changes: 28 additions & 0 deletions
28
apps/docs/src/components/landing/animations/install-binary.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| export function InstallBinaryAnim() { | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of installing the ServerBee binary" | ||
| className="flex h-40 items-center justify-center" | ||
| role="img" | ||
| > | ||
| <div className="relative flex flex-col items-center gap-3"> | ||
| <div className="rounded-lg border border-amber-400/40 bg-amber-400/10 px-4 py-2 font-mono text-amber-300 text-xs shadow-[0_0_30px_-12px_rgba(255,179,0,0.6)]"> | ||
| serverbee | ||
| </div> | ||
| <svg aria-hidden="true" focusable="false" height="32" viewBox="0 0 20 32" width="20"> | ||
| <path | ||
| d="M10 2 L10 24 M4 18 L10 26 L16 18" | ||
| fill="none" | ||
| stroke="#ffb300" | ||
| strokeLinecap="round" | ||
| strokeWidth="2" | ||
| /> | ||
| </svg> | ||
| <div className="flex items-center gap-2 rounded-md border border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-zinc-300"> | ||
| <span className="pulse-dot inline-block h-2 w-2 rounded-full bg-emerald-400" /> | ||
| systemd · active | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export function LightBandArrow() { | ||
| return ( | ||
| <div aria-hidden className="relative mx-2 hidden h-px flex-1 self-center bg-white/10 md:block"> | ||
| <span className="light-band absolute -top-px h-[3px] w-1/3 rounded-full bg-gradient-to-r from-transparent via-amber-300 to-transparent shadow-[0_0_12px_2px_rgba(255,179,0,0.4)]" /> | ||
| </div> | ||
| ) | ||
| } |
103 changes: 103 additions & 0 deletions
103
apps/docs/src/components/landing/animations/mini-dashboard.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| export function MiniDashboard() { | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of a ServerBee server card" | ||
| className="relative w-full max-w-md rounded-2xl border border-white/10 bg-white/[0.03] p-5 shadow-2xl shadow-amber-500/5 backdrop-blur" | ||
| role="img" | ||
| > | ||
| <header className="mb-4 flex items-center justify-between"> | ||
| <div className="flex items-center gap-2"> | ||
| <span className="pulse-dot inline-block h-2.5 w-2.5 rounded-full bg-emerald-400" /> | ||
| <span className="font-medium text-sm text-zinc-100">edge-tokyo-01</span> | ||
| </div> | ||
| <span className="rounded-md bg-white/5 px-2 py-0.5 font-mono text-xs text-zinc-400">linux/arm64</span> | ||
| </header> | ||
|
|
||
| <div className="grid grid-cols-2 gap-4"> | ||
| <Ring color="#ffb300" label="CPU" value={42} /> | ||
| <Ring color="#4cc9f0" label="MEM" value={61} /> | ||
| </div> | ||
|
|
||
| <div className="mt-5"> | ||
| <div className="mb-2 flex items-center justify-between text-xs text-zinc-400"> | ||
| <span>Network</span> | ||
| <span className="font-mono text-zinc-300">↑ 2.1 MB/s · ↓ 318 KB/s</span> | ||
| </div> | ||
| <Sparkline /> | ||
| </div> | ||
|
|
||
| <footer className="mt-4 grid grid-cols-3 gap-2 text-center text-xs"> | ||
| <Stat label="Load" value="0.42" /> | ||
| <Stat label="Disk" value="58%" /> | ||
| <Stat label="Uptime" value="14d" /> | ||
| </footer> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Ring({ label, value, color }: { label: string; value: number; color: string }) { | ||
| const dash = 220 | ||
| return ( | ||
| <div className="flex items-center gap-3 rounded-xl bg-white/[0.03] p-3"> | ||
| <svg aria-hidden="true" focusable="false" height="60" viewBox="0 0 80 80" width="60"> | ||
| <circle cx="40" cy="40" fill="none" r="34" stroke="rgba(255,255,255,0.08)" strokeWidth="8" /> | ||
| <circle | ||
| className="ring-anim" | ||
| cx="40" | ||
| cy="40" | ||
| fill="none" | ||
| r="34" | ||
| stroke={color} | ||
| strokeDasharray={dash} | ||
| strokeLinecap="round" | ||
| strokeWidth="8" | ||
| transform="rotate(-90 40 40)" | ||
| /> | ||
| </svg> | ||
| <div> | ||
| <div className="font-mono text-xs text-zinc-400">{label}</div> | ||
| <div className="font-semibold text-xl text-zinc-100">{value}%</div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Sparkline() { | ||
| return ( | ||
| <div className="relative h-14 w-full overflow-hidden rounded-md bg-white/[0.03]"> | ||
| <svg | ||
| aria-hidden="true" | ||
| className="spark-scroll absolute inset-y-0 left-0 h-full w-[200%]" | ||
| focusable="false" | ||
| preserveAspectRatio="none" | ||
| viewBox="0 0 400 56" | ||
| > | ||
| <defs> | ||
| <linearGradient id="spark-fill" x1="0" x2="0" y1="0" y2="1"> | ||
| <stop offset="0%" stopColor="#ffb300" stopOpacity="0.45" /> | ||
| <stop offset="100%" stopColor="#ffb300" stopOpacity="0" /> | ||
| </linearGradient> | ||
| </defs> | ||
| <path | ||
| d="M0 38 L20 30 L40 34 L60 22 L80 28 L100 18 L120 26 L140 14 L160 24 L180 16 L200 30 L220 22 L240 32 L260 18 L280 28 L300 20 L320 34 L340 24 L360 30 L380 22 L400 28 L400 56 L0 56 Z" | ||
| fill="url(#spark-fill)" | ||
| /> | ||
| <path | ||
| d="M0 38 L20 30 L40 34 L60 22 L80 28 L100 18 L120 26 L140 14 L160 24 L180 16 L200 30 L220 22 L240 32 L260 18 L280 28 L300 20 L320 34 L340 24 L360 30 L380 22 L400 28" | ||
| fill="none" | ||
| stroke="#ffb300" | ||
| strokeWidth="1.5" | ||
| /> | ||
| </svg> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| function Stat({ label, value }: { label: string; value: string }) { | ||
| return ( | ||
| <div className="rounded-lg bg-white/[0.03] py-2"> | ||
| <div className="text-[10px] text-zinc-500 uppercase tracking-wider">{label}</div> | ||
| <div className="font-mono text-sm text-zinc-200">{value}</div> | ||
| </div> | ||
| ) | ||
| } | ||
29 changes: 29 additions & 0 deletions
29
apps/docs/src/components/landing/animations/monitor-dots.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| export function MonitorDotsAnim() { | ||
| const probes = [ | ||
| { name: 'SSL', meta: 'expires in 73d' }, | ||
| { name: 'DNS', meta: 'A · CNAME' }, | ||
| { name: 'HTTP', meta: '200 · keyword OK' }, | ||
| { name: 'TCP', meta: ':443 · 18 ms' }, | ||
| { name: 'WHOIS', meta: 'renews 2027-04' } | ||
| ] | ||
| return ( | ||
| <div | ||
| aria-label="Animated demo of service monitors" | ||
| className="grid h-full grid-cols-1 gap-1.5 font-mono text-xs sm:grid-cols-2" | ||
| role="img" | ||
| > | ||
| {probes.map((p, i) => ( | ||
| <div className="flex items-center justify-between rounded-md bg-white/[0.03] px-3 py-1.5" key={p.name}> | ||
| <div className="flex items-center gap-2"> | ||
| <span | ||
| className="pulse-dot inline-block h-2 w-2 rounded-full bg-emerald-400" | ||
| style={{ animationDelay: `${i * 0.35}s` }} | ||
| /> | ||
| <span className="text-zinc-200">{p.name}</span> | ||
| </div> | ||
| <span className="text-[10px] text-zinc-500">{p.meta}</span> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| ) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ring progress visualization doesn't use the
valueprop.The
Ringcomponent accepts avalueprop (e.g., 42, 61) but doesn't calculatestrokeDashoffsetto reflect that value. Currently,strokeDasharrayis fixed at 220 and nostrokeDashoffsetis set, meaning both rings will display identically regardless of their different values.For a proper progress ring, calculate and apply the offset:
Then add
strokeDashoffset={offset}to the animated circle, or apply it via the.ring-animCSS class using a CSS custom property.🔧 Proposed fix
function Ring({ label, value, color }: { label: string; value: number; color: string }) { - const dash = 220 + const radius = 34 + const circumference = 2 * Math.PI * radius + const offset = circumference * (1 - value / 100) return ( <div className="flex items-center gap-3 rounded-xl bg-white/[0.03] p-3"> <svg aria-hidden="true" focusable="false" height="60" viewBox="0 0 80 80" width="60"> <circle cx="40" cy="40" fill="none" r="34" stroke="rgba(255,255,255,0.08)" strokeWidth="8" /> <circle className="ring-anim" cx="40" cy="40" fill="none" - r="34" + r={radius} stroke={color} - strokeDasharray={dash} + strokeDasharray={circumference} + strokeDashoffset={offset} strokeLinecap="round" strokeWidth="8" transform="rotate(-90 40 40)" /> </svg>🤖 Prompt for AI Agents