Skip to content

Commit a25ce4d

Browse files
committed
feat(docs): Phase 1 - Upgraded docs components and layout
- Added Cmd+K search with cmdk - Added Table of Contents with scroll spy - Added breadcrumb navigation - Added syntax highlighted code blocks with copy button and language tabs - Added callout components (info, warning, tip, danger, success) - Added step-by-step tutorial components - Added prerequisites with collapsible - Added time estimate and difficulty badges - Added pagination (prev/next) - Upgraded DocsSidebar with icons and search - Upgraded DocsLayout with mobile support and TOC - Redesigned DocsHomePage with professional look - Rewrote MCPSetupPage using new components New shadcn components: - scroll-area - collapsible - command (cmdk) Added dependencies: - cmdk - @radix-ui/react-scroll-area - @radix-ui/react-collapsible
1 parent d24543a commit a25ce4d

22 files changed

Lines changed: 2367 additions & 1321 deletions

frontend/bun.lock

Lines changed: 0 additions & 772 deletions
This file was deleted.

frontend/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
"dependencies": {
1313
"@radix-ui/react-accordion": "^1.2.12",
1414
"@radix-ui/react-avatar": "^1.1.11",
15+
"@radix-ui/react-collapsible": "^1.1.12",
1516
"@radix-ui/react-dialog": "^1.1.15",
1617
"@radix-ui/react-dropdown-menu": "^2.1.16",
1718
"@radix-ui/react-label": "^2.1.8",
1819
"@radix-ui/react-navigation-menu": "^1.2.14",
1920
"@radix-ui/react-progress": "^1.1.8",
21+
"@radix-ui/react-scroll-area": "^1.2.10",
2022
"@radix-ui/react-separator": "^1.1.8",
2123
"@radix-ui/react-slot": "^1.2.4",
2224
"@radix-ui/react-switch": "^1.2.6",
@@ -28,6 +30,7 @@
2830
"@types/react-syntax-highlighter": "^15.5.13",
2931
"class-variance-authority": "^0.7.1",
3032
"clsx": "^2.1.1",
33+
"cmdk": "^1.1.1",
3134
"dagre": "^0.8.5",
3235
"framer-motion": "^12.29.0",
3336
"lucide-react": "^0.554.0",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Clock } from 'lucide-react'
2+
import { cn } from '@/lib/utils'
3+
4+
interface TimeEstimateProps {
5+
minutes: number
6+
className?: string
7+
}
8+
9+
export function TimeEstimate({ minutes, className }: TimeEstimateProps) {
10+
const label = minutes === 1 ? '1 min read' : `${minutes} min read`
11+
12+
return (
13+
<span className={cn(
14+
'inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium',
15+
'text-gray-400 bg-white/5 border border-white/10 rounded-full',
16+
className
17+
)}>
18+
<Clock className="w-3 h-3" />
19+
{label}
20+
</span>
21+
)
22+
}
23+
24+
// Difficulty badge
25+
type Difficulty = 'beginner' | 'intermediate' | 'advanced'
26+
27+
interface DifficultyBadgeProps {
28+
level: Difficulty
29+
className?: string
30+
}
31+
32+
const difficultyConfig: Record<Difficulty, { label: string; className: string }> = {
33+
beginner: {
34+
label: 'Beginner',
35+
className: 'text-green-400 bg-green-500/10 border-green-500/30',
36+
},
37+
intermediate: {
38+
label: 'Intermediate',
39+
className: 'text-amber-400 bg-amber-500/10 border-amber-500/30',
40+
},
41+
advanced: {
42+
label: 'Advanced',
43+
className: 'text-red-400 bg-red-500/10 border-red-500/30',
44+
},
45+
}
46+
47+
export function DifficultyBadge({ level, className }: DifficultyBadgeProps) {
48+
const config = difficultyConfig[level]
49+
50+
return (
51+
<span className={cn(
52+
'inline-flex items-center px-2.5 py-1 text-xs font-medium border rounded-full',
53+
config.className,
54+
className
55+
)}>
56+
{config.label}
57+
</span>
58+
)
59+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Link, useLocation } from 'react-router-dom'
2+
import { ChevronRight, Home } from 'lucide-react'
3+
4+
interface BreadcrumbItem {
5+
label: string
6+
href: string
7+
}
8+
9+
// Map paths to readable labels
10+
const pathLabels: Record<string, string> = {
11+
'docs': 'Documentation',
12+
'quickstart': 'Quick Start',
13+
'mcp-setup': 'MCP Setup',
14+
'mcp-tools': 'MCP Tools',
15+
'mcp-examples': 'Examples',
16+
'features': 'Features',
17+
'search': 'Semantic Search',
18+
'dependencies': 'Dependencies',
19+
'impact': 'Impact Analysis',
20+
'style': 'Code Style',
21+
'deployment': 'Deployment',
22+
'docker': 'Docker',
23+
'self-host': 'Self-Hosting',
24+
'api': 'API Reference',
25+
'authentication': 'Authentication',
26+
'repositories': 'Repositories',
27+
'architecture': 'Architecture',
28+
'contributing': 'Contributing',
29+
}
30+
31+
export function DocsBreadcrumb() {
32+
const location = useLocation()
33+
const pathSegments = location.pathname.split('/').filter(Boolean)
34+
35+
// Build breadcrumb items
36+
const items: BreadcrumbItem[] = pathSegments.map((segment, index) => {
37+
const href = '/' + pathSegments.slice(0, index + 1).join('/')
38+
const label = pathLabels[segment] || segment.charAt(0).toUpperCase() + segment.slice(1)
39+
return { label, href }
40+
})
41+
42+
// Don't show breadcrumb on docs home
43+
if (pathSegments.length <= 1) {
44+
return null
45+
}
46+
47+
return (
48+
<nav className="flex items-center gap-1 text-sm text-gray-400 mb-6">
49+
<Link
50+
to="/docs"
51+
className="flex items-center hover:text-white transition-colors"
52+
>
53+
<Home className="w-4 h-4" />
54+
</Link>
55+
56+
{items.slice(1).map((item, index) => (
57+
<div key={item.href} className="flex items-center gap-1">
58+
<ChevronRight className="w-4 h-4 text-gray-600" />
59+
{index === items.length - 2 ? (
60+
<span className="text-white font-medium">{item.label}</span>
61+
) : (
62+
<Link
63+
to={item.href}
64+
className="hover:text-white transition-colors"
65+
>
66+
{item.label}
67+
</Link>
68+
)}
69+
</div>
70+
))}
71+
</nav>
72+
)
73+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { cn } from '@/lib/utils'
2+
import { AlertCircle, AlertTriangle, Info, Lightbulb, CheckCircle } from 'lucide-react'
3+
4+
type CalloutType = 'info' | 'warning' | 'tip' | 'danger' | 'success'
5+
6+
interface DocsCalloutProps {
7+
type?: CalloutType
8+
title?: string
9+
children: React.ReactNode
10+
}
11+
12+
const calloutConfig: Record<CalloutType, {
13+
icon: React.ReactNode
14+
containerClass: string
15+
titleClass: string
16+
}> = {
17+
info: {
18+
icon: <Info className="w-5 h-5" />,
19+
containerClass: 'bg-blue-500/10 border-blue-500/30',
20+
titleClass: 'text-blue-400',
21+
},
22+
warning: {
23+
icon: <AlertTriangle className="w-5 h-5" />,
24+
containerClass: 'bg-amber-500/10 border-amber-500/30',
25+
titleClass: 'text-amber-400',
26+
},
27+
tip: {
28+
icon: <Lightbulb className="w-5 h-5" />,
29+
containerClass: 'bg-green-500/10 border-green-500/30',
30+
titleClass: 'text-green-400',
31+
},
32+
danger: {
33+
icon: <AlertCircle className="w-5 h-5" />,
34+
containerClass: 'bg-red-500/10 border-red-500/30',
35+
titleClass: 'text-red-400',
36+
},
37+
success: {
38+
icon: <CheckCircle className="w-5 h-5" />,
39+
containerClass: 'bg-emerald-500/10 border-emerald-500/30',
40+
titleClass: 'text-emerald-400',
41+
},
42+
}
43+
44+
export function DocsCallout({ type = 'info', title, children }: DocsCalloutProps) {
45+
const config = calloutConfig[type]
46+
47+
return (
48+
<div className={cn(
49+
'my-6 rounded-lg border p-4',
50+
config.containerClass
51+
)}>
52+
<div className="flex gap-3">
53+
<span className={cn('shrink-0 mt-0.5', config.titleClass)}>
54+
{config.icon}
55+
</span>
56+
<div className="flex-1 min-w-0">
57+
{title && (
58+
<p className={cn('font-semibold mb-1', config.titleClass)}>
59+
{title}
60+
</p>
61+
)}
62+
<div className="text-gray-300 text-sm [&>p]:mb-2 [&>p:last-child]:mb-0">
63+
{children}
64+
</div>
65+
</div>
66+
</div>
67+
</div>
68+
)
69+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { Link } from 'react-router-dom'
2+
import { ArrowRight, ChevronLeft, ChevronRight } from 'lucide-react'
3+
import { cn } from '@/lib/utils'
4+
5+
interface RelatedDoc {
6+
title: string
7+
description: string
8+
href: string
9+
icon?: React.ReactNode
10+
}
11+
12+
interface DocsRelatedProps {
13+
items: RelatedDoc[]
14+
title?: string
15+
}
16+
17+
export function DocsRelated({ items, title = 'Related Documentation' }: DocsRelatedProps) {
18+
if (items.length === 0) return null
19+
20+
return (
21+
<div className="my-12 pt-8 border-t border-white/10">
22+
<h3 className="text-lg font-semibold text-white mb-4">{title}</h3>
23+
<div className="grid gap-3 sm:grid-cols-2">
24+
{items.map((item) => (
25+
<Link
26+
key={item.href}
27+
to={item.href}
28+
className="group flex items-start gap-3 p-4 rounded-lg bg-white/5 border border-white/10 hover:border-blue-500/50 hover:bg-blue-500/5 transition-all"
29+
>
30+
{item.icon && (
31+
<span className="mt-0.5 text-gray-400 group-hover:text-blue-400 transition-colors">
32+
{item.icon}
33+
</span>
34+
)}
35+
<div className="flex-1 min-w-0">
36+
<h4 className="font-medium text-white group-hover:text-blue-400 transition-colors flex items-center gap-1">
37+
{item.title}
38+
<ArrowRight className="w-4 h-4 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all" />
39+
</h4>
40+
<p className="text-sm text-gray-400 mt-0.5 line-clamp-2">
41+
{item.description}
42+
</p>
43+
</div>
44+
</Link>
45+
))}
46+
</div>
47+
</div>
48+
)
49+
}
50+
51+
interface DocsNavLink {
52+
title: string
53+
href: string
54+
}
55+
56+
interface DocsPaginationProps {
57+
prev?: DocsNavLink
58+
next?: DocsNavLink
59+
}
60+
61+
export function DocsPagination({ prev, next }: DocsPaginationProps) {
62+
return (
63+
<div className="my-12 pt-8 border-t border-white/10 flex items-center justify-between gap-4">
64+
{prev ? (
65+
<Link
66+
to={prev.href}
67+
className="group flex items-center gap-2 text-gray-400 hover:text-white transition-colors"
68+
>
69+
<ChevronLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
70+
<div className="text-right">
71+
<span className="text-xs text-gray-500 block">Previous</span>
72+
<span className="font-medium">{prev.title}</span>
73+
</div>
74+
</Link>
75+
) : (
76+
<div />
77+
)}
78+
79+
{next ? (
80+
<Link
81+
to={next.href}
82+
className="group flex items-center gap-2 text-gray-400 hover:text-white transition-colors text-right"
83+
>
84+
<div>
85+
<span className="text-xs text-gray-500 block">Next</span>
86+
<span className="font-medium">{next.title}</span>
87+
</div>
88+
<ChevronRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
89+
</Link>
90+
) : (
91+
<div />
92+
)}
93+
</div>
94+
)
95+
}
96+
97+
interface DocsCardProps {
98+
title: string
99+
description: string
100+
href: string
101+
icon?: React.ReactNode
102+
badge?: string
103+
}
104+
105+
export function DocsCard({ title, description, href, icon, badge }: DocsCardProps) {
106+
return (
107+
<Link
108+
to={href}
109+
className={cn(
110+
'group relative flex flex-col p-5 rounded-xl',
111+
'bg-[#111113] border border-white/10',
112+
'hover:border-blue-500/50 hover:bg-blue-500/5 transition-all'
113+
)}
114+
>
115+
{badge && (
116+
<span className="absolute top-3 right-3 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider rounded-full bg-blue-500/20 text-blue-400">
117+
{badge}
118+
</span>
119+
)}
120+
121+
<div className="flex items-start gap-4">
122+
{icon && (
123+
<div className="p-2 bg-blue-500/10 rounded-lg text-blue-400 group-hover:bg-blue-500/20 transition-colors">
124+
{icon}
125+
</div>
126+
)}
127+
<div className="flex-1 min-w-0">
128+
<h3 className="text-lg font-medium text-white mb-1 group-hover:text-blue-400 transition-colors">
129+
{title}
130+
</h3>
131+
<p className="text-gray-400 text-sm line-clamp-2">
132+
{description}
133+
</p>
134+
</div>
135+
</div>
136+
</Link>
137+
)
138+
}
139+
140+
export function DocsCardGrid({ children }: { children: React.ReactNode }) {
141+
return (
142+
<div className="grid gap-4 sm:grid-cols-2 my-6">
143+
{children}
144+
</div>
145+
)
146+
}

0 commit comments

Comments
 (0)