Skip to content

Commit 0ff1490

Browse files
committed
docs
1 parent 30c6d3b commit 0ff1490

4 files changed

Lines changed: 435 additions & 0 deletions

File tree

Lines changed: 394 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,394 @@
1+
import React, { useState } from "react";
2+
import {
3+
BookOpen,
4+
Code2,
5+
Terminal,
6+
Settings,
7+
Layout,
8+
ArrowRight,
9+
Check,
10+
Copy,
11+
Menu,
12+
X,
13+
Globe,
14+
Zap
15+
} from "lucide-react";
16+
import { cn } from "../lib/utils";
17+
18+
// --- Components ---
19+
20+
function CodeBlock({ code, language = "html" }: { code: string; language?: string }) {
21+
const [copied, setCopied] = useState(false);
22+
23+
const copyToClipboard = () => {
24+
navigator.clipboard.writeText(code);
25+
setCopied(true);
26+
setTimeout(() => setCopied(false), 2000);
27+
};
28+
29+
return (
30+
<div className="relative group rounded-lg overflow-hidden border border-border bg-slate-950 my-4">
31+
<div className="flex items-center justify-between px-4 py-2 bg-slate-900 border-b border-white/10">
32+
<span className="text-xs text-slate-400 font-mono">{language}</span>
33+
<button
34+
onClick={copyToClipboard}
35+
className="p-1.5 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors"
36+
title="Copy code"
37+
>
38+
{copied ? <Check size={14} className="text-green-400" /> : <Copy size={14} />}
39+
</button>
40+
</div>
41+
<div className="p-4 overflow-x-auto">
42+
<pre className="text-sm font-mono text-slate-50 leading-relaxed">
43+
<code>{code}</code>
44+
</pre>
45+
</div>
46+
</div>
47+
);
48+
}
49+
50+
function Section({
51+
id,
52+
title,
53+
children,
54+
icon: Icon
55+
}: {
56+
id: string;
57+
title: string;
58+
children: React.ReactNode;
59+
icon?: React.ElementType
60+
}) {
61+
return (
62+
<section id={id} className="scroll-mt-24 mb-16 animate-in fade-in slide-in-from-bottom-4 duration-700">
63+
<div className="flex items-center gap-3 mb-6">
64+
{Icon && (
65+
<div className="p-2 rounded-lg bg-primary/10 text-primary">
66+
<Icon size={24} />
67+
</div>
68+
)}
69+
<h2 className="text-3xl font-bold tracking-tight text-foreground">{title}</h2>
70+
</div>
71+
<div className="prose prose-slate max-w-none text-muted-foreground/90 leading-7">
72+
{children}
73+
</div>
74+
</section>
75+
);
76+
}
77+
78+
// --- Framework Tabs Component ---
79+
80+
function FrameworkTabs() {
81+
const [active, setActive] = useState<"react" | "next" | "hugo">("react");
82+
83+
return (
84+
<div className="mt-8 border border-border rounded-xl overflow-hidden bg-card/30">
85+
<div className="flex items-center border-b border-border bg-muted/30">
86+
{[
87+
{ id: "react", label: "React", icon: Zap },
88+
{ id: "next", label: "Next.js", icon: Terminal },
89+
{ id: "hugo", label: "Hugo", icon: Layout },
90+
].map((tab) => {
91+
const Icon = tab.icon; // Get icon component
92+
return (
93+
<button
94+
key={tab.id}
95+
onClick={() => setActive(tab.id as any)}
96+
className={cn(
97+
"flex items-center gap-2 px-6 py-4 text-sm font-medium border-r border-border transition-all hover:bg-muted/50",
98+
active === tab.id
99+
? "bg-card text-primary border-b-2 border-b-primary -mb-px"
100+
: "text-muted-foreground bg-transparent hover:text-foreground"
101+
)}
102+
>
103+
<Icon size={16} />
104+
{tab.label}
105+
</button>
106+
);
107+
})}
108+
</div>
109+
110+
<div className="p-6 bg-card">
111+
{active === "react" && (
112+
<div className="animate-in fade-in duration-300 space-y-4">
113+
<div>
114+
<p className="mb-3 text-sm font-medium text-foreground">1. Add the script to <code>public/index.html</code>:</p>
115+
<CodeBlock code={`<script src="https://commentkit.ankush.one/bundle.js" defer></script>`} />
116+
</div>
117+
<div>
118+
<p className="mb-3 text-sm font-medium text-foreground">2. Render the container in your component:</p>
119+
<CodeBlock language="tsx" code={`export function Comments() {
120+
return <div data-commentkit />;
121+
}`} />
122+
</div>
123+
</div>
124+
)}
125+
126+
{active === "next" && (
127+
<div className="animate-in fade-in duration-300 space-y-4">
128+
<div>
129+
<p className="mb-3 text-sm font-medium text-foreground">1. Add script to <code>app/layout.tsx</code>:</p>
130+
<CodeBlock language="tsx" code={`import Script from 'next/script'
131+
132+
export default function RootLayout({ children }) {
133+
return (
134+
<html lang="en">
135+
<body>
136+
{children}
137+
<Script src="https://commentkit.ankush.one/bundle.js" strategy="lazyOnload" />
138+
</body>
139+
</html>
140+
)
141+
}`} />
142+
</div>
143+
<div>
144+
<p className="mb-3 text-sm font-medium text-foreground">2. Create a client component:</p>
145+
<CodeBlock language="tsx" code={`"use client";
146+
147+
export function Comments() {
148+
return <div data-commentkit />;
149+
}`} />
150+
</div>
151+
</div>
152+
)}
153+
154+
{active === "hugo" && (
155+
<div className="animate-in fade-in duration-300">
156+
<p className="mb-3 text-sm font-medium text-foreground">Add to your partial template (e.g. <code>layouts/partials/comments.html</code>):</p>
157+
<CodeBlock language="html" code={`{{ if not .Params.disableComments }}
158+
<section class="comments">
159+
<div data-commentkit></div>
160+
<script src="https://commentkit.ankush.one/bundle.js" defer></script>
161+
</section>
162+
{{ end }}`} />
163+
</div>
164+
)}
165+
</div>
166+
</div>
167+
);
168+
}
169+
170+
// --- Data ---
171+
172+
const SECTIONS = [
173+
{ id: "introduction", title: "Introduction", icon: BookOpen },
174+
{ id: "installation", title: "Installation", icon: Terminal },
175+
{ id: "frameworks", title: "Frameworks", icon: Layout },
176+
{ id: "api", title: "API Reference", icon: Code2 },
177+
];
178+
179+
export function DocsPage() {
180+
const [activeSection, setActiveSection] = useState("introduction");
181+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
182+
183+
// Handle scroll spy to update active section
184+
React.useEffect(() => {
185+
const observer = new IntersectionObserver(
186+
(entries) => {
187+
entries.forEach((entry) => {
188+
if (entry.isIntersecting) {
189+
setActiveSection(entry.target.id);
190+
}
191+
});
192+
},
193+
{ rootMargin: "-20% 0px -60% 0px" }
194+
);
195+
196+
SECTIONS.forEach(({ id }) => {
197+
const element = document.getElementById(id);
198+
if (element) observer.observe(element);
199+
});
200+
201+
return () => observer.disconnect();
202+
}, []);
203+
204+
const scrollToSection = (id: string) => {
205+
const element = document.getElementById(id);
206+
if (element) {
207+
element.scrollIntoView({ behavior: "smooth" });
208+
setActiveSection(id);
209+
setMobileMenuOpen(false);
210+
}
211+
};
212+
213+
return (
214+
<div className="min-h-screen bg-background text-foreground flex flex-col md:flex-row">
215+
{/* Mobile Header */}
216+
<div className="md:hidden sticky top-0 z-50 bg-background/80 backdrop-blur-md border-b border-border p-4 flex items-center justify-between">
217+
<div className="font-bold text-xl tracking-tight flex items-center gap-2">
218+
<div className="h-8 w-8 rounded-lg bg-primary flex items-center justify-center text-primary-foreground font-bold">
219+
CK
220+
</div>
221+
CommentKit
222+
</div>
223+
<button onClick={() => setMobileMenuOpen(!mobileMenuOpen)}>
224+
{mobileMenuOpen ? <X /> : <Menu />}
225+
</button>
226+
</div>
227+
228+
{/* Sidebar Navigation */}
229+
<aside
230+
className={cn(
231+
"fixed inset-y-0 left-0 z-40 w-64 bg-card border-r border-border transform transition-transform duration-300 ease-in-out md:translate-x-0 md:static md:h-screen md:sticky md:top-0 overflow-y-auto",
232+
mobileMenuOpen ? "translate-x-0" : "-translate-x-full"
233+
)}
234+
>
235+
<div className="p-6">
236+
<div className="hidden md:flex items-center gap-2 mb-8">
237+
<div className="h-8 w-8 rounded-lg bg-primary flex items-center justify-center text-primary-foreground font-bold">
238+
CK
239+
</div>
240+
<span className="font-bold text-xl tracking-tight">CommentKit</span>
241+
</div>
242+
243+
<nav className="space-y-1">
244+
{SECTIONS.map((section) => (
245+
<button
246+
key={section.id}
247+
onClick={() => scrollToSection(section.id)}
248+
className={cn(
249+
"w-full flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-all",
250+
activeSection === section.id
251+
? "bg-primary text-primary-foreground shadow-sm"
252+
: "text-muted-foreground hover:bg-secondary hover:text-foreground"
253+
)}
254+
>
255+
<section.icon size={18} />
256+
{section.title}
257+
</button>
258+
))}
259+
</nav>
260+
261+
<div className="mt-8 pt-8 border-t border-border">
262+
<h4 className="text-xs font-semibold uppercase text-muted-foreground mb-4 tracking-wider">Resources</h4>
263+
<a
264+
href="https://commentkit.ankush.one"
265+
className="flex items-center gap-2 text-sm text-foreground/80 hover:text-primary transition-colors mb-3"
266+
>
267+
<Globe size={16} /> Website
268+
</a>
269+
<a
270+
href="https://github.com/ankushKun/commentkit"
271+
className="flex items-center gap-2 text-sm text-foreground/80 hover:text-primary transition-colors mb-3"
272+
>
273+
<Zap size={16} /> GitHub
274+
</a>
275+
<a
276+
href="https://commentkit.ankush.one/example"
277+
target="_blank"
278+
className="flex items-center gap-2 text-sm text-foreground/80 hover:text-primary transition-colors"
279+
>
280+
<ArrowRight size={16} /> Example Demo
281+
</a>
282+
</div>
283+
</div>
284+
</aside>
285+
286+
{/* Main Content */}
287+
<main className="flex-1 min-w-0">
288+
<div className="max-w-4xl mx-auto px-4 py-12 md:px-12 md:py-16">
289+
290+
<header className="mb-16 animate-in fade-in slide-in-from-bottom-8 duration-700">
291+
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary text-sm font-medium mb-6">
292+
<span className="relative flex h-2 w-2">
293+
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
294+
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
295+
</span>
296+
v1.0.0 Now Available
297+
</div>
298+
<h1 className="text-4xl md:text-6xl font-bold tracking-tight text-foreground mb-6">
299+
Documentation
300+
</h1>
301+
<p className="text-xl text-muted-foreground leading-relaxed max-w-2xl">
302+
Everything you need to integrate CommentKit's powerful threaded/nested comment system into your website.
303+
</p>
304+
</header>
305+
306+
<div className="space-y-24">
307+
308+
{/* Introduction */}
309+
<Section id="introduction" title="Introduction" icon={BookOpen}>
310+
<p className="mb-4">
311+
CommentKit is a privacy-focused, lightweight, and embeddable comment system designed for the modern web.
312+
It provides a seamless commenting experience with features like:
313+
</p>
314+
{/* <ul className="grid md:grid-cols-2 gap-4 mt-6 mb-8 text-sm">
315+
{[
316+
"Infinite nested threading (Reddit-style)",
317+
"Cross-site authentication with Magic Links",
318+
"Markdown support",
319+
"Real-time updates",
320+
"Responsive design focused on Mobile",
321+
"Dark mode support"
322+
].map((item, i) => (
323+
<li key={i} className="flex items-center gap-2 bg-card border border-border p-3 rounded-lg">
324+
<Check size={16} className="text-primary" />
325+
{item}
326+
</li>
327+
))}
328+
</ul> */}
329+
<p>
330+
Whether you're running a static blog, a documentation site, or a full-fledged web app, CommentKit drops in with just a few lines of code.
331+
</p>
332+
</Section>
333+
334+
{/* Installation */}
335+
<Section id="installation" title="Installation" icon={Terminal}>
336+
<p className="mb-6">
337+
Getting started with CommentKit is incredibly simple. It's designed to be <strong>zero-config</strong>.
338+
</p>
339+
340+
<h3 className="text-xl font-semibold text-foreground mb-3 mt-8">1. Add the Script</h3>
341+
<p className="mb-3">
342+
Include the CommentKit bundle in your HTML <code>&lt;head&gt;</code> or just before the closing <code>&lt;/body&gt;</code> tag.
343+
</p>
344+
<CodeBlock code={`<script src="https://commentkit.ankush.one/bundle.js" defer></script>`} />
345+
346+
<h3 className="text-xl font-semibold text-foreground mb-3 mt-8">2. Place the Container</h3>
347+
<p className="mb-3">
348+
Add the container element where you want the comments to appear.
349+
</p>
350+
<CodeBlock code={`<div data-commentkit></div>`} />
351+
352+
<div className="bg-blue-500/5 border border-blue-500/20 p-4 rounded-lg mt-6 flex items-start gap-3">
353+
<div className="p-1 bg-blue-500/10 rounded-full text-blue-500 mt-0.5">
354+
<Zap size={16} />
355+
</div>
356+
<div className="text-sm text-blue-600 dark:text-blue-400">
357+
<strong>Zero Config:</strong> CommentKit automatically identifies the thread using your page URL and title. No extra setup required.
358+
</div>
359+
</div>
360+
</Section>
361+
362+
{/* Configuration */}
363+
{/* Frameworks */}
364+
<Section id="frameworks" title="Framework Integration" icon={Layout}>
365+
<p className="mb-6">
366+
CommentKit works with any framework. Select your framework below for specific integration guides.
367+
</p>
368+
<FrameworkTabs />
369+
</Section>
370+
371+
{/* API Ref */}
372+
<Section id="api" title="API Reference" icon={Code2}>
373+
<div className="flex flex-col items-center justify-center py-12 text-center border border-dashed border-border rounded-lg bg-card/50">
374+
<div className="p-3 bg-secondary rounded-full mb-4">
375+
<Code2 size={32} className="text-muted-foreground" />
376+
</div>
377+
<h3 className="text-xl font-semibold mb-2">Coming Soon</h3>
378+
<p className="text-muted-foreground max-w-sm">
379+
We are working on documenting our REST API. Stay tuned for updates!
380+
</p>
381+
</div>
382+
</Section>
383+
384+
</div>
385+
386+
<footer className="mt-32 pt-12 border-t border-border text-center text-muted-foreground text-sm">
387+
<p>&copy; {new Date().getFullYear()} CommentKit. All rights reserved.</p>
388+
</footer>
389+
390+
</div>
391+
</main>
392+
</div>
393+
);
394+
}

0 commit comments

Comments
 (0)