From 10a317a499e3d9e606f7630a00ee7fdef4bd4d98 Mon Sep 17 00:00:00 2001 From: pheralb Date: Wed, 8 Nov 2023 17:22:30 +0000 Subject: [PATCH] Update docs website + add support for light/dark mode. --- website/contentlayer.config.ts | 73 ++++++++++++ website/{next.config.mjs => next.config.js} | 5 +- website/src/app/docs/[...slug]/page.tsx | 71 ++++++++++++ website/src/app/docs/layout.tsx | 119 ++++++++++++++++++++ website/src/app/layout.tsx | 18 ++- website/src/app/page.tsx | 12 +- website/src/components/cardSpotlight.tsx | 2 +- website/src/components/features.tsx | 10 +- website/src/components/mdx/index.tsx | 15 +++ website/src/components/mode-toggle.tsx | 44 ++++++++ website/src/components/navbar.tsx | 14 ++- website/src/components/socials.tsx | 37 +++--- website/src/providers/theme-provider.tsx | 9 ++ website/src/styles/headings.ts | 1 + website/tsconfig.json | 12 +- 15 files changed, 405 insertions(+), 37 deletions(-) create mode 100644 website/contentlayer.config.ts rename website/{next.config.mjs => next.config.js} (54%) create mode 100644 website/src/app/docs/[...slug]/page.tsx create mode 100644 website/src/app/docs/layout.tsx create mode 100644 website/src/components/mdx/index.tsx create mode 100644 website/src/components/mode-toggle.tsx create mode 100644 website/src/providers/theme-provider.tsx create mode 100644 website/src/styles/headings.ts diff --git a/website/contentlayer.config.ts b/website/contentlayer.config.ts new file mode 100644 index 0000000..bda1c9d --- /dev/null +++ b/website/contentlayer.config.ts @@ -0,0 +1,73 @@ +import type { ComputedFields, FieldDefs } from "contentlayer/source-files"; +import { defineDocumentType, makeSource } from "contentlayer/source-files"; + +// Remark/Rehype extensions: +import rehypeSlug from "rehype-slug"; +import rehypeAutolinkHeadings from "rehype-autolink-headings"; + +// Custom styles: +import { headingStyles } from "./src/styles/headings"; + +// Define a document type: +const computedFields: ComputedFields = { + slug: { + type: "string", + resolve: (doc) => `/${doc._raw.flattenedPath}`, + }, + slugAsParams: { + type: "string", + resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), + }, +}; + +// Shared fields: +const sharedFields: FieldDefs = { + order: { + type: "number", + required: true, + }, + title: { + type: "string", + required: true, + }, + description: { + type: "string", + }, +}; + +// Pages: +export const Page = defineDocumentType(() => ({ + name: "Page", + filePathPattern: `pages/**/*.mdx`, + contentType: "mdx", + fields: sharedFields, + computedFields, +})); + +export const EditorPages = defineDocumentType(() => ({ + name: "EditorPages", + filePathPattern: `editor/**/*.mdx`, + contentType: "mdx", + fields: sharedFields, + computedFields, +})); + +// Create the source: +export default makeSource({ + contentDirPath: "./docs", + documentTypes: [Page, EditorPages], + mdx: { + rehypePlugins: [ + [rehypeSlug], + [ + rehypeAutolinkHeadings, + { + behavior: "wrap", + properties: { + className: [headingStyles], + }, + }, + ], + ], + }, +}); diff --git a/website/next.config.mjs b/website/next.config.js similarity index 54% rename from website/next.config.mjs rename to website/next.config.js index 3688f47..2b78239 100644 --- a/website/next.config.mjs +++ b/website/next.config.js @@ -1,3 +1,6 @@ +const { withContentlayer } = require("next-contentlayer"); + +// Next.js config: /** @type {import('next').NextConfig} */ const nextConfig = { swcMinify: true, @@ -5,4 +8,4 @@ const nextConfig = { transpilePackages: ["@typethings/ui"], }; -export default nextConfig; +module.exports = withContentlayer(nextConfig); diff --git a/website/src/app/docs/[...slug]/page.tsx b/website/src/app/docs/[...slug]/page.tsx new file mode 100644 index 0000000..c57a604 --- /dev/null +++ b/website/src/app/docs/[...slug]/page.tsx @@ -0,0 +1,71 @@ +import { notFound } from "next/navigation"; +import { Metadata } from "next"; +import { allPages } from "contentlayer/generated"; +import { Mdx } from "@/components/mdx"; +import { ProseClasses, cn } from "@typethings/ui"; + +interface PageProps { + params: { + slug: string[]; + }; +} + +async function getPageFromParams(params: PageProps["params"]) { + const slug = params?.slug?.join("/"); + const page = allPages.find((page) => page.slugAsParams === slug); + + if (!page) { + null; + } + + return page; +} + +export async function generateMetadata({ + params, +}: PageProps): Promise { + const page = await getPageFromParams(params); + + if (!page) { + return {}; + } + + return { + title: page.title, + description: page.description, + }; +} + +export async function generateStaticParams(): Promise { + return allPages.map((page) => ({ + slug: page.slugAsParams.split("/"), + })); +} + +export default async function PagePage({ params }: PageProps) { + const page = await getPageFromParams(params); + + if (!page) { + notFound(); + } + + return ( +
+
+

