create-unmint 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +57 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +499 -0
  4. package/package.json +48 -0
  5. package/template/LICENSE +21 -0
  6. package/template/README.md +278 -0
  7. package/template/__tests__/components/callout.test.tsx +46 -0
  8. package/template/__tests__/components/card.test.tsx +59 -0
  9. package/template/__tests__/components/tabs.test.tsx +61 -0
  10. package/template/__tests__/theme-config.test.ts +49 -0
  11. package/template/__tests__/utils.test.ts +25 -0
  12. package/template/app/api/og/route.tsx +90 -0
  13. package/template/app/api/search/route.ts +6 -0
  14. package/template/app/components/docs/docs-pager.tsx +41 -0
  15. package/template/app/components/docs/docs-sidebar.tsx +143 -0
  16. package/template/app/components/docs/docs-toc.tsx +61 -0
  17. package/template/app/components/docs/mdx/accordion.tsx +54 -0
  18. package/template/app/components/docs/mdx/callout.tsx +102 -0
  19. package/template/app/components/docs/mdx/card.tsx +110 -0
  20. package/template/app/components/docs/mdx/code-block.tsx +42 -0
  21. package/template/app/components/docs/mdx/frame.tsx +14 -0
  22. package/template/app/components/docs/mdx/index.tsx +167 -0
  23. package/template/app/components/docs/mdx/pre.tsx +82 -0
  24. package/template/app/components/docs/mdx/steps.tsx +59 -0
  25. package/template/app/components/docs/mdx/tabs.tsx +60 -0
  26. package/template/app/components/docs/mdx/youtube.tsx +18 -0
  27. package/template/app/components/docs/search-dialog.tsx +281 -0
  28. package/template/app/components/docs/theme-toggle.tsx +35 -0
  29. package/template/app/docs/[[...slug]]/page.tsx +139 -0
  30. package/template/app/docs/layout.tsx +98 -0
  31. package/template/app/globals.css +151 -0
  32. package/template/app/layout.tsx +33 -0
  33. package/template/app/page.tsx +5 -0
  34. package/template/app/providers/theme-provider.tsx +8 -0
  35. package/template/content/docs/components.mdx +82 -0
  36. package/template/content/docs/customization.mdx +34 -0
  37. package/template/content/docs/deployment.mdx +28 -0
  38. package/template/content/docs/index.mdx +91 -0
  39. package/template/content/docs/meta.json +13 -0
  40. package/template/content/docs/quickstart.mdx +110 -0
  41. package/template/content/docs/theming.mdx +41 -0
  42. package/template/lib/docs-source.ts +7 -0
  43. package/template/lib/theme-config.ts +89 -0
  44. package/template/lib/utils.ts +6 -0
  45. package/template/next.config.mjs +10 -0
  46. package/template/package-lock.json +10695 -0
  47. package/template/package.json +45 -0
  48. package/template/postcss.config.mjs +7 -0
  49. package/template/public/logo.png +0 -0
  50. package/template/public/logo.svg +9 -0
  51. package/template/public/logo.txt +1 -0
  52. package/template/source.config.ts +22 -0
  53. package/template/tailwind.config.ts +34 -0
  54. package/template/tsconfig.json +33 -0
  55. package/template/vitest.config.ts +16 -0
