- {children}
+
+ {/* Mobile header */}
+
+
+
+
+
+
+
+ setMobileMenuOpen(false)} />
+
+
+
+
+
+
+
+
Docs
+
+
+
+
+
-
+
+
+
+ {/* Desktop sidebar */}
+
+
+ {/* Main content */}
+
+
+
+ {/* Article content */}
+
+
+
+ {children}
+
+
+
+ {/* Table of contents - desktop only */}
+ {showToc && toc.length > 0 && (
+
+ )}
+
+
+
+
)
}
+
+// Mobile sidebar content
+function MobileSidebar({ onNavigate }: { onNavigate: () => void }) {
+ return (
+
+
+
+
+
+
+
+
OpenCodeIntel
+
Documentation
+
+
+
+
+
+
+ )
+}
+
+// Mobile navigation items
+const mobileNavigation = [
+ {
+ title: 'Getting Started',
+ items: [
+ { title: 'Introduction', href: '/docs' },
+ { title: 'Quick Start', href: '/docs/quickstart' },
+ ],
+ },
+ {
+ title: 'MCP Integration',
+ items: [
+ { title: 'MCP Setup Guide', href: '/docs/mcp-setup' },
+ { title: 'Tools Reference', href: '/docs/mcp-tools' },
+ { title: 'Example Prompts', href: '/docs/mcp-examples' },
+ ],
+ },
+ {
+ title: 'Features',
+ items: [
+ { title: 'Semantic Search', href: '/docs/features/search' },
+ { title: 'Dependency Analysis', href: '/docs/features/dependencies' },
+ { title: 'Impact Prediction', href: '/docs/features/impact' },
+ { title: 'Code Style Analysis', href: '/docs/features/style' },
+ ],
+ },
+ {
+ title: 'Deployment',
+ items: [
+ { title: 'Docker Setup', href: '/docs/deployment/docker' },
+ { title: 'Self-Hosting', href: '/docs/deployment/self-host' },
+ ],
+ },
+ {
+ title: 'API Reference',
+ items: [
+ { title: 'Overview', href: '/docs/api' },
+ { title: 'Repositories', href: '/docs/api/repositories' },
+ { title: 'Search', href: '/docs/api/search' },
+ { title: 'Analysis', href: '/docs/api/analysis' },
+ ],
+ },
+ {
+ title: 'Contributing',
+ items: [
+ { title: 'Architecture', href: '/docs/architecture' },
+ { title: 'Development Setup', href: '/docs/contributing' },
+ ],
+ },
+]
+
+function MobileNavigation({ onNavigate }: { onNavigate: () => void }) {
+ const location = useLocation()
+
+ const isActive = (href: string) => {
+ return location.pathname === href
+ }
+
+ return (
+
+ )
+}
diff --git a/frontend/src/components/docs/DocsPageHeader.tsx b/frontend/src/components/docs/DocsPageHeader.tsx
new file mode 100644
index 0000000..f2422a0
--- /dev/null
+++ b/frontend/src/components/docs/DocsPageHeader.tsx
@@ -0,0 +1,38 @@
+import { TimeEstimate, DifficultyBadge } from './DocsBadges'
+
+interface DocsPageHeaderProps {
+ title: string
+ description: string
+ timeEstimate?: number
+ difficulty?: 'beginner' | 'intermediate' | 'advanced'
+ category?: string
+}
+
+export function DocsPageHeader({
+ title,
+ description,
+ timeEstimate,
+ difficulty,
+ category
+}: DocsPageHeaderProps) {
+ return (
+
+ {category && (
+
+ {category}
+
+ )}
+
+
{title}
+
+
{description}
+
+ {(timeEstimate != null || difficulty) && (
+
+ {timeEstimate != null && }
+ {difficulty && }
+
+ )}
+
+ )
+}
diff --git a/frontend/src/components/docs/DocsPrerequisites.tsx b/frontend/src/components/docs/DocsPrerequisites.tsx
new file mode 100644
index 0000000..8ffb685
--- /dev/null
+++ b/frontend/src/components/docs/DocsPrerequisites.tsx
@@ -0,0 +1,101 @@
+import { useState } from 'react'
+import { ChevronDown, Check, ExternalLink } from 'lucide-react'
+import { cn } from '@/lib/utils'
+import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
+
+interface Prerequisite {
+ text: string
+ href?: string
+ completed?: boolean
+}
+
+interface DocsPrerequisitesProps {
+ items: Prerequisite[]
+ defaultOpen?: boolean
+}
+
+export function DocsPrerequisites({ items, defaultOpen = false }: DocsPrerequisitesProps) {
+ const [open, setOpen] = useState(defaultOpen)
+
+ return (
+
+
+
+ 📋
+ Prerequisites
+ ({items.length} items)
+
+
+
+
+
+
+
+ {items.map((item, index) => (
+ -
+
+ {item.completed ? (
+
+ ) : (
+
+ )}
+
+
+ {item.href ? (
+
+ {item.text}
+
+
+ ) : (
+ item.text
+ )}
+
+
+ ))}
+
+
+
+
+ )
+}
+
+// What you will learn section
+interface LearningObjective {
+ text: string
+}
+
+interface DocsLearningObjectivesProps {
+ items: LearningObjective[]
+}
+
+export function DocsLearningObjectives({ items }: DocsLearningObjectivesProps) {
+ return (
+
+
+ 🎯
+ What you will learn
+
+
+ {items.map((item, index) => (
+ -
+
+ {item.text}
+
+ ))}
+
+
+ )
+}
diff --git a/frontend/src/components/docs/DocsRelated.tsx b/frontend/src/components/docs/DocsRelated.tsx
new file mode 100644
index 0000000..fad57bc
--- /dev/null
+++ b/frontend/src/components/docs/DocsRelated.tsx
@@ -0,0 +1,101 @@
+import { Link } from 'react-router-dom'
+import { ArrowRight, ChevronLeft, ChevronRight } from 'lucide-react'
+import { cn } from '@/lib/utils'
+
+interface RelatedDoc {
+ title: string
+ description: string
+ href: string
+ icon?: React.ReactNode
+}
+
+interface DocsRelatedProps {
+ items: RelatedDoc[]
+ title?: string
+}
+
+export function DocsRelated({ items, title = 'Related' }: DocsRelatedProps) {
+ return (
+
+
+ {title}
+
+
+ {items.map((item) => (
+
+ {item.icon && (
+
+ {item.icon}
+
+ )}
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+
+ ))}
+
+
+ )
+}
+
+// Previous/Next navigation at bottom of page
+interface DocsPaginationProps {
+ prev?: {
+ title: string
+ href: string
+ }
+ next?: {
+ title: string
+ href: string
+ }
+}
+
+export function DocsPagination({ prev, next }: DocsPaginationProps) {
+ return (
+
+ {prev ? (
+
+
+
+
Previous
+
{prev.title}
+
+
+ ) : (
+
+ )}
+
+ {next ? (
+
+
+
+
+ ) : (
+
+ )}
+
+ )
+}
diff --git a/frontend/src/components/docs/DocsSearch.tsx b/frontend/src/components/docs/DocsSearch.tsx
new file mode 100644
index 0000000..b8d942e
--- /dev/null
+++ b/frontend/src/components/docs/DocsSearch.tsx
@@ -0,0 +1,239 @@
+import { useEffect, useState, useCallback, useMemo } from 'react'
+import { useNavigate } from 'react-router-dom'
+import {
+ CommandDialog,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from '@/components/ui/command'
+import {
+ FileText,
+ Zap,
+ GitBranch,
+ Search as SearchIcon,
+ AlertTriangle,
+ Palette,
+ Terminal,
+ Server,
+ Code,
+ BookOpen
+} from 'lucide-react'
+
+interface DocPage {
+ title: string
+ href: string
+ description: string
+ icon: React.ReactNode
+ category: string
+}
+
+const docsPages: DocPage[] = [
+ // Getting Started
+ {
+ title: 'Introduction',
+ href: '/docs',
+ description: 'Overview of OpenCodeIntel',
+ icon:
,
+ category: 'Getting Started'
+ },
+ {
+ title: 'Quick Start',
+ href: '/docs/quickstart',
+ description: 'Get up and running in 5 minutes',
+ icon:
,
+ category: 'Getting Started'
+ },
+
+ // MCP Integration
+ {
+ title: 'MCP Setup Guide',
+ href: '/docs/mcp-setup',
+ description: 'Connect to Claude Desktop',
+ icon:
,
+ category: 'MCP Integration'
+ },
+ {
+ title: 'MCP Tools Reference',
+ href: '/docs/mcp-tools',
+ description: 'All available MCP tools',
+ icon:
,
+ category: 'MCP Integration'
+ },
+ {
+ title: 'Example Prompts',
+ href: '/docs/mcp-examples',
+ description: 'Real prompts that work',
+ icon:
,
+ category: 'MCP Integration'
+ },
+
+ // Features
+ {
+ title: 'Semantic Search',
+ href: '/docs/features/search',
+ description: 'Find code by meaning',
+ icon:
,
+ category: 'Features'
+ },
+ {
+ title: 'Dependency Analysis',
+ href: '/docs/features/dependencies',
+ description: 'Visualize architecture',
+ icon:
,
+ category: 'Features'
+ },
+ {
+ title: 'Impact Prediction',
+ href: '/docs/features/impact',
+ description: 'Know what breaks',
+ icon:
,
+ category: 'Features'
+ },
+ {
+ title: 'Code Style Analysis',
+ href: '/docs/features/style',
+ description: 'Team conventions',
+ icon:
,
+ category: 'Features'
+ },
+
+ // Deployment
+ {
+ title: 'Docker Setup',
+ href: '/docs/deployment/docker',
+ description: 'Run with Docker Compose',
+ icon:
,
+ category: 'Deployment'
+ },
+ {
+ title: 'Self-Hosting Guide',
+ href: '/docs/deployment/self-host',
+ description: 'Full deployment guide',
+ icon:
,
+ category: 'Deployment'
+ },
+
+ // API Reference
+ {
+ title: 'API Overview',
+ href: '/docs/api',
+ description: 'REST API introduction',
+ icon:
,
+ category: 'API Reference'
+ },
+ {
+ title: 'Repositories API',
+ href: '/docs/api/repositories',
+ description: 'Manage indexed repositories',
+ icon:
,
+ category: 'API Reference'
+ },
+ {
+ title: 'Search API',
+ href: '/docs/api/search',
+ description: 'Semantic code search',
+ icon:
,
+ category: 'API Reference'
+ },
+ {
+ title: 'Analysis API',
+ href: '/docs/api/analysis',
+ description: 'Dependencies, impact, style',
+ icon:
,
+ category: 'API Reference'
+ },
+
+ // Contributing
+ {
+ title: 'Architecture',
+ href: '/docs/architecture',
+ description: 'System design and tech stack',
+ icon:
,
+ category: 'Contributing'
+ },
+ {
+ title: 'Development Setup',
+ href: '/docs/contributing',
+ description: 'Local dev environment',
+ icon:
,
+ category: 'Contributing'
+ },
+]
+
+// Pre-compute grouped pages at module level since docsPages is constant
+const groupedPages = docsPages.reduce((acc, page) => {
+ if (!acc[page.category]) {
+ acc[page.category] = []
+ }
+ acc[page.category].push(page)
+ return acc
+}, {} as Record
)
+
+export function DocsSearch() {
+ const [open, setOpen] = useState(false)
+ const navigate = useNavigate()
+
+ const isMac = useMemo(() => {
+ if (typeof navigator === 'undefined') return true
+ return navigator.platform.toLowerCase().includes('mac')
+ }, [])
+
+ useEffect(() => {
+ const down = (e: KeyboardEvent) => {
+ if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
+ e.preventDefault()
+ setOpen((open) => !open)
+ }
+ }
+
+ document.addEventListener('keydown', down)
+ return () => document.removeEventListener('keydown', down)
+ }, [])
+
+ const runCommand = useCallback((command: () => void) => {
+ setOpen(false)
+ command()
+ }, [])
+
+ return (
+ <>
+
+
+
+
+
+ No results found.
+ {Object.entries(groupedPages).map(([category, pages]) => (
+
+ {pages.map((page) => (
+ runCommand(() => navigate(page.href))}
+ className="flex items-center gap-3 cursor-pointer"
+ >
+ {page.icon}
+
+ {page.title}
+ {page.description}
+
+
+ ))}
+
+ ))}
+
+
+ >
+ )
+}
diff --git a/frontend/src/components/docs/DocsSidebar.tsx b/frontend/src/components/docs/DocsSidebar.tsx
index d902619..8cf81c2 100644
--- a/frontend/src/components/docs/DocsSidebar.tsx
+++ b/frontend/src/components/docs/DocsSidebar.tsx
@@ -1,4 +1,20 @@
import { Link, useLocation } from 'react-router-dom'
+import { cn } from '@/lib/utils'
+import { ScrollArea } from '@/components/ui/scroll-area'
+import { DocsSearch } from './DocsSearch'
+import {
+ BookOpen,
+ Zap,
+ Terminal,
+ Code,
+ FileText,
+ Search,
+ GitBranch,
+ AlertTriangle,
+ Palette,
+ Server,
+ ChevronLeft
+} from 'lucide-react'
interface NavItem {
title: string
@@ -15,32 +31,48 @@ const navigation: NavSection[] = [
{
title: 'Getting Started',
items: [
- { title: 'Introduction', href: '/docs' },
- { title: 'Quick Start', href: '/docs/quickstart' },
+ { title: 'Introduction', href: '/docs', icon: },
+ { title: 'Quick Start', href: '/docs/quickstart', icon: },
],
},
{
title: 'MCP Integration',
items: [
- { title: 'MCP Setup Guide', href: '/docs/mcp-setup' },
- { title: 'Available Tools', href: '/docs/mcp-tools' },
- { title: 'Example Prompts', href: '/docs/mcp-examples' },
+ { title: 'MCP Setup Guide', href: '/docs/mcp-setup', icon: },
+ { title: 'Tools Reference', href: '/docs/mcp-tools', icon: },
+ { title: 'Example Prompts', href: '/docs/mcp-examples', icon: },
],
},
{
title: 'Features',
items: [
- { title: 'Semantic Search', href: '/docs/features/search' },
- { title: 'Dependency Analysis', href: '/docs/features/dependencies' },
- { title: 'Impact Prediction', href: '/docs/features/impact' },
- { title: 'Code Style Analysis', href: '/docs/features/style' },
+ { title: 'Semantic Search', href: '/docs/features/search', icon: },
+ { title: 'Dependency Analysis', href: '/docs/features/dependencies', icon: },
+ { title: 'Impact Prediction', href: '/docs/features/impact', icon: },
+ { title: 'Code Style Analysis', href: '/docs/features/style', icon: },
+ ],
+ },
+ {
+ title: 'API Reference',
+ items: [
+ { title: 'Overview', href: '/docs/api', icon: },
+ { title: 'Repositories', href: '/docs/api/repositories', icon: },
+ { title: 'Search', href: '/docs/api/search', icon: },
+ { title: 'Analysis', href: '/docs/api/analysis', icon: },
],
},
{
title: 'Deployment',
items: [
- { title: 'Docker Setup', href: '/docs/deployment/docker' },
- { title: 'Self-Hosting', href: '/docs/deployment/self-host' },
+ { title: 'Docker Setup', href: '/docs/deployment/docker', icon: },
+ { title: 'Self-Hosting', href: '/docs/deployment/self-host', icon: },
+ ],
+ },
+ {
+ title: 'Contributing',
+ items: [
+ { title: 'Architecture', href: '/docs/architecture', icon: },
+ { title: 'Development Setup', href: '/docs/contributing', icon: },
],
},
]
@@ -53,43 +85,83 @@ export function DocsSidebar() {
}
return (
-