diff --git a/.gitignore b/.gitignore index fd3dbb5..73123d0 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# bun +bun.lock diff --git a/README.md b/README.md index fbec515..68f4d02 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ **DocuBook** is a documentation web project designed to provide a simple and user-friendly interface for accessing various types of documentation. This site is crafted for developers and teams who need quick access to references, guides, and essential documents. -> **Note**: This application is a fork of [AriaDocs](https://github.com/nisabmohd/Aria-Docs), created by [Nisab Mohd](https://github.com/nisabmohd). DocuBook provides an alternative to the documentation solution found on [Mintlify](https://mintlify.com/), utilizing `.mdx` (Markdown + JSX) for content creation and management. - [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/gitfromwildan/docubook) diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx deleted file mode 100644 index 42951bc..0000000 --- a/app/blog/[slug]/page.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Typography } from "@/components/typography"; -import { buttonVariants } from "@/components/ui/button"; -import { Author, getAllBlogStaticPaths, getBlogForSlug } from "@/lib/markdown"; -import { ArrowLeftIcon } from "lucide-react"; -import Link from "next/link"; -import { notFound } from "next/navigation"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { formatDate } from "@/lib/utils"; -import { ScrollToTop } from "@/components/scroll-to-top"; - -type PageProps = { - params: { slug: string }; -}; - -export async function generateMetadata({ params: { slug } }: PageProps) { - const res = await getBlogForSlug(slug); - if (!res) return null; - const { frontmatter } = res; - return { - title: frontmatter.title, - description: frontmatter.description, - }; -} - -export async function generateStaticParams() { - const val = await getAllBlogStaticPaths(); - if (!val) return []; - return val.map((it) => ({ slug: it })); -} - -export default async function BlogPage({ params: { slug } }: PageProps) { - const res = await getBlogForSlug(slug); - if (!res) notFound(); - return ( -
- - Back to blog - -
-

- {formatDate(res.frontmatter.date)} -

-

- {res.frontmatter.title} -

-
-

Posted by

