Skip to content

Commit f555d72

Browse files
committed
update docs layout
1 parent 4d1972a commit f555d72

File tree

10 files changed

+2025
-1230
lines changed

10 files changed

+2025
-1230
lines changed

app/(home)/FeatureCard.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"use client";
2+
3+
import { motion } from 'framer-motion';
4+
import type { Variants } from 'framer-motion';
5+
import type { ReactNode } from 'react';
6+
7+
interface FeatureCardProps {
8+
icon: ReactNode;
9+
title: string;
10+
subtitle?: string;
11+
description: string;
12+
iconBgGradient: string;
13+
variants?: Variants;
14+
transition?: { duration: number };
15+
}
16+
17+
export default function FeatureCard({
18+
icon,
19+
title,
20+
subtitle,
21+
description,
22+
iconBgGradient,
23+
variants,
24+
transition = { duration: 0.6 },
25+
}: FeatureCardProps) {
26+
return (
27+
<motion.div
28+
variants={variants}
29+
transition={transition}
30+
className="group p-6 rounded-2xl border border-fd-border bg-fd-card hover:shadow-lg transition-shadow"
31+
>
32+
<div className="flex items-center gap-3 mb-4">
33+
<div className={`p-3 ${iconBgGradient} rounded-xl transition-transform`}>
34+
{icon}
35+
</div>
36+
<h3 className="text-2xl font-bold">
37+
{title}
38+
{subtitle && (
39+
<span className="ml-2 md:ml-3 text-base font-normal text-fd-muted-foreground/60">
40+
{subtitle}
41+
</span>
42+
)}
43+
</h3>
44+
</div>
45+
<p className="text-fd-muted-foreground">
46+
{description}
47+
</p>
48+
</motion.div>
49+
);
50+
}

app/(home)/page.tsx

Lines changed: 456 additions & 136 deletions
Large diffs are not rendered by default.

app/api/search/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ const search = {
2929
},
3030
};
3131

32-
export const { staticGET: GET } = createFromSource(source, undefined, search);
32+
export const { staticGET: GET } = createFromSource(source, search);

app/docs/[[...slug]]/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
2-
import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle';
32
import type { ReactNode } from 'react';
43
import { baseOptions } from '@/app/layout.config';
54
import { source } from '@/lib/source';
65
import { GithubInfo } from 'fumadocs-ui/components/github-info';
6+
import { RootToggle } from '@/components/RootToggle';
77

88
const maps = {
99
'Hydro': <GithubInfo owner="hydro-dev" repo="Hydro" />,

app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import './global.css';
22
import 'katex/dist/katex.css';
3-
import { RootProvider } from 'fumadocs-ui/provider';
3+
import { RootProvider } from 'fumadocs-ui/provider/next';
44
import { Inter } from 'next/font/google';
55
import type { ReactNode } from 'react';
66

components/RootToggle.tsx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use client';
2+
3+
import { ChevronDown } from 'lucide-react';
4+
import Link from 'next/link';
5+
import { usePathname } from 'next/navigation';
6+
import { useState, useRef, useEffect } from 'react';
7+
8+
interface RootToggleOption {
9+
title: string;
10+
description: string;
11+
url: string;
12+
}
13+
14+
interface RootToggleProps {
15+
options: RootToggleOption[];
16+
}
17+
18+
export function RootToggle({ options }: RootToggleProps) {
19+
const pathname = usePathname();
20+
const [isOpen, setIsOpen] = useState(false);
21+
const containerRef = useRef<HTMLDivElement>(null);
22+
23+
// Find the current active option based on pathname
24+
const currentOption = options.find((option) => pathname.startsWith(option.url)) || options[0];
25+
26+
// Close dropdown when clicking outside
27+
useEffect(() => {
28+
const handleClickOutside = (event: MouseEvent) => {
29+
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
30+
setIsOpen(false);
31+
}
32+
};
33+
34+
if (isOpen) {
35+
document.addEventListener('mousedown', handleClickOutside);
36+
}
37+
38+
return () => {
39+
document.removeEventListener('mousedown', handleClickOutside);
40+
};
41+
}, [isOpen]);
42+
43+
return (
44+
<div ref={containerRef} className="relative">
45+
<button
46+
type="button"
47+
onClick={() => setIsOpen(!isOpen)}
48+
className="w-full flex items-center justify-between gap-2 px-3 py-2 text-sm rounded-lg border border-fd-border bg-fd-background hover:bg-fd-muted transition-colors"
49+
aria-expanded={isOpen}
50+
aria-haspopup="true"
51+
>
52+
<div className="flex flex-col items-start min-w-0 flex-1">
53+
<span className="font-medium text-fd-foreground truncate w-full">
54+
{currentOption.title}
55+
</span>
56+
<span className="text-xs text-fd-muted-foreground truncate w-full">
57+
{currentOption.description}
58+
</span>
59+
</div>
60+
<ChevronDown
61+
className={`h-4 w-4 text-fd-muted-foreground flex-shrink-0 transition-transform ${
62+
isOpen ? 'transform rotate-180' : ''
63+
}`}
64+
/>
65+
</button>
66+
67+
{isOpen && (
68+
<div className="absolute top-full left-0 right-0 mt-1 bg-fd-background border border-fd-border rounded-lg shadow-lg z-50 overflow-hidden">
69+
{options.map((option) => {
70+
const isActive = pathname.startsWith(option.url);
71+
return (
72+
<Link
73+
key={option.url}
74+
href={option.url}
75+
onClick={() => setIsOpen(false)}
76+
className={`block px-3 py-2 text-sm transition-colors ${
77+
isActive
78+
? 'bg-fd-muted text-fd-foreground font-medium'
79+
: 'text-fd-foreground hover:bg-fd-muted'
80+
}`}
81+
>
82+
<div className="flex flex-col">
83+
<span className="font-medium">{option.title}</span>
84+
<span className="text-xs text-fd-muted-foreground">{option.description}</span>
85+
</div>
86+
</Link>
87+
);
88+
})}
89+
</div>
90+
)}
91+
</div>
92+
);
93+
}

