Skip to content

Commit 351441e

Browse files
committed
feat(landing): handle theme both on ssr and csr
1 parent 6e80ad9 commit 351441e

File tree

6 files changed

+90
-26
lines changed

6 files changed

+90
-26
lines changed

apps/docs/app/(home)/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Hero } from "@/components/hero";
22

33
export default function HomePage() {
44
return (
5-
<main className="h-screen w-full -mt-32 bg-black">
5+
<main className="h-screen w-full -mt-34 bg-white dark:bg-black">
66
<Hero />
77
</main>
88
);

apps/docs/app/layout.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Inter } from "next/font/google";
66
import { Navbar } from "@/components/navbar";
77
import SearchDialog from "@/components/search";
88
import { baseOptions } from "@/lib/layout.shared";
9+
import { ThemeProvider } from "@/components/theme-provider";
10+
import { cookies } from "next/headers";
911

1012
const inter = Inter({
1113
subsets: ["latin"],
@@ -16,18 +18,24 @@ export const metadata: Metadata = {
1618
description: "Rust library for AI apps, inspired by the Vercel AI SDK.",
1719
};
1820

19-
export default function Layout({ children }: LayoutProps<"/">) {
21+
export default async function Layout({ children }: LayoutProps<"/">) {
22+
const cookieStore = await cookies();
23+
const themeCookie = cookieStore.get("theme");
24+
const theme = themeCookie?.value || "dark";
25+
2026
return (
2127
<html lang="en" className={inter.className} suppressHydrationWarning>
2228
<body className="flex flex-col min-h-screen">
23-
<RootProvider
24-
search={{
25-
SearchDialog,
26-
}}
27-
>
28-
<ServerNavbar />
29-
<HomeLayout {...baseOptions()}>{children}</HomeLayout>
30-
</RootProvider>
29+
<ThemeProvider theme={theme}>
30+
<RootProvider
31+
search={{
32+
SearchDialog,
33+
}}
34+
>
35+
<ServerNavbar />
36+
<HomeLayout {...baseOptions()}>{children}</HomeLayout>
37+
</RootProvider>
38+
</ThemeProvider>
3139
</body>
3240
</html>
3341
);

apps/docs/components/hero.tsx

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22
import Link from "next/link";
3+
import { useTheme } from "next-themes";
34
import { Button } from "@/components/ui/button";
45
import { Copy, SquareArrowOutUpRight } from "lucide-react";
56
import {
@@ -8,21 +9,32 @@ import {
89
TabsList,
910
TabsTrigger,
1011
} from "fumadocs-ui/components/tabs";
12+
import { useServerTheme } from "@/components/theme-provider";
1113
import { Anthropic, Google, OpenAI } from "@lobehub/icons";
1214
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
1315

1416
export function Hero() {
17+
const { resolvedTheme } = useTheme();
18+
const { serverTheme } = useServerTheme();
19+
const theme = resolvedTheme || serverTheme;
20+
const isDark = theme === "dark";
21+
22+
const gridColor = isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
23+
const overlayBackground = isDark
24+
? "radial-gradient(ellipse 120% 100% at 50% 0%, transparent 0%, rgba(0,0,0,0.3) 60%, rgba(0,0,0,0.7) 100%)"
25+
: "radial-gradient(ellipse 120% 100% at 50% 0%, transparent 0%, rgba(255,255,255,0.3) 60%, rgba(255,255,255,0.7) 100%)";
26+
1527
return (
16-
<div className="h-full w-full mt-[-12px] relative flex flex-col items-center justify-center bg-black text-white md:p-8">
28+
<div className="relative flex flex-col items-center justify-center min-h-[calc(100vh-64px)] w-full overflow-hidden p-4 md:p-8">
1729
{/* Background Grid with Gradient Overlay */}
1830
<div className="absolute inset-0 pointer-events-none">
1931
{/* Grid Pattern */}
2032
<div
2133
className="absolute inset-0"
2234
style={{
2335
backgroundImage: `
24-
linear-gradient(to right, rgba(255,255,255,0.08) 1px, transparent 1px),
25-
linear-gradient(to bottom, rgba(255,255,255,0.08) 1px, transparent 1px)
36+
linear-gradient(to right, ${gridColor} 1px, transparent 1px),
37+
linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)
2638
`,
2739
backgroundSize: "80px 80px",
2840
}}
@@ -32,54 +44,53 @@ export function Hero() {
3244
<div
3345
className="absolute inset-0"
3446
style={{
35-
background:
36-
"radial-gradient(ellipse 120% 100% at 50% 0%, transparent 0%, rgba(0,0,0,0.3) 60%, rgba(0,0,0,0.7) 100%)",
47+
background: overlayBackground,
3748
}}
3849
/>
3950
</div>
4051

4152
<div className="relative z-10 grid grid-cols-1 lg:grid-cols-2 gap-12 max-w-7xl w-full items-center">
4253
{/* Left Column */}
4354
<div className="flex flex-col items-start text-left space-y-6">
44-
<div className="flex items-center gap-2 mb-2 text-xs text-gray-400">
45-
<div className="w-2 h-2 rounded-full bg-white/50" />
55+
<div className="flex items-center gap-2 mb-2 text-xs text-gray-600 dark:text-gray-400">
56+
<div className="w-2 h-2 rounded-full bg-black/50 dark:bg-white/50" />
4657
<span>Blazingly Fast :)</span>
4758
</div>
4859

49-
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight text-white leading-tight">
60+
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight text-black dark:text-white leading-tight">
5061
The AI Toolkit for <span className="text-orange-500">Rust</span>
5162
</h1>
5263

53-
<p className="text-base text-gray-400 max-w-xl">
64+
<p className="text-base text-gray-600 dark:text-gray-400 max-w-xl">
5465
An open-source Rust library for building AI-powered applications,
5566
inspired by the Vercel AI SDK.
5667
</p>
5768

5869
{/* Command Snippet */}
59-
<div className="w-full rounded-xs max-w-md bg-black border border-white/10 p-2.5 flex items-center gap-2.5 font-mono text-xs">
60-
<span className="text-white font-semibold">
61-
<span className="text-red-400"> cargo </span>add{" "}
70+
<div className="w-full rounded-xs max-w-md bg-white border border-black/10 dark:bg-black dark:border-white/10 p-2.5 flex items-center gap-2.5 font-mono text-xs">
71+
<span className="text-black dark:text-white font-semibold">
72+
<span className="text-red-500 dark:text-red-400"> cargo </span>add{" "}
6273
<span className="text-orange-500">aisdk</span>
6374
</span>
6475
<div className="flex-1" />
6576
<Copy
66-
className="w-3.5 h-3.5 text-gray-500 cursor-pointer hover:text-white transition-colors"
77+
className="w-3.5 h-3.5 text-gray-500 cursor-pointer hover:text-black dark:hover:text-white transition-colors"
6778
onClick={() => navigator.clipboard.writeText("cargo add aisdk")}
6879
/>
6980
</div>
7081
<div className="flex flex-wrap gap-3">
7182
<Button
7283
asChild
7384
size="default"
74-
className="bg-white rounded-xs font-semibold text-black hover:bg-gray-200 px-6"
85+
className="bg-black dark:bg-white rounded-xs font-semibold text-white dark:text-black hover:bg-gray-800 dark:hover:bg-gray-200 px-6"
7586
>
7687
<Link href="/docs">GET STARTED</Link>
7788
</Button>
7889
<Button
7990
variant="outline"
8091
size="default"
8192
asChild
82-
className="px-5 rounded-xs border-white/10 bg-transparent text-white hover:bg-white/5 hover:text-white"
93+
className="px-5 rounded-xs border-black/10 dark:border-white/10 bg-transparent text-black dark:text-white hover:bg-black/5 dark:hover:bg-white/5 hover:text-black dark:hover:text-white"
8394
>
8495
<Link href="https://github.com/lazy-hq/aisdk" target="_blank">
8596
<SquareArrowOutUpRight className="mr-1 h-4 w-4" />
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"use client";
2+
import { createContext, useContext } from "react";
3+
4+
interface ThemeContextValue {
5+
serverTheme: string;
6+
}
7+
8+
const ThemeContext = createContext<ThemeContextValue>({ serverTheme: "dark" });
9+
10+
export function ThemeProvider({
11+
children,
12+
theme,
13+
}: {
14+
children: React.ReactNode;
15+
theme: string;
16+
}) {
17+
return (
18+
<ThemeContext.Provider value={{ serverTheme: theme }}>
19+
{children}
20+
</ThemeContext.Provider>
21+
);
22+
}
23+
24+
export function useServerTheme() {
25+
return useContext(ThemeContext);
26+
}

apps/docs/components/theme-toggle.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Moon, Sun } from "lucide-react";
44
import { useTheme } from "next-themes";
55
import * as React from "react";
66
import { Button } from "@/components/ui/button";
7+
import { setThemeCookie } from "@/lib/setThemeCookie";
78

89
export function ThemeToggle() {
910
const { theme, setTheme } = useTheme();
@@ -22,12 +23,18 @@ export function ThemeToggle() {
2223
);
2324
}
2425

26+
const handleThemeChange = () => {
27+
const value = theme === "dark" ? "light" : "dark";
28+
setTheme(value);
29+
setThemeCookie(value);
30+
};
31+
2532
return (
2633
<Button
2734
variant="ghost"
2835
size="icon"
2936
className="h-9 w-9"
30-
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
37+
onClick={handleThemeChange}
3138
>
3239
<Moon className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
3340
<Sun className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />

apps/docs/lib/setThemeCookie.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"use server";
2+
3+
import { cookies } from "next/headers";
4+
5+
export async function setThemeCookie(theme: string) {
6+
const cookieStore = await cookies();
7+
cookieStore.set("theme", theme, {
8+
path: "/",
9+
maxAge: 60 * 60 * 24 * 365, // 1 year
10+
sameSite: "lax",
11+
});
12+
}

0 commit comments

Comments
 (0)