+ {page.title} +

+ {page.description && ( +

{page.description}

+ )} +
+
+ +
+
+ ); +} diff --git a/website/src/app/docs/layout.tsx b/website/src/app/docs/layout.tsx new file mode 100644 index 0000000..88063fa --- /dev/null +++ b/website/src/app/docs/layout.tsx @@ -0,0 +1,119 @@ +"use client"; + +import React from "react"; +import Container from "@/components/container"; +import { + Button, + Collapsible, + CollapsibleContent, + CollapsibleTrigger, + Input, + ProseClasses, + cn, +} from "@typethings/ui"; +import { + ArrowDown, + Book, + ChevronDown, + ChevronUp, + Package, + Rocket, + Search, +} from "lucide-react"; +import { allEditorPages, allPages } from "contentlayer/generated"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +interface iLayoutProps { + children: React.ReactNode; +} + +const Layout = (props: iLayoutProps) => { + const path = usePathname(); + + const groups = [ + { + icon: , + groupName: "App", + pages: allPages, + }, + { + icon: , + groupName: "typethings/editor", + pages: allEditorPages, + }, + ]; + + return ( + <> +
+ +
+
+ + Documentation + +
+
+ + +
+
+
+
+ + {/* Create a grid, the left zone fixed with 300px and second full screen. */} + +
+
+ {props.children} +
+
+
+ + ); +}; + +export default Layout; diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx index 6e2df8e..24e6f6f 100644 --- a/website/src/app/layout.tsx +++ b/website/src/app/layout.tsx @@ -8,6 +8,9 @@ import { cn } from "@typethings/ui"; // Layout: import Navbar from "@/components/navbar"; +// Providers: +import { ThemeProvider } from "@/providers/theme-provider"; + // Metadata: export const metadata: Metadata = { title: { @@ -56,14 +59,21 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - + - - {children} + + + {children} + ); diff --git a/website/src/app/page.tsx b/website/src/app/page.tsx index 134cb25..f36b1f3 100644 --- a/website/src/app/page.tsx +++ b/website/src/app/page.tsx @@ -5,6 +5,7 @@ import Windows from "@/components/icons/windows"; import { Global } from "@/global/data"; import { buttonVariants, cn } from "@typethings/ui"; import { Book } from "lucide-react"; +import Image from "next/image"; import Link from "next/link"; export default function Home() { @@ -18,7 +19,7 @@ export default function Home() { return ( <> -
+
@@ -63,11 +64,14 @@ export default function Home() {
- {/* eslint-disable-next-line @next/next/no-img-element */} - dashboard image
diff --git a/website/src/components/cardSpotlight.tsx b/website/src/components/cardSpotlight.tsx index 050d008..88532cd 100644 --- a/website/src/components/cardSpotlight.tsx +++ b/website/src/components/cardSpotlight.tsx @@ -46,7 +46,7 @@ const CardSpotlight = (props: iCardSpotlight) => { onBlur={handleBlur} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} - className="relative flex overflow-hidden rounded-md border border-neutral-800 p-6" + className="relative flex overflow-hidden rounded-md border dark:border-neutral-800 p-6" >
{ {FeaturesData.map((feature, index) => ( -

+

{feature.title}

{feature.description}

diff --git a/website/src/components/mdx/index.tsx b/website/src/components/mdx/index.tsx new file mode 100644 index 0000000..156b9bf --- /dev/null +++ b/website/src/components/mdx/index.tsx @@ -0,0 +1,15 @@ +import Image from "next/image"; +import { useMDXComponent } from "next-contentlayer/hooks"; + +const components = { + Image, +}; + +interface MdxProps { + code: string; +} + +export function Mdx({ code }: MdxProps) { + const Component = useMDXComponent(code); + return ; +} diff --git a/website/src/components/mode-toggle.tsx b/website/src/components/mode-toggle.tsx new file mode 100644 index 0000000..664dbf2 --- /dev/null +++ b/website/src/components/mode-toggle.tsx @@ -0,0 +1,44 @@ +"use client"; + +import * as React from "react"; +import { MoonIcon, SunIcon } from "lucide-react"; +import { useTheme } from "next-themes"; +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@typethings/ui"; + +export function ModeToggle() { + const { setTheme } = useTheme(); + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); +} diff --git a/website/src/components/navbar.tsx b/website/src/components/navbar.tsx index 756460b..426bd84 100644 --- a/website/src/components/navbar.tsx +++ b/website/src/components/navbar.tsx @@ -5,28 +5,32 @@ import Link from "next/link"; import { buttonVariants } from "@typethings/ui"; import Container from "./container"; import { Global } from "@/global/data"; +import { ModeToggle } from "./mode-toggle"; const Navbar = () => { return (