lib/source.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { docs } from '@/.source';
1+
import { docs } from 'fumadocs-mdx:collections/server';
22
import { loader } from 'fumadocs-core/source';
33
import { icons } from 'lucide-react';
44
import { createElement } from 'react';

package.json

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,35 @@
1111
"postinstall": "fumadocs-mdx"
1212
},
1313
"dependencies": {
14-
"@orama/stopwords": "^3.1.13",
15-
"@orama/tokenizers": "^3.1.13",
14+
"@orama/stopwords": "^3.1.18",
15+
"@orama/tokenizers": "^3.1.18",
1616
"embla-carousel-react": "^8.6.0",
17-
"fumadocs-core": "15.7.11",
18-
"fumadocs-mdx": "11.9.1",
19-
"fumadocs-twoslash": "^3.1.7",
20-
"fumadocs-ui": "15.7.11",
21-
"katex": "^0.16.22",
22-
"lucide-react": "^0.544.0",
23-
"next": "15.5.3",
24-
"react": "^19.1.1",
25-
"react-dom": "^19.1.1",
17+
"framer-motion": "^12.29.0",
18+
"fumadocs-core": "16.4.8",
19+
"fumadocs-mdx": "14.2.6",
20+
"fumadocs-twoslash": "^3.1.12",
21+
"fumadocs-ui": "16.4.8",
22+
"katex": "^0.16.27",
23+
"lucide-react": "^0.563.0",
24+
"next": "16.1.4",
25+
"react": "^19.2.3",
26+
"react-dom": "19.2.3",
2627
"rehype-katex": "^7.0.1",
2728
"remark-math": "^6.0.0",
28-
"twoslash": "^0.3.4"
29+
"twoslash": "^0.3.6"
2930
},
3031
"devDependencies": {
31-
"@tailwindcss/postcss": "^4.1.13",
32+
"@tailwindcss/postcss": "^4.1.18",
3233
"@types/mdx": "^2.0.13",
3334
"@types/node": "22.13.8",
34-
"@types/react": "^19.1.13",
35-
"@types/react-dom": "^19.1.9",
35+
"@types/react": "^19.2.9",
36+
"@types/react-dom": "^19.2.3",
3637
"eslint": "^8.57.1",
3738
"eslint-config-next": "15.5.3",
38-
"hydrooj": "^5.0.0-beta.9",
39+
"hydrooj": "^5.0.0-beta.17",
3940
"postcss": "^8.5.6",
40-
"tailwindcss": "^4.1.13",
41-
"typescript": "^5.8.2"
41+
"tailwindcss": "^4.1.18",
42+
"typescript": "^5.9.3"
4243
},
4344
"packageManager": "[email protected]"
4445
}

tsconfig.json

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
"compilerOptions": {
33
"baseUrl": ".",
44
"target": "ESNext",
5-
"lib": ["dom", "dom.iterable", "esnext"],
5+
"lib": [
6+
"dom",
7+
"dom.iterable",
8+
"esnext"
9+
],
610
"allowJs": true,
711
"skipLibCheck": true,
812
"strict": true,
@@ -13,18 +17,28 @@
1317
"moduleResolution": "bundler",
1418
"resolveJsonModule": true,
1519
"isolatedModules": true,
16-
"jsx": "preserve",
20+
"jsx": "react-jsx",
1721
"incremental": true,
1822
"paths": {
19-
"@/.source": ["./.source/index.ts"],
20-
"@/*": ["./*"]
23+
"fumadocs-mdx:collections/*": [".source/*"],
24+
"@/*": [
25+
"./*"
26+
]
2127
},
2228
"plugins": [
2329
{
2430
"name": "next"
2531
}
2632
]
2733
},
28-
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
29-
"exclude": ["node_modules"]
34+
"include": [
35+
"next-env.d.ts",
36+
"**/*.ts",
37+
"**/*.tsx",
38+
".next/types/**/*.ts",
39+
".next/dev/types/**/*.ts"
40+
],
41+
"exclude": [
42+
"node_modules"
43+
]
3044
}

0 commit comments

Comments
 (0)