- -
-
-
- {res.content} -
- -
- ); -} - -function Authors({ authors }: { authors: Author[] }) { - return ( -
- {authors.map((author) => { - return ( - - - - - {author.username.slice(0, 2).toUpperCase()} - - -
-

{author.username}

-

- @{author.handle} -

-
- - ); - })} -
- ); -} diff --git a/app/blog/layout.tsx b/app/blog/layout.tsx deleted file mode 100644 index 6211155..0000000 --- a/app/blog/layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { PropsWithChildren } from "react"; - -export default function BlogLayout({ children }: PropsWithChildren) { - return ( -
- {children} -
- ); -} diff --git a/app/blog/page.tsx b/app/blog/page.tsx deleted file mode 100644 index 567db7c..0000000 --- a/app/blog/page.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Author, BlogMdxFrontmatter, getAllBlogs } from "@/lib/markdown"; -import { formatDate2, stringToDate } from "@/lib/utils"; -import { getMetadata } from "@/app/layout"; -import Image from "next/image"; -import Link from "next/link"; -import { AuroraText } from "@/components/ui/aurora"; -import { ShineBorder } from "@/components/ui/shine-border"; -import docuConfig from "@/docu.json"; - -export const metadata = getMetadata({ - title: "Blog", - description: "Discover the latest updates, tutorials, and insights on DocuBook.", -}); -const { meta } = docuConfig; -export default async function BlogIndexPage() { - const blogs = (await getAllBlogs()).sort( - (a, b) => stringToDate(b.date).getTime() - stringToDate(a.date).getTime() - ); - return ( -
-
- # Stay Informed, Stay Ahead -

- Blog Posts -

-

- Explore updates, tips, and deep dives from the {meta.title}. -

-
-
- {blogs.map((blog) => ( - - ))} -
-
- ); -} - -function BlogCard({ - date, - title, - description, - slug, - cover, - authors, -}: BlogMdxFrontmatter & { slug: string }) { - return ( - -
- {title} -
-
-

{title}

-

{description}

-
-
-

- Published on {formatDate2(date)} -

- -
- - ); -} - -function AvatarGroup({ users, max = 4 }: { users: Author[]; max?: number }) { - const displayUsers = users.slice(0, max); - const remainingUsers = Math.max(users.length - max, 0); - - return ( -
- {displayUsers.map((user, index) => ( - - - - {user.username.slice(0, 2).toUpperCase()} - - - ))} - {remainingUsers > 0 && ( - - +{remainingUsers} - - )} -
- ); -} diff --git a/app/changelog/layout.tsx b/app/changelog/layout.tsx deleted file mode 100644 index b77f34a..0000000 --- a/app/changelog/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export default function ChangelogLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( -
- {children} -
- ); -} \ No newline at end of file diff --git a/app/changelog/page.tsx b/app/changelog/page.tsx deleted file mode 100644 index 0caacf0..0000000 --- a/app/changelog/page.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Suspense } from "react"; -import { getChangelogEntries } from "@/lib/changelog"; -import { VersionEntry } from "@/components/changelog/version-entry"; -import { VersionToc } from "@/components/changelog/version-toc"; -import { FloatingVersionToc } from "@/components/changelog/floating-version"; - -export default async function ChangelogPage() { - const entries = await getChangelogEntries(); - - return ( -
- }> - ({ version, date }))} - /> - - -
-
-
-
- {entries.map((entry, index) => ( -
- -
- ))} -
-
-
- {/* Floating TOC for smaller screens */} - {entries.length > 0 && ( - ({ version, date }))} - /> - )} -
- ); -} diff --git a/app/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx index 7022893..e765173 100644 --- a/app/docs/[[...slug]]/page.tsx +++ b/app/docs/[[...slug]]/page.tsx @@ -8,7 +8,6 @@ import EditThisPage from "@/components/edit-on-github"; import { formatDate2 } from "@/lib/utils"; import docuConfig from "@/docu.json"; import MobToc from "@/components/mob-toc"; -import { ScrollToTop } from "@/components/scroll-to-top"; const { meta } = docuConfig; @@ -78,11 +77,9 @@ export default async function DocsPage({ params: { slug = [] } }: PageProps) { return (
-
+
+ -
- -

{title}

{description}

@@ -101,7 +98,6 @@ export default async function DocsPage({ params: { slug = [] } }: PageProps) {
-
diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx index ef73ca4..d949ff0 100644 --- a/app/docs/layout.tsx +++ b/app/docs/layout.tsx @@ -8,7 +8,9 @@ export default function DocsLayout({ return (
-
{children}
+
+ {children} +
); } diff --git a/app/playground/layout.tsx b/app/playground/layout.tsx deleted file mode 100644 index bd0f70b..0000000 --- a/app/playground/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { PropsWithChildren } from "react"; -import { getMetadata } from "@/app/layout"; - -export const metadata = getMetadata({ - title: "Playground", - description: "Test and experiment with DocuBook markdown components in real-time", - image: "img-playground.png", - }); - -export default function PlaygroundLayout({ children }: PropsWithChildren) { - return ( -
- {children} -
- ); -} diff --git a/app/playground/page.tsx b/app/playground/page.tsx deleted file mode 100644 index 2247a7d..0000000 --- a/app/playground/page.tsx +++ /dev/null @@ -1,395 +0,0 @@ -"use client"; - -import { useState, useEffect, useRef } from "react"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { Separator } from "@/components/ui/separator"; -import { toast } from "sonner"; -import { - List, - ListOrdered, - Heading2, - Heading3, - Code, - Quote, - ImageIcon, - Link as LinkIcon, - Table, - Maximize2, - Minimize2, - Type, - ChevronDown, - Notebook, - Component, - Youtube as YoutubeIcon, - HelpCircle, - LayoutGrid, - MousePointer2, - Rows, - LayoutPanelTop, - Laptop2, - Copy, - Download, - RotateCcw, - Calendar -} from "lucide-react"; -import { Button as UIButton } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { - handleParagraphClick, - handleHeading2Click, - handleHeading3Click, - handleBulletListClick, - handleNumberedListClick, - handleLinkClick, - handleImageClick, - handleBlockquoteClick, - handleCodeBlockClick, - handleTableClick, - handleNoteClick, - handleComponentClick, - handleMetadataClick, - } from "@/components/playground/MarkComponent"; - -import "@/styles/editor.css"; - -const ToolbarButton = ({ icon: Icon, label, onClick }: { icon: any, label: string, onClick?: () => void }) => ( - - - -); - -const ToolbarSeparator = () => ( - -); - -const MobileMessage = () => ( -
- -

Desktop View Recommended

-

- The Playground works best on larger screens. Please switch to a desktop device for the best experience. -

-
-); - -export default function PlaygroundPage() { - const [markdown, setMarkdown] = useState(""); - const [isFullscreen, setIsFullscreen] = useState(false); - const [isMobile, setIsMobile] = useState(false); - const [lineCount, setLineCount] = useState(1); - const editorRef = useRef(null); - const lineNumbersRef = useRef(null); - - useEffect(() => { - const checkMobile = () => { - setIsMobile(window.innerWidth < 768); - }; - - checkMobile(); - window.addEventListener('resize', checkMobile); - - return () => { - window.removeEventListener('resize', checkMobile); - }; - }, []); - - useEffect(() => { - // Update line count when markdown content changes - const lines = markdown.split('\n').length; - setLineCount(Math.max(lines, 1)); - }, [markdown]); - - // Sync scroll position between editor and line numbers - useEffect(() => { - const textarea = editorRef.current; - const lineNumbers = lineNumbersRef.current; - - if (!textarea || !lineNumbers) return; - - const handleScroll = () => { - lineNumbers.scrollTop = textarea.scrollTop; - }; - - textarea.addEventListener('scroll', handleScroll); - return () => textarea.removeEventListener('scroll', handleScroll); - }, []); - - const toggleFullscreen = () => { - setIsFullscreen(!isFullscreen); - }; - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(markdown); - toast.success('Content copied to clipboard'); - } catch (err) { - toast.error('Failed to copy content'); - } - }; - - const handleDownload = () => { - try { - const blob = new Blob([markdown], { type: 'text/markdown' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = 'index.mdx'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - toast.success('Content downloaded successfully'); - } catch (err) { - toast.error('Failed to download content'); - } - }; - - const handleReset = () => { - if (markdown.trim()) { - toast.custom((t) => ( -
-

Clear editor content?

-

This action cannot be undone.

-
- { - setMarkdown(''); - toast.success('all content in the editor has been cleaned'); - toast.dismiss(t); - }} - > - Clear - - toast.dismiss(t)} - > - Cancel - -
-
- ), { duration: 10000 }); - } - }; - - const insertAtCursor = (textArea: HTMLTextAreaElement, text: string) => { - const start = textArea.selectionStart; - const end = textArea.selectionEnd; - const before = markdown.substring(0, start); - const after = markdown.substring(end); - - const needsLeadingNewline = before && !before.endsWith('\n\n') ? '\n\n' : ''; - const needsTrailingNewline = after && !after.startsWith('\n\n') ? '\n\n' : ''; - - const newText = `${before}${needsLeadingNewline}${text}${needsTrailingNewline}${after}`; - setMarkdown(newText); - - requestAnimationFrame(() => { - textArea.focus(); - const newPosition = before.length + needsLeadingNewline.length + text.length + 1; - textArea.setSelectionRange(newPosition, newPosition); - }); - }; - - if (isMobile) { - return ; - } - - return ( -
-
-
-
-

DocuPLAY

-

- Test and experiment with DocuBook markdown components in real-time -

-
-
-
- -
-
- -
-
-
- {markdown.trim() && ( - <> - - - Copy - - - - Download - - - - Reset - - - - )} -
- - {isFullscreen ? ( - <> - - Exit Fullscreen - - ) : ( - <> - - Fullscreen - - )} - -
-
- handleMetadataClick(insertAtCursor)} /> - - handleParagraphClick(insertAtCursor)} /> - handleHeading2Click(insertAtCursor)} /> - handleHeading3Click(insertAtCursor)} /> - handleBulletListClick(insertAtCursor)} /> - handleNumberedListClick(insertAtCursor)} /> - - handleLinkClick(insertAtCursor)} /> - handleImageClick(insertAtCursor)} /> - handleBlockquoteClick(insertAtCursor)} /> - handleCodeBlockClick(insertAtCursor)} /> - handleTableClick(insertAtCursor)} /> - - - - - - - - - - - Note - - - Danger - - - Warning - - - Success - - - - - - - - - - - - - - - Stepper - - - - Card - - - - Button - - - - Accordion - - - - Tabs - - - - Youtube - - - - Tooltip - - - -
-
-
-
-
- {Array.from({ length: lineCount }).map((_, i) => ( -
- ))} -
-
-