diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ab7a1da --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Mohd. Nisab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx new file mode 100644 index 0000000..0150741 --- /dev/null +++ b/app/blog/[slug]/page.tsx @@ -0,0 +1,100 @@ +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 Image from "next/image"; + +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

+ +
+
+
+
+ cover +
+ {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 new file mode 100644 index 0000000..6211155 --- /dev/null +++ b/app/blog/layout.tsx @@ -0,0 +1,9 @@ +import { PropsWithChildren } from "react"; + +export default function BlogLayout({ children }: PropsWithChildren) { + return ( +
+ {children} +
+ ); +} diff --git a/app/blog/page.tsx b/app/blog/page.tsx new file mode 100644 index 0000000..7202d2c --- /dev/null +++ b/app/blog/page.tsx @@ -0,0 +1,96 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Author, BlogMdxFrontmatter, getAllBlogs } from "@/lib/markdown"; +import { formatDate2, stringToDate } from "@/lib/utils"; +import { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; + +export const metadata: Metadata = { + title: "AriaDocs - Blog", +}; + +export default async function BlogIndexPage() { + const blogs = (await getAllBlogs()).sort( + (a, b) => stringToDate(b.date).getTime() - stringToDate(a.date).getTime() + ); + return ( +
+
+

+ The latest blogs of this product +

+

+ All the latest blogs and news, straight from the team. +

+
+
+ {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/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..07c3dd8 --- /dev/null +++ b/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,51 @@ +import DocsBreadcrumb from "@/components/docs-breadcrumb"; +import Pagination from "@/components/pagination"; +import Toc from "@/components/toc"; +import { page_routes } from "@/lib/routes-config"; +import { notFound } from "next/navigation"; +import { getDocsForSlug } from "@/lib/markdown"; +import { Typography } from "@/components/typography"; + +type PageProps = { + params: { slug: string[] }; +}; + +export default async function DocsPage({ params: { slug = [] } }: PageProps) { + const pathName = slug.join("/"); + const res = await getDocsForSlug(pathName); + + if (!res) notFound(); + return ( +
+
+ + +

{res.frontmatter.title}

+

+ {res.frontmatter.description} +

+
{res.content}
+ +
+
+ +
+ ); +} + +export async function generateMetadata({ params: { slug = [] } }: PageProps) { + const pathName = slug.join("/"); + const res = await getDocsForSlug(pathName); + if (!res) return null; + const { frontmatter } = res; + return { + title: frontmatter.title, + description: frontmatter.description, + }; +} + +export function generateStaticParams() { + return page_routes.map((item) => ({ + slug: item.href.split("/").slice(1), + })); +} diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx new file mode 100644 index 0000000..ef73ca4 --- /dev/null +++ b/app/docs/layout.tsx @@ -0,0 +1,14 @@ +import { Leftbar } from "@/components/leftbar"; + +export default function DocsLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( +
+ +
{children}
+
+ ); +} diff --git a/app/error.tsx b/app/error.tsx new file mode 100644 index 0000000..8a8ae0b --- /dev/null +++ b/app/error.tsx @@ -0,0 +1,44 @@ +"use client"; // Error components must be Client Components + +import { Button, buttonVariants } from "@/components/ui/button"; +import Link from "next/link"; +import { useEffect } from "react"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + console.error(error); + }, [error]); + + return ( +
+
+

Oops!

+

+ Something went wrong {":`("} +

+

+ We're sorry, but an error occurred while processing your request. +

+
+
+ + + Back to homepage + +
+
+ ); +} diff --git a/app/favicon.ico b/app/favicon.ico new file mode 100644 index 0000000..56276eb Binary files /dev/null and b/app/favicon.ico differ diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..9d9cc07 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,45 @@ +import type { Metadata } from "next"; +import { ThemeProvider } from "@/components/contexts/theme-provider"; +import { Navbar } from "@/components/navbar"; +import { GeistSans } from "geist/font/sans"; +import { GeistMono } from "geist/font/mono"; +import { Footer } from "@/components/footer"; +import "@/styles/globals.css"; + +export const metadata: Metadata = { + title: "Comparit", + // metadataBase: new URL("https://ariadocs.vercel.app/"), + description: + "An IDE Agnostic Model Comparison Tool.", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + + + +
+ {children} +
+ {/*