Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 11 additions & 35 deletions docs/suspensive.org/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,40 +1,16 @@
import { recmaCodeHike, remarkCodeHike } from 'codehike/mdx'
import nextra from 'nextra'
import { remarkSandpack } from 'remark-sandpack'

/** @type {import('codehike/mdx').CodeHikeConfig} */
const chConfig = {
syntaxHighlighting: {
theme: 'github-dark',
},
}

const withNextra = nextra({
defaultShowCopyCode: true,
latex: true,
mdxOptions: {
remarkPlugins: [[remarkCodeHike, chConfig], remarkSandpack],
recmaPlugins: [[recmaCodeHike, chConfig]],
rehypePlugins: [],
rehypePrettyCodeOptions: {
theme: 'github-dark-default',
keepBackground: false,
},
},
search: {
codeblocks: true,
},
codeHighlight: true,
readingTime: true,
})

/**
* @type {import('next').NextConfig}
*/
export default withNextra({
export default {
reactStrictMode: true,
i18n: {
locales: ['en', 'ko'],
defaultLocale: 'en',
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
webpack: (config) => {
// Add support for importing MDX files
config.resolve.extensionAlias = {
'.js': ['.ts', '.tsx', '.js', '.jsx'],
'.mjs': ['.mts', '.mjs'],
'.cjs': ['.cts', '.cjs'],
}
return config
},
})
}
8 changes: 6 additions & 2 deletions docs/suspensive.org/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
"start": "next start -p 4000"
},
"dependencies": {
"@chevrotain/regexp-to-ast": "^11.0.3",
"@codesandbox/sandpack-react": "^2.20.0",
"@next/third-parties": "^15.5.6",
"@radix-ui/react-dialog": "^1.1.3",
"@radix-ui/react-dropdown-menu": "^2.1.3",
"@suspensive/react": "workspace:*",
"@suspensive/react-query-4": "workspace:*",
"@tanstack/react-query": "catalog:react-query4",
Expand All @@ -34,10 +37,11 @@
"lucide-react": "^0.553.0",
"motion": "^12.23.24",
"next": "^15.5.6",
"nextra": "^4.6.0",
"nextra-theme-docs": "^4.6.0",
"next-mdx-remote": "^5.0.0",
"next-themes": "^0.4.4",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"rehype-pretty-code": "^0.14.1",
"remark-sandpack": "^0.0.5",
"sharp": "catalog:",
"zod": "^3.25.47"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
'use client'

import type { $NextraMetadata, Heading } from 'nextra'
import { type ReactNode } from 'react'
import { FadeIn } from './FadeIn'
import { useMDXComponents as getMDXComponents } from '@/mdx-components'

export type TOCItem = {
depth: number
value: string
id: string
}

type MDXContentProps = {
toc: Array<Heading>
toc: TOCItem[]
sourceCode: string
metadata: $NextraMetadata
metadata: any
isIndexPage: boolean
mdxPath: string[]
children: ReactNode
Expand Down
87 changes: 60 additions & 27 deletions docs/suspensive.org/src/app/[lang]/[[...mdxPath]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,79 @@
import type { $NextraMetadata, Heading } from 'nextra'
import { generateStaticParamsFor, importPage } from 'nextra/pages'
import type { Metadata } from 'next'
import { MDXContent } from './MDXContent'

type Page = {
toc: Array<Heading>
metadata: $NextraMetadata
default: React.ComponentType<{ params: Awaited<PageProps['params']> }>
sourceCode: string
}
import { DocsLayout } from '@/components/layout'
import { getAllMdxFiles, getMdxContent } from '@/lib/mdx'
import { getPageMap } from '@/lib/page-map'

type PageParams = {
mdxPath: string[]
lang: string
mdxPath?: string[]
lang: 'en' | 'ko'
}

type PageProps = Readonly<{
params: Promise<PageParams>
}>

export const generateStaticParams = generateStaticParamsFor('mdxPath')
export async function generateStaticParams(): Promise<
{ mdxPath: string[]; lang: string }[]
> {
const locales = ['en', 'ko']
const params: { mdxPath: string[]; lang: string }[] = []

for (const lang of locales) {
const paths = await getAllMdxFiles(lang)
for (const mdxPath of paths) {
params.push({ mdxPath, lang })
}
}

export async function generateMetadata(props: PageProps) {
return params
}

export async function generateMetadata(props: PageProps): Promise<Metadata> {
const params = await props.params
const page = (await importPage(params.mdxPath, params.lang)) as Page
return page.metadata
const { lang, mdxPath = [] } = params

const content = await getMdxContent(lang, mdxPath)

if (!content) {
return {
title: 'Not Found',
}
}

const title = (content.frontmatter as any)?.title || 'Suspensive'

return {
title,
}
}

export default async function Page(props: PageProps) {
const params = await props.params
const page = (await importPage(params.mdxPath, params.lang)) as Page
const Content = page.default
const isIndexPage = page.metadata.filePath.includes('index.mdx')
const { lang, mdxPath = [] } = params

const content = await getMdxContent(lang, mdxPath)
const pageMap = getPageMap(lang)

if (!content) {
return <div>Page not found</div>
}

const isIndexPage =
mdxPath.length === 0 || mdxPath[mdxPath.length - 1] === 'index'
const currentPath = `/${lang}${mdxPath.length > 0 ? `/${mdxPath.join('/')}` : ''}`

return (
<MDXContent
toc={page.toc}
sourceCode={page.sourceCode}
metadata={page.metadata}
isIndexPage={isIndexPage}
mdxPath={params.mdxPath}
>
<Content params={params} />
</MDXContent>
<DocsLayout pageMap={pageMap} toc={content.toc} currentPath={currentPath}>
<MDXContent
toc={content.toc}
sourceCode={content.sourceCode}
metadata={content.frontmatter}
isIndexPage={isIndexPage}
mdxPath={mdxPath}
>
{content.content}
</MDXContent>
</DocsLayout>
)
}
9 changes: 3 additions & 6 deletions docs/suspensive.org/src/app/[lang]/_components/Logo.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
'use client'

import { useIsClient } from '@suspensive/react'
import { motion } from 'motion/react'
import { useTheme } from 'nextra-theme-docs'
import { useTheme } from 'next-themes'

export const Logo = () => {
const { resolvedTheme } = useTheme()

const isClient = useIsClient()

return isClient ? (
return (
<motion.div>
<div className="relative flex items-center gap-1">
<svg
Expand All @@ -29,5 +26,5 @@ export const Logo = () => {
<span className="absolute -top-1 -right-3 text-[8px]">v3</span>
</div>
</motion.div>
) : null
)
}
79 changes: 25 additions & 54 deletions docs/suspensive.org/src/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,13 @@ import { GoogleAnalytics, GoogleTagManager } from '@next/third-parties/google'
import { ClientOnly } from '@suspensive/react'
import type { Metadata } from 'next'
import Script from 'next/script'
import { Head, Search } from 'nextra/components'
import { getPageMap } from 'nextra/page-map'
import {
Footer,
LastUpdated,
Layout,
LocaleSwitch,
Navbar,
} from 'nextra-theme-docs'
import { ThemeProvider } from 'next-themes'
import type { ReactNode } from 'react'
import { getDictionary, getDirection } from '../_dictionaries/get-dictionary'
import './styles.css'
import { Logo } from './_components/Logo'
import { Footer, LocaleSwitch, Navbar, Search } from '@/components/layout'
import { SandPackCSS } from '@/components/Sandpack/SandPackCSS'
import { STORAGE_KEYS } from '@/constants'

export const metadata = {
title: {
Expand All @@ -40,58 +32,37 @@ export default async function RootLayout({
}) {
const { lang } = await params
const dictionary = await getDictionary(lang)
const pageMap = await getPageMap(lang)

return (
<html lang={lang} dir={getDirection(lang)} suppressHydrationWarning>
<Head backgroundColor={{ dark: 'rgb(0,0,0)' }}>
<head>
<meta name="theme-color" content="rgb(0,0,0)" />
<ClientOnly>
<SandPackCSS />
</ClientOnly>
</Head>
</head>
<body>
<Layout
darkMode
search={<Search placeholder={dictionary.search.placeholder} />}
navbar={
<Navbar
logo={<Logo />}
projectLink="https://github.com/toss/suspensive"
chatLink="https://discord.gg/RFcR9WWmCH"
>
<LocaleSwitch />
</Navbar>
}
footer={
<Footer>
MIT {new Date().getFullYear()} © Viva Republica, Inc.
</Footer>
}
docsRepositoryBase="https://github.com/toss/suspensive/tree/main/docs/suspensive.org"
i18n={[
{ locale: 'en', name: 'English' },
{ locale: 'ko', name: '한국어' },
]}
sidebar={{
defaultMenuCollapseLevel: 2,
autoCollapse: true,
toggleButton: true,
}}
toc={{
...dictionary.toc,
float: true,
}}
editLink={dictionary.editPage}
pageMap={pageMap}
nextThemes={{
defaultTheme: 'system',
storageKey: STORAGE_KEYS.THEME,
}}
feedback={{ content: '' }}
lastUpdated={<LastUpdated>{dictionary.lastUpdated}</LastUpdated>}
<ThemeProvider
attribute="class"
defaultTheme={'system'}
storageKey={'theme'}
enableSystem
>
{children}
</Layout>
<Navbar
logo={<Logo />}
projectLink="https://github.com/toss/suspensive"
chatLink="https://discord.gg/RFcR9WWmCH"
search={<Search placeholder={dictionary.search.placeholder} />}
>
<LocaleSwitch
locales={[
{ locale: 'en', name: 'English' },
{ locale: 'ko', name: '한국어' },
]}
/>
</Navbar>
<div className="min-h-screen">{children}</div>
</ThemeProvider>
<GoogleTagManager gtmId="G-NYQZGKRL0Y" />
<GoogleAnalytics gaId="G-NYQZGKRL0Y" />
<ClientOnly>
Expand Down
4 changes: 3 additions & 1 deletion docs/suspensive.org/src/app/[lang]/not-found.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { NotFoundPage as default } from 'nextra-theme-docs'
'use client'

export { default } from 'next/error'
Loading
Loading