Skip to content

Commit a11ff2c

Browse files
Copilot4darsh-Dev
andcommitted
Implement comprehensive documentation page with interactive navigation and Mermaid diagrams
Co-authored-by: 4darsh-Dev <109789509+4darsh-Dev@users.noreply.github.com>
1 parent cbcb8fc commit a11ff2c

14 files changed

Lines changed: 5788 additions & 5 deletions

optiblogai-site/eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const eslintConfig = [
2020
"@next/next/no-html-link-for-pages": "off",
2121
"@typescript-eslint/no-unused-vars": "off",
2222
"@typescript-eslint/no-explicit-any": "off",
23+
"react/no-unescaped-entities": "off",
2324
},
2425
},
2526
];

optiblogai-site/package-lock.json

Lines changed: 1616 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

optiblogai-site/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@types/mermaid": "^9.1.0",
13+
"@types/react-syntax-highlighter": "^15.5.13",
1214
"clsx": "^2.1.1",
1315
"framer-motion": "^12.23.6",
1416
"lucide-react": "^0.525.0",
17+
"mermaid": "^11.9.0",
1518
"next": "15.4.1",
1619
"react": "19.1.0",
1720
"react-dom": "19.1.0",
1821
"react-icons": "^5.5.0",
22+
"react-syntax-highlighter": "^15.6.1",
1923
"tailwind-merge": "^3.3.1"
2024
},
2125
"devDependencies": {
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
"use client";
2+
3+
import React, { useState } from "react";
4+
import { ChevronDown, ChevronRight } from "lucide-react";
5+
6+
interface NavigationItem {
7+
id: string;
8+
title: string;
9+
icon: React.ComponentType<any>;
10+
subsections?: {
11+
id: string;
12+
title: string;
13+
}[];
14+
}
15+
16+
interface DocNavigationProps {
17+
sections: NavigationItem[];
18+
activeSection: string;
19+
onSectionChange: (sectionId: string) => void;
20+
searchQuery: string;
21+
}
22+
23+
const DocNavigation: React.FC<DocNavigationProps> = ({
24+
sections,
25+
activeSection,
26+
onSectionChange,
27+
searchQuery,
28+
}) => {
29+
const [expandedSections, setExpandedSections] = useState<Set<string>>(new Set(["overview"]));
30+
31+
const toggleSection = (sectionId: string) => {
32+
const newExpanded = new Set(expandedSections);
33+
if (newExpanded.has(sectionId)) {
34+
newExpanded.delete(sectionId);
35+
} else {
36+
newExpanded.add(sectionId);
37+
}
38+
setExpandedSections(newExpanded);
39+
};
40+
41+
// Filter sections based on search query
42+
const filteredSections = sections.filter((section) =>
43+
searchQuery === "" ||
44+
section.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
45+
section.subsections?.some(sub =>
46+
sub.title.toLowerCase().includes(searchQuery.toLowerCase())
47+
)
48+
);
49+
50+
return (
51+
<nav className="px-4 pb-6">
52+
<div className="space-y-1">
53+
{filteredSections.map((section) => {
54+
const Icon = section.icon;
55+
const isActive = activeSection === section.id;
56+
const isExpanded = expandedSections.has(section.id);
57+
58+
return (
59+
<div key={section.id}>
60+
<button
61+
onClick={() => {
62+
onSectionChange(section.id);
63+
if (section.subsections) {
64+
toggleSection(section.id);
65+
}
66+
}}
67+
className={`w-full flex items-center justify-between px-3 py-2 text-sm font-medium rounded-md transition-colors ${
68+
isActive
69+
? "bg-indigo-50 text-indigo-700 border-r-2 border-indigo-700"
70+
: "text-gray-600 hover:text-gray-900 hover:bg-gray-50"
71+
}`}
72+
>
73+
<div className="flex items-center space-x-3">
74+
<Icon className={`h-4 w-4 ${isActive ? "text-indigo-700" : "text-gray-400"}`} />
75+
<span>{section.title}</span>
76+
</div>
77+
78+
{section.subsections && (
79+
<div className="ml-2">
80+
{isExpanded ? (
81+
<ChevronDown className="h-4 w-4 text-gray-400" />
82+
) : (
83+
<ChevronRight className="h-4 w-4 text-gray-400" />
84+
)}
85+
</div>
86+
)}
87+
</button>
88+
89+
{/* Subsections */}
90+
{section.subsections && isExpanded && (
91+
<div className="mt-1 ml-6 space-y-1">
92+
{section.subsections
93+
.filter(sub =>
94+
searchQuery === "" ||
95+
sub.title.toLowerCase().includes(searchQuery.toLowerCase())
96+
)
97+
.map((subsection) => (
98+
<button
99+
key={subsection.id}
100+
onClick={() => onSectionChange(subsection.id)}
101+
className={`w-full text-left px-3 py-2 text-sm rounded-md transition-colors ${
102+
activeSection === subsection.id
103+
? "bg-indigo-50 text-indigo-700"
104+
: "text-gray-500 hover:text-gray-900 hover:bg-gray-50"
105+
}`}
106+
>
107+
{subsection.title}
108+
</button>
109+
))}
110+
</div>
111+
)}
112+
</div>
113+
);
114+
})}
115+
</div>
116+
117+
{/* Quick Links */}
118+
<div className="mt-8 pt-6 border-t border-gray-200">
119+
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">
120+
Quick Links
121+
</h3>
122+
<div className="space-y-2">
123+
<a
124+
href="https://github.com/solve-ease/OptiBlogAi"
125+
target="_blank"
126+
rel="noopener noreferrer"
127+
className="block px-3 py-2 text-sm text-gray-600 hover:text-indigo-600 transition-colors"
128+
>
129+
GitHub Repository
130+
</a>
131+
<a
132+
href="/demo"
133+
className="block px-3 py-2 text-sm text-gray-600 hover:text-indigo-600 transition-colors"
134+
>
135+
Live Demo
136+
</a>
137+
<a
138+
href="/community"
139+
className="block px-3 py-2 text-sm text-gray-600 hover:text-indigo-600 transition-colors"
140+
>
141+
Community
142+
</a>
143+
</div>
144+
</div>
145+
146+
{/* Version Info */}
147+
<div className="mt-6 pt-4 border-t border-gray-200">
148+
<div className="px-3 py-2">
149+
<div className="text-xs text-gray-500 mb-1">Version</div>
150+
<div className="text-sm font-medium text-gray-900">v1.0.0</div>
151+
</div>
152+
</div>
153+
</nav>
154+
);
155+
};
156+
157+
export default DocNavigation;
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
"use client";
2+
3+
import React, { useState, useEffect } from "react";
4+
import { ChevronRight, Menu, X, Search, BookOpen, Code, Zap, Server, Settings, Users } from "lucide-react";
5+
import DocNavigation from "./DocNavigation";
6+
import OverviewSection from "./sections/OverviewSection";
7+
import ArchitectureSection from "./sections/ArchitectureSection";
8+
import FrontendSection from "./sections/FrontendSection";
9+
import BackendSection from "./sections/BackendSection";
10+
import AgentSystemSection from "./sections/AgentSystemSection";
11+
import APIReferenceSection from "./sections/APIReferenceSection";
12+
import DeploymentSection from "./sections/DeploymentSection";
13+
14+
interface Section {
15+
id: string;
16+
title: string;
17+
icon: React.ComponentType<any>;
18+
component: React.ComponentType<any>;
19+
}
20+
21+
const sections: Section[] = [
22+
{ id: "overview", title: "Overview", icon: BookOpen, component: OverviewSection },
23+
{ id: "architecture", title: "Architecture", icon: Zap, component: ArchitectureSection },
24+
{ id: "frontend", title: "Frontend Guide", icon: Code, component: FrontendSection },
25+
{ id: "backend", title: "Backend Guide", icon: Settings, component: BackendSection },
26+
{ id: "agent-system", title: "Agent System", icon: Zap, component: AgentSystemSection },
27+
{ id: "api", title: "API Reference", icon: Server, component: APIReferenceSection },
28+
{ id: "deployment", title: "Deployment", icon: Settings, component: DeploymentSection },
29+
];
30+
31+
const DocumentationLayout: React.FC = () => {
32+
const [activeSection, setActiveSection] = useState("overview");
33+
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
34+
const [searchQuery, setSearchQuery] = useState("");
35+
36+
// Get the active section component
37+
const ActiveComponent = sections.find(s => s.id === activeSection)?.component || OverviewSection;
38+
39+
const handleSectionChange = (sectionId: string) => {
40+
setActiveSection(sectionId);
41+
setIsSidebarOpen(false); // Close sidebar on mobile after selection
42+
};
43+
44+
return (
45+
<div className="min-h-screen bg-gray-50">
46+
{/* Header */}
47+
<header className="bg-white border-b border-gray-200 sticky top-0 z-40">
48+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
49+
<div className="flex items-center justify-between h-16">
50+
{/* Left side */}
51+
<div className="flex items-center space-x-4">
52+
{/* Mobile menu button */}
53+
<button
54+
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
55+
className="lg:hidden inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
56+
>
57+
{isSidebarOpen ? (
58+
<X className="h-6 w-6" />
59+
) : (
60+
<Menu className="h-6 w-6" />
61+
)}
62+
</button>
63+
64+
{/* Title */}
65+
<div className="flex items-center space-x-2">
66+
<BookOpen className="h-6 w-6 text-indigo-600" />
67+
<h1 className="text-xl font-semibold text-gray-900">OptiBlogAi Docs</h1>
68+
</div>
69+
70+
{/* Breadcrumbs */}
71+
<nav className="hidden md:flex items-center space-x-2 text-sm text-gray-500">
72+
<span>Documentation</span>
73+
<ChevronRight className="h-4 w-4" />
74+
<span className="text-gray-900 font-medium">
75+
{sections.find(s => s.id === activeSection)?.title}
76+
</span>
77+
</nav>
78+
</div>
79+
80+
{/* Search bar */}
81+
<div className="flex-1 max-w-md mx-4">
82+
<div className="relative">
83+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
84+
<input
85+
type="text"
86+
placeholder="Search documentation..."
87+
value={searchQuery}
88+
onChange={(e) => setSearchQuery(e.target.value)}
89+
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
90+
/>
91+
</div>
92+
</div>
93+
94+
{/* Right side actions */}
95+
<div className="flex items-center space-x-3">
96+
<a
97+
href="https://github.com/solve-ease/OptiBlogAi"
98+
target="_blank"
99+
rel="noopener noreferrer"
100+
className="text-gray-500 hover:text-gray-900 transition-colors"
101+
>
102+
<Users className="h-5 w-5" />
103+
</a>
104+
</div>
105+
</div>
106+
</div>
107+
</header>
108+
109+
<div className="flex">
110+
{/* Sidebar */}
111+
<aside
112+
className={`${
113+
isSidebarOpen ? "translate-x-0" : "-translate-x-full"
114+
} lg:translate-x-0 fixed lg:static inset-y-0 left-0 z-30 w-80 bg-white border-r border-gray-200 transition-transform duration-300 ease-in-out`}
115+
>
116+
<div className="h-full overflow-y-auto pt-4">
117+
<DocNavigation
118+
sections={sections}
119+
activeSection={activeSection}
120+
onSectionChange={handleSectionChange}
121+
searchQuery={searchQuery}
122+
/>
123+
</div>
124+
</aside>
125+
126+
{/* Overlay for mobile */}
127+
{isSidebarOpen && (
128+
<div
129+
className="fixed inset-0 bg-black bg-opacity-25 z-20 lg:hidden"
130+
onClick={() => setIsSidebarOpen(false)}
131+
/>
132+
)}
133+
134+
{/* Main content */}
135+
<main className="flex-1 min-w-0">
136+
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
137+
<ActiveComponent />
138+
</div>
139+
</main>
140+
</div>
141+
</div>
142+
);
143+
};
144+
145+
export default DocumentationLayout;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"use client";
2+
3+
import React, { useEffect, useRef } from "react";
4+
import mermaid from "mermaid";
5+
6+
interface MermaidDiagramProps {
7+
chart: string;
8+
id: string;
9+
className?: string;
10+
}
11+
12+
const MermaidDiagram: React.FC<MermaidDiagramProps> = ({ chart, id, className = "" }) => {
13+
const mermaidRef = useRef<HTMLDivElement>(null);
14+
15+
useEffect(() => {
16+
mermaid.initialize({
17+
startOnLoad: true,
18+
theme: "default",
19+
securityLevel: "loose",
20+
themeVariables: {
21+
primaryColor: "#4f46e5",
22+
primaryTextColor: "#ffffff",
23+
primaryBorderColor: "#4f46e5",
24+
lineColor: "#6b7280",
25+
secondaryColor: "#10b981",
26+
tertiaryColor: "#f59e0b",
27+
background: "#ffffff",
28+
mainBkg: "#f8fafc",
29+
secondBkg: "#e5e7eb",
30+
tertiaryBkg: "#f3f4f6",
31+
},
32+
});
33+
34+
if (mermaidRef.current) {
35+
mermaidRef.current.innerHTML = chart;
36+
mermaid.contentLoaded();
37+
}
38+
}, [chart]);
39+
40+
return (
41+
<div className={`mermaid-container bg-gray-50 rounded-lg p-4 overflow-x-auto ${className}`}>
42+
<div
43+
ref={mermaidRef}
44+
id={id}
45+
className="mermaid"
46+
style={{ textAlign: "center" }}
47+
>
48+
{chart}
49+
</div>
50+
</div>
51+
);
52+
};
53+
54+
export default MermaidDiagram;

0 commit comments

Comments
 (0)