@@ -0,0 +1,35 @@
1
+ 'use client'
2
+
3
+ import { useTheme } from 'next-themes'
4
+ import { useEffect, useState } from 'react'
5
+
6
+ export function ThemeToggle() {
7
+ const { theme, setTheme } = useTheme()
8
+ const [mounted, setMounted] = useState(false)
9
+
10
+ useEffect(() => {
11
+ setMounted(true)
12
+ }, [])
13
+
14
+ if (!mounted) {
15
+ return <div className="w-9 h-9" />
16
+ }
17
+
18
+ return (
19
+ <button
20
+ onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
21
+ className="flex items-center justify-center w-9 h-9 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
22
+ aria-label="Toggle theme"
23
+ >
24
+ {theme === 'dark' ? (
25
+ <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
26
+ <path strokeLinecap="round" strokeLinejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
27
+ </svg>
28
+ ) : (
29
+ <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
30
+ <path strokeLinecap="round" strokeLinejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
31
+ </svg>
32
+ )}
33
+ </button>
34
+ )
35
+ }
@@ -0,0 +1,139 @@
1
+ import { source } from '@/lib/docs-source'
2
+ import { notFound } from 'next/navigation'
3
+ import { DocsTOC } from '../../components/docs/docs-toc'
4
+ import { DocsPager } from '../../components/docs/docs-pager'
5
+ import { getMDXComponents } from '../../components/docs/mdx'
6
+ import { findNeighbour } from 'fumadocs-core/page-tree'
7
+ import type { Metadata } from 'next'
8
+ import type { Root, Node } from 'fumadocs-core/page-tree'
9
+ import { siteConfig, themeConfig } from '@/lib/theme-config'
10
+
11
+ interface PageProps {
12
+ params: Promise<{ slug?: string[] }>
13
+ }
14
+
15
+ // Find the section separator that precedes this page in the tree
16
+ function findSectionName(tree: Root, pageUrl: string): string {
17
+ let lastSeparator = 'Documentation'
18
+
19
+ function traverse(nodes: Node[]): string | null {
20
+ for (const node of nodes) {
21
+ if (node.type === 'separator') {
22
+ // node.name can be ReactNode, convert to string safely
23
+ lastSeparator = typeof node.name === 'string' ? node.name : 'Documentation'
24
+ } else if (node.type === 'page' && node.url === pageUrl) {
25
+ return lastSeparator
26
+ } else if (node.type === 'folder' && node.children) {
27
+ const result = traverse(node.children)
28
+ if (result) return result
29
+ }
30
+ }
31
+ return null
32
+ }
33
+
34
+ return traverse(tree.children) || lastSeparator
35
+ }
36
+
37
+ export default async function DocsPage({ params }: PageProps) {
38
+ const { slug } = await params
39
+ const page = source.getPage(slug)
40
+
41
+ if (!page) notFound()
42
+
43
+ const MDXContent = page.data.body
44
+ const toc = page.data.toc
45
+
46
+ // Get prev/next navigation using fumadocs utility
47
+ const tree = source.pageTree
48
+ const neighbours = findNeighbour(tree, page.url)
49
+
50
+ // Find section name for the header banner
51
+ const sectionName = findSectionName(tree, page.url)
52
+
53
+ return (
54
+ <div className="flex gap-8">
55
+ {/* Main content */}
56
+ <article className="flex-1 min-w-0 max-w-3xl">
57
+ {/* Header banner */}
58
+ <header className="mb-8 pb-6 border-b border-border">
59
+ <p className="text-sm text-[var(--accent)] font-medium mb-2">
60
+ {sectionName}
61
+ </p>
62
+ <h1 className="text-3xl font-bold text-foreground">
63
+ {page.data.title}
64
+ </h1>
65
+ {page.data.description && (
66
+ <p className="mt-3 text-base text-muted-foreground">
67
+ {page.data.description}
68
+ </p>
69
+ )}
70
+ </header>
71
+
72
+ {/* MDX content */}
73
+ <div className="prose prose-slate dark:prose-invert max-w-none">
74
+ <MDXContent components={getMDXComponents()} />
75
+ </div>
76
+
77
+ <DocsPager
78
+ previous={neighbours.previous ? {
79
+ name: typeof neighbours.previous.name === 'string' ? neighbours.previous.name : 'Previous',
80
+ url: neighbours.previous.url
81
+ } : undefined}
82
+ next={neighbours.next ? {
83
+ name: typeof neighbours.next.name === 'string' ? neighbours.next.name : 'Next',
84
+ url: neighbours.next.url
85
+ } : undefined}
86
+ />
87
+ </article>
88
+
89
+ {/* Table of contents */}
90
+ <DocsTOC toc={toc} />
91
+ </div>
92
+ )
93
+ }
94
+
95
+ export async function generateStaticParams() {
96
+ return source.generateParams()
97
+ }
98
+
99
+ export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
100
+ const { slug } = await params
101
+ const page = source.getPage(slug)
102
+
103
+ if (!page) return {}
104
+
105
+ const tree = source.pageTree
106
+ const section = findSectionName(tree, page.url)
107
+ const title = page.data.title
108
+ const description = page.data.description
109
+
110
+ // Build OG image URL with query params
111
+ const ogImageUrl = new URL(`${siteConfig.url}/api/og`)
112
+ ogImageUrl.searchParams.set('title', title)
113
+ ogImageUrl.searchParams.set('section', section)
114
+
115
+ return {
116
+ title,
117
+ description,
118
+ openGraph: {
119
+ title,
120
+ description,
121
+ type: 'article',
122
+ url: `${siteConfig.url}${page.url}`,
123
+ images: [
124
+ {
125
+ url: ogImageUrl.toString(),
126
+ width: 1200,
127
+ height: 630,
128
+ alt: title,
129
+ },
130
+ ],
131
+ },
132
+ twitter: {
133
+ card: 'summary_large_image',
134
+ title,
135
+ description,
136
+ images: [ogImageUrl.toString()],
137
+ },
138
+ }
139
+ }
@@ -0,0 +1,98 @@
1
+ import Link from 'next/link'
2
+ import Image from 'next/image'
3
+ import { source } from '@/lib/docs-source'
4
+ import { DocsSidebar } from '../components/docs/docs-sidebar'
5
+ import { SearchTrigger } from '../components/docs/search-dialog'
6
+ import { ThemeToggle } from '../components/docs/theme-toggle'
7
+ import { siteConfig } from '@/lib/theme-config'
8
+
9
+ export default function DocsLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode
13
+ }) {
14
+ const tree = source.pageTree
15
+
16
+ return (
17
+ <div className="min-h-screen flex flex-col">
18
+ {/* Header */}
19
+ <header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
20
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
21
+ <div className="flex h-16 items-center justify-between">
22
+ {/* Logo */}
23
+ <Link href="/" className="flex items-center gap-2">
24
+ {siteConfig.logo.src && (
25
+ <Image
26
+ src={siteConfig.logo.src}
27
+ alt={siteConfig.logo.alt}
28
+ width={siteConfig.logo.width}
29
+ height={siteConfig.logo.height}
30
+ className="dark:invert"
31
+ />
32
+ )}
33
+ <span className="font-semibold text-lg">{siteConfig.name}</span>
34
+ </Link>
35
+
36
+ {/* Center: Search */}
37
+ <div className="flex-1 flex justify-center px-4">
38
+ <SearchTrigger />
39
+ </div>
40
+
41
+ {/* Right: Links */}
42
+ <div className="flex items-center gap-2">
43
+ {siteConfig.links.github && (
44
+ <a
45
+ href={siteConfig.links.github}
46
+ target="_blank"
47
+ rel="noopener noreferrer"
48
+ className="p-2 text-muted-foreground hover:text-foreground transition-colors"
49
+ >
50
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
51
+ <path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd" />
52
+ </svg>
53
+ </a>
54
+ )}
55
+ <ThemeToggle />
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </header>
60
+
61
+ {/* Main content */}
62
+ <div className="flex-1">
63
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
64
+ <div className="flex gap-8">
65
+ <DocsSidebar tree={tree} />
66
+ <main className="flex-1 min-w-0">
67
+ {children}
68
+ </main>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ {/* Footer */}
74
+ <footer className="border-t border-border py-8">
75
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
76
+ <div className="flex flex-col sm:flex-row justify-between items-center gap-4">
77
+ <p className="text-sm text-muted-foreground">
78
+ {siteConfig.footer.copyright}
79
+ </p>
80
+ <div className="flex gap-4">
81
+ {siteConfig.footer.links.map((link) => (
82
+ <a
83
+ key={link.href}
84
+ href={link.href}
85
+ target="_blank"
86
+ rel="noopener noreferrer"
87
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors"
88
+ >
89
+ {link.label}
90
+ </a>
91
+ ))}
92
+ </div>
93
+ </div>
94
+ </div>
95
+ </footer>
96
+ </div>
97
+ )
98
+ }
@@ -0,0 +1,151 @@
1
+ @import 'tailwindcss';
2
+
3
+ @custom-variant dark (&:is(.dark *));
4
+
5
+ @theme inline {
6
+ --color-background: var(--background);
7
+ --color-foreground: var(--foreground);
8
+ --color-card: var(--card);
9
+ --color-card-foreground: var(--card-foreground);
10
+ --color-popover: var(--popover);
11
+ --color-popover-foreground: var(--popover-foreground);
12
+ --color-primary: var(--primary);
13
+ --color-primary-foreground: var(--primary-foreground);
14
+ --color-secondary: var(--secondary);
15
+ --color-secondary-foreground: var(--secondary-foreground);
16
+ --color-muted: var(--muted);
17
+ --color-muted-foreground: var(--muted-foreground);
18
+ --color-accent: var(--accent);
19
+ --color-accent-foreground: var(--accent-foreground);
20
+ --color-destructive: var(--destructive);
21
+ --color-border: var(--border);
22
+ --color-input: var(--input);
23
+ --color-ring: var(--ring);
24
+ --font-sans: 'Inter', system-ui, sans-serif;
25
+ --font-mono: 'Fira Code', ui-monospace, monospace;
26
+ --radius-sm: calc(var(--radius) - 4px);
27
+ --radius-md: calc(var(--radius) - 2px);
28
+ --radius-lg: var(--radius);
29
+ --radius-xl: calc(var(--radius) + 4px);
30
+ }
31
+
32
+ :root {
33
+ --radius: 0.625rem;
34
+ --background: oklch(1 0 0);
35
+ --foreground: oklch(0.145 0 0);
36
+ --card: oklch(1 0 0);
37
+ --card-foreground: oklch(0.145 0 0);
38
+ --popover: oklch(1 0 0);
39
+ --popover-foreground: oklch(0.145 0 0);
40
+ --primary: oklch(0.205 0 0);
41
+ --primary-foreground: oklch(0.985 0 0);
42
+ --secondary: oklch(0.97 0 0);
43
+ --secondary-foreground: oklch(0.205 0 0);
44
+ --muted: oklch(0.97 0 0);
45
+ --muted-foreground: oklch(0.556 0 0);
46
+ --destructive: oklch(0.577 0.245 27.325);
47
+ --border: oklch(0.922 0 0);
48
+ --input: oklch(0.922 0 0);
49
+ --ring: oklch(0.708 0 0);
50
+
51
+ /* Brand accent colors - customize these for your brand */
52
+ --accent: #0891b2;
53
+ --accent-foreground: #ffffff;
54
+ --accent-muted: rgba(8, 145, 178, 0.1);
55
+ }
56
+
57
+ .dark {
58
+ --background: oklch(0.145 0 0);
59
+ --foreground: oklch(0.985 0 0);
60
+ --card: oklch(0.205 0 0);
61
+ --card-foreground: oklch(0.985 0 0);
62
+ --popover: oklch(0.205 0 0);
63
+ --popover-foreground: oklch(0.985 0 0);
64
+ --primary: oklch(0.922 0 0);
65
+ --primary-foreground: oklch(0.205 0 0);
66
+ --secondary: oklch(0.269 0 0);
67
+ --secondary-foreground: oklch(0.985 0 0);
68
+ --muted: oklch(0.269 0 0);
69
+ --muted-foreground: oklch(0.708 0 0);
70
+ --destructive: oklch(0.704 0.191 22.216);
71
+ --border: oklch(1 0 0 / 10%);
72
+ --input: oklch(1 0 0 / 15%);
73
+ --ring: oklch(0.556 0 0);
74
+
75
+ /* Brand accent colors - brighter for dark mode */
76
+ --accent: #22d3ee;
77
+ --accent-foreground: #0f172a;
78
+ --accent-muted: rgba(34, 211, 238, 0.1);
79
+ }
80
+
81
+ @layer base {
82
+ * {
83
+ @apply border-border outline-ring/50;
84
+ }
85
+ body {
86
+ @apply bg-background text-foreground;
87
+ }
88
+ }
89
+
90
+ /* Syntax highlighting - Shiki integration */
91
+ pre {
92
+ overflow-x: auto;
93
+ padding: 1rem;
94
+ border-radius: 0.5rem;
95
+ }
96
+
97
+ pre code {
98
+ display: block;
99
+ min-width: max-content;
100
+ background: transparent !important;
101
+ border: none !important;
102
+ padding: 1rem !important;
103
+ margin: 0 !important;
104
+ border-radius: 0 !important;
105
+ color: inherit !important;
106
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
107
+ }
108
+
109
+ code {
110
+ font-family: var(--font-mono);
111
+ }
112
+
113
+ /* Shiki dual-theme support */
114
+ pre code span {
115
+ color: var(--shiki-light);
116
+ }
117
+
118
+ .dark pre code span {
119
+ color: var(--shiki-dark);
120
+ }
121
+
122
+ /* Code block line highlighting */
123
+ pre code [data-highlighted-line] {
124
+ background-color: rgba(0, 0, 0, 0.05);
125
+ display: block;
126
+ margin: 0 -1rem;
127
+ padding: 0 1rem;
128
+ }
129
+
130
+ .dark pre code [data-highlighted-line] {
131
+ background-color: rgba(255, 255, 255, 0.05);
132
+ }
133
+
134
+ /* Scrollbar styling */
135
+ ::-webkit-scrollbar {
136
+ width: 8px;
137
+ height: 8px;
138
+ }
139
+
140
+ ::-webkit-scrollbar-track {
141
+ background: transparent;
142
+ }
143
+
144
+ ::-webkit-scrollbar-thumb {
145
+ background: oklch(0.556 0 0 / 0.3);
146
+ border-radius: 4px;
147
+ }
148
+
149
+ ::-webkit-scrollbar-thumb:hover {
150
+ background: oklch(0.556 0 0 / 0.5);
151
+ }
@@ -0,0 +1,33 @@
1
+ import type { Metadata } from 'next'
2
+ import { ThemeProvider } from './providers/theme-provider'
3
+ import { siteConfig } from '@/lib/theme-config'
4
+ import './globals.css'
5
+
6
+ export const metadata: Metadata = {
7
+ title: {
8
+ default: siteConfig.name,
9
+ template: `%s | ${siteConfig.name}`,
10
+ },
11
+ description: siteConfig.description,
12
+ }
13
+
14
+ export default function RootLayout({
15
+ children,
16
+ }: {
17
+ children: React.ReactNode
18
+ }) {
19
+ return (
20
+ <html lang="en" suppressHydrationWarning>
21
+ <body>
22
+ <ThemeProvider
23
+ attribute="class"
24
+ defaultTheme="system"
25
+ enableSystem
26
+ disableTransitionOnChange
27
+ >
28
+ {children}
29
+ </ThemeProvider>
30
+ </body>
31
+ </html>
32
+ )
33
+ }
@@ -0,0 +1,5 @@
1
+ import { redirect } from 'next/navigation'
2
+
3
+ export default function Home() {
4
+ redirect('/docs')
5
+ }
@@ -0,0 +1,8 @@
1
+ 'use client'
2
+
3
+ import { ThemeProvider as NextThemesProvider } from 'next-themes'
4
+ import type { ThemeProviderProps } from 'next-themes'
5
+
6
+ export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
7
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
8
+ }
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: Components
3
+ description: Pre-built MDX components for beautiful documentation
4
+ ---
5
+
6
+ Unmint includes a rich set of MDX components that you can use in your documentation pages.
7
+
8
+ ## Cards
9
+
10
+ Use cards to highlight links or features:
11
+
12
+ <CardGroup cols={2}>
13
+ <Card title="Quick Start" icon="rocket" href="/docs/quickstart">
14
+ Get started in under 5 minutes
15
+ </Card>
16
+ <Card title="Components" icon="code" href="/docs/components">
17
+ Explore available components
18
+ </Card>
19
+ </CardGroup>
20
+
21
+ ### Available Icons
22
+
23
+ Cards support these built-in icons: `rocket`, `code`, `book`, `gear`, `plug`, `terminal`.
24
+
25
+ ## Callouts
26
+
27
+ Callouts draw attention to important information:
28
+
29
+ <Info>
30
+ This is an info callout for general information.
31
+ </Info>
32
+
33
+ <Tip>
34
+ This is a tip callout for helpful suggestions.
35
+ </Tip>
36
+
37
+ <Warning>
38
+ This is a warning callout for potential issues.
39
+ </Warning>
40
+
41
+ ## Steps
42
+
43
+ Use steps for sequential instructions:
44
+
45
+ <Steps>
46
+ <Step title="First Step">
47
+ Do this first.
48
+ </Step>
49
+ <Step title="Second Step">
50
+ Then do this.
51
+ </Step>
52
+ </Steps>
53
+
54
+ ## Tabs
55
+
56
+ Organize related content into tabs:
57
+
58
+ <Tabs>
59
+ <Tab title="npm">
60
+ ```bash
61
+ npm install my-package
62
+ ```
63
+ </Tab>
64
+ <Tab title="yarn">
65
+ ```bash
66
+ yarn add my-package
67
+ ```
68
+ </Tab>
69
+ </Tabs>
70
+
71
+ ## Accordions
72
+
73
+ Collapse content that isn't always needed:
74
+
75
+ <AccordionGroup>
76
+ <Accordion title="What is Unmint?">
77
+ Unmint is a free, open-source documentation system.
78
+ </Accordion>
79
+ <Accordion title="Is it really free?">
80
+ Yes! MIT licensed and free to use.
81
+ </Accordion>
82
+ </AccordionGroup>
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Customization
3
+ description: Advanced customization options
4
+ ---
5
+
6
+ ## Navigation Structure
7
+
8
+ Edit `content/docs/meta.json`:
9
+
10
+ ```json
11
+ {
12
+ "pages": [
13
+ "index",
14
+ "quickstart",
15
+ "---Getting Started---",
16
+ "installation"
17
+ ]
18
+ }
19
+ ```
20
+
21
+ - **Page references**: Filename without `.mdx`
22
+ - **Separators**: `"---Section Name---"` for headers
23
+
24
+ ## Adding Components
25
+
26
+ Create custom MDX components in `app/components/docs/mdx/`:
27
+
28
+ ```tsx
29
+ export function MyComponent({ children }) {
30
+ return <div className="my-component">{children}</div>
31
+ }
32
+ ```
33
+
34
+ Then register in `app/components/docs/mdx/index.tsx`.
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Deployment
3
+ description: Deploy your docs to Vercel, Netlify, or any static host
4
+ ---
5
+
6
+ Unmint can be deployed anywhere that supports Next.js.
7
+
8
+ ## Vercel (Recommended)
9
+
10
+ <Steps>
11
+ <Step title="Push to GitHub">
12
+ Push your repository to GitHub.
13
+ </Step>
14
+ <Step title="Import to Vercel">
15
+ Go to vercel.com/new and import your repository.
16
+ </Step>
17
+ <Step title="Deploy">
18
+ Vercel will automatically detect Next.js and deploy.
19
+ </Step>
20
+ </Steps>
21
+
22
+ ## Build Commands
23
+
24
+ ```bash
25
+ npm run dev # Development
26
+ npm run build # Production build
27
+ npm run start # Start production server
28
+ ```