polen 0.10.0-next.5 → 0.10.0-next.7

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 (54) hide show
  1. package/build/api/content/$$.d.ts +1 -0
  2. package/build/api/content/$$.d.ts.map +1 -1
  3. package/build/api/content/$$.js +1 -0
  4. package/build/api/content/$$.js.map +1 -1
  5. package/build/api/content/navbar.d.ts +10 -0
  6. package/build/api/content/navbar.d.ts.map +1 -0
  7. package/build/api/content/navbar.js +45 -0
  8. package/build/api/content/navbar.js.map +1 -0
  9. package/build/api/content/sidebar.d.ts +85 -5
  10. package/build/api/content/sidebar.d.ts.map +1 -1
  11. package/build/api/content/sidebar.js +151 -75
  12. package/build/api/content/sidebar.js.map +1 -1
  13. package/build/api/vite/plugins/pages.d.ts +1 -4
  14. package/build/api/vite/plugins/pages.d.ts.map +1 -1
  15. package/build/api/vite/plugins/pages.js +4 -42
  16. package/build/api/vite/plugins/pages.js.map +1 -1
  17. package/build/lib/file-router/scan.d.ts.map +1 -1
  18. package/build/lib/file-router/scan.js +6 -1
  19. package/build/lib/file-router/scan.js.map +1 -1
  20. package/build/sandbox.js +17 -2
  21. package/build/sandbox.js.map +1 -1
  22. package/build/template/components/HamburgerMenu.d.ts +9 -0
  23. package/build/template/components/HamburgerMenu.d.ts.map +1 -0
  24. package/build/template/components/HamburgerMenu.jsx +53 -0
  25. package/build/template/components/HamburgerMenu.jsx.map +1 -0
  26. package/build/template/components/NotFound.d.ts +2 -0
  27. package/build/template/components/NotFound.d.ts.map +1 -0
  28. package/build/template/components/NotFound.jsx +26 -0
  29. package/build/template/components/NotFound.jsx.map +1 -0
  30. package/build/template/components/ThemeToggle.d.ts +3 -0
  31. package/build/template/components/ThemeToggle.d.ts.map +1 -0
  32. package/build/template/components/ThemeToggle.jsx +10 -0
  33. package/build/template/components/ThemeToggle.jsx.map +1 -0
  34. package/build/template/contexts/ThemeContext.d.ts +12 -0
  35. package/build/template/contexts/ThemeContext.d.ts.map +1 -0
  36. package/build/template/contexts/ThemeContext.jsx +41 -0
  37. package/build/template/contexts/ThemeContext.jsx.map +1 -0
  38. package/build/template/routes/root.d.ts.map +1 -1
  39. package/build/template/routes/root.jsx +55 -39
  40. package/build/template/routes/root.jsx.map +1 -1
  41. package/package.json +1 -1
  42. package/src/api/content/$$.ts +1 -0
  43. package/src/api/content/navbar.test.ts +55 -0
  44. package/src/api/content/navbar.ts +61 -0
  45. package/src/api/content/sidebar.test.ts +297 -0
  46. package/src/api/content/sidebar.ts +235 -88
  47. package/src/api/vite/plugins/pages.ts +5 -51
  48. package/src/lib/file-router/scan.ts +7 -1
  49. package/src/sandbox.ts +20 -1
  50. package/src/template/components/HamburgerMenu.tsx +96 -0
  51. package/src/template/components/NotFound.tsx +28 -0
  52. package/src/template/components/ThemeToggle.tsx +21 -0
  53. package/src/template/contexts/ThemeContext.tsx +60 -0
  54. package/src/template/routes/root.tsx +74 -51
@@ -1,5 +1,6 @@
1
1
  import type { Config } from '#api/config/index'
2
2
  import { Content } from '#api/content/$'
3
+ import { createNavbar } from '#api/content/navbar'
3
4
  import type { NavbarDataRegistry } from '#api/vite/data/navbar'
4
5
  import { polenVirtual } from '#api/vite/vi'
5
6
  import type { Vite } from '#dep/vite/index'
@@ -9,7 +10,6 @@ import { debugPolen } from '#singletons/debug'
9
10
  import { superjson } from '#singletons/superjson'
10
11
  import mdx from '@mdx-js/rollup'
11
12
  import rehypeShiki from '@shikijs/rehype'
12
- import { Tree } from '@wollybeard/kit'
13
13
  import { Arr, Cache, Path, Str } from '@wollybeard/kit'
14
14
  import remarkFrontmatter from 'remark-frontmatter'
15
15
  import remarkGfm from 'remark-gfm'
@@ -26,14 +26,10 @@ export interface Options {
26
26
  }
27
27
 
28
28
  export interface ProjectDataPages {
29
- sidebarIndex: SidebarIndex
29
+ sidebarIndex: Content.SidebarIndex
30
30
  pages: Content.Page[]
31
31
  }
32
32
 
33
- export interface SidebarIndex {
34
- [pathExpression: string]: Content.Sidebar
35
- }
36
-
37
33
  /**
38
34
  * Pages plugin with tree support
39
35
  */
@@ -204,57 +200,15 @@ export const Pages = ({
204
200
  const navbarPages = navbarData.get('pages')
205
201
  navbarPages.length = 0 // Clear existing
206
202
 
207
- // Process first-level children as navigation items
208
- if (scanResult.tree.root) {
209
- for (const child of scanResult.tree.root.children) {
210
- // Now we have Page objects in the tree
211
- const page = child.value
212
- const pathExp = FileRouter.routeToPathExpression(page.route)
213
-
214
- // Skip hidden pages and index files at root level
215
- if (page.metadata.hidden || page.route.logical.path.slice(-1)[0] === 'index') {
216
- continue
217
- }
218
-
219
- // Only include top-level pages (files directly in pages directory)
220
- if (page.route.logical.path.length === 1) {
221
- const title = Str.titlizeSlug(page.route.logical.path[0]!)
222
- navbarPages.push({
223
- // IMPORTANT: Always ensure paths start with '/' for React Router compatibility.
224
- pathExp: pathExp.startsWith('/') ? pathExp : '/' + pathExp,
225
- title,
226
- })
227
- }
228
- }
229
- }
203
+ const navbarItems = createNavbar(scanResult.list)
204
+ navbarPages.push(...navbarItems)
230
205
  }
231
206
 
232
207
  //
233
208
  // ━━ Build Sidebar
234
209
  //
235
210
 
236
- const sidebarIndex: SidebarIndex = {}
237
-
238
- // Build sidebar for each top-level directory using the page tree
239
- if (scanResult.tree.root) {
240
- Tree.visit(scanResult.tree, (node) => {
241
- if (!node.value) return
242
- const page = node.value as any
243
- // Only process top-level directories (pages with logical path length > 1 indicate nested structure)
244
- if (page.route.logical.path.length === 1 && node.children.length > 0) {
245
- const topLevelDir = page.route.logical.path[0]!
246
- const pathExp = `/${topLevelDir}`
247
-
248
- // Create a subtree for this directory
249
- const subtree = Tree.Tree(Tree.Node(page, node.children)) as Tree.Tree<any>
250
-
251
- // Build sidebar using the new page tree builder
252
- const sidebar = Content.buildFromPageTree(subtree, [topLevelDir])
253
- debug(`Built sidebar for ${pathExp}:`, sidebar)
254
- sidebarIndex[pathExp] = sidebar
255
- }
256
- })
257
- }
211
+ const sidebarIndex = Content.buildSidebarIndex(scanResult)
258
212
 
259
213
  //
260
214
  // ━━ Put It All together
@@ -87,7 +87,13 @@ export const filePathToRoute = (filePathExpression: string, rootDir: string): Ro
87
87
  }
88
88
 
89
89
  export const filePathToRouteLogical = (filePath: Path.Parsed): RouteLogical => {
90
- const dirPath = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
90
+ const dirSegments = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
91
+
92
+ // Parse numbered prefixes from directory segments
93
+ const dirPath = dirSegments.map(segment => {
94
+ const prefixMatch = Str.match(segment, conventions.numberedPrefix.pattern)
95
+ return prefixMatch?.groups.name ?? segment
96
+ })
91
97
 
92
98
  // Parse numbered prefix from filename
93
99
  const prefixMatch = Str.match(filePath.name, conventions.numberedPrefix.pattern)
package/src/sandbox.ts CHANGED
@@ -1 +1,20 @@
1
- // Sandbox file for temporary testing
1
+ import { filePathToRouteLogical } from '#lib/file-router/scan'
2
+ import { Path } from '@wollybeard/kit'
3
+
4
+ // Test parsing of numbered directory
5
+ const testPath1 = Path.parse('a/10_b/index.md')
6
+ const logical1 = filePathToRouteLogical(testPath1)
7
+ console.log('Path 1:', testPath1)
8
+ console.log('Logical 1:', logical1)
9
+
10
+ // Test parsing of numbered file
11
+ const testPath2 = Path.parse('a/10_b/g.md')
12
+ const logical2 = filePathToRouteLogical(testPath2)
13
+ console.log('\nPath 2:', testPath2)
14
+ console.log('Logical 2:', logical2)
15
+
16
+ // Test directory structure
17
+ const testPath3 = Path.parse('a/30_d/index.md')
18
+ const logical3 = filePathToRouteLogical(testPath3)
19
+ console.log('\nPath 3:', testPath3)
20
+ console.log('Logical 3:', logical3)
@@ -0,0 +1,96 @@
1
+ import type { Content } from '#api/content/$'
2
+ import { Cross2Icon, HamburgerMenuIcon } from '@radix-ui/react-icons'
3
+ import { Box, Flex, IconButton, Text } from '@radix-ui/themes'
4
+ import { useEffect } from 'react'
5
+ import { Sidebar } from '../components/sidebar/Sidebar.tsx'
6
+
7
+ export interface HamburgerMenuProps {
8
+ isOpen: boolean
9
+ onToggle: () => void
10
+ onClose: () => void
11
+ sidebarData: Content.Item[]
12
+ }
13
+
14
+ export const HamburgerMenu: React.FC<HamburgerMenuProps> = ({
15
+ isOpen,
16
+ onToggle,
17
+ onClose,
18
+ sidebarData,
19
+ }) => {
20
+ // Prevent body scroll when mobile menu is open
21
+ useEffect(() => {
22
+ if (isOpen) {
23
+ document.body.style.overflow = 'hidden'
24
+ } else {
25
+ document.body.style.overflow = ''
26
+ }
27
+
28
+ // Cleanup
29
+ return () => {
30
+ document.body.style.overflow = ''
31
+ }
32
+ }, [isOpen])
33
+
34
+ return (
35
+ <>
36
+ {/* Mobile menu button - show on mobile/tablet, hide on desktop */}
37
+ <Box display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}>
38
+ <IconButton
39
+ size='2'
40
+ variant='ghost'
41
+ onClick={onToggle}
42
+ aria-label='Toggle navigation menu'
43
+ >
44
+ {isOpen ? <Cross2Icon width='18' height='18' /> : <HamburgerMenuIcon width='18' height='18' />}
45
+ </IconButton>
46
+ </Box>
47
+
48
+ {/* Mobile Sidebar Drawer */}
49
+ {isOpen && (
50
+ <>
51
+ {/* Backdrop */}
52
+ <Box
53
+ position='fixed'
54
+ inset='0'
55
+ style={{
56
+ backgroundColor: 'var(--black-a9)',
57
+ zIndex: 50,
58
+ }}
59
+ onClick={onClose}
60
+ display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}
61
+ />
62
+
63
+ {/* Drawer */}
64
+ <Box
65
+ position='fixed'
66
+ top='0'
67
+ left='0'
68
+ bottom='0'
69
+ width='280px'
70
+ style={{
71
+ backgroundColor: 'var(--color-background)',
72
+ boxShadow: 'var(--shadow-6)',
73
+ zIndex: 100,
74
+ overflowY: 'auto',
75
+ }}
76
+ p='4'
77
+ display={{ initial: 'block', xs: 'block', sm: 'block', md: 'none', lg: 'none', xl: 'none' }}
78
+ >
79
+ <Flex justify='between' align='center' mb='4'>
80
+ <Text size='5' weight='bold'>Navigation</Text>
81
+ <IconButton
82
+ size='2'
83
+ variant='ghost'
84
+ onClick={onClose}
85
+ aria-label='Close navigation menu'
86
+ >
87
+ <Cross2Icon width='18' height='18' />
88
+ </IconButton>
89
+ </Flex>
90
+ <Sidebar data={sidebarData} />
91
+ </Box>
92
+ </>
93
+ )}
94
+ </>
95
+ )
96
+ }
@@ -0,0 +1,28 @@
1
+ import { Box, Button, Flex, Heading, Text } from '@radix-ui/themes'
2
+ import { Link as LinkReactRouter } from 'react-router'
3
+
4
+ export const NotFound: React.FC = () => {
5
+ return (
6
+ <Flex direction='column' align='center' gap='6' style={{ textAlign: `center`, paddingTop: `4rem` }}>
7
+ <Heading size='9' style={{ color: `var(--gray-12)` }}>404</Heading>
8
+ <Box>
9
+ <Heading size='5' mb='2'>Page Not Found</Heading>
10
+ <Text size='3' color='gray'>
11
+ The page you're looking for doesn't exist or has been moved.
12
+ </Text>
13
+ </Box>
14
+ <Flex gap='3'>
15
+ <LinkReactRouter to='/'>
16
+ <Button variant='soft' size='3'>
17
+ Go Home
18
+ </Button>
19
+ </LinkReactRouter>
20
+ <LinkReactRouter to='/reference'>
21
+ <Button variant='outline' size='3'>
22
+ View API Reference
23
+ </Button>
24
+ </LinkReactRouter>
25
+ </Flex>
26
+ </Flex>
27
+ )
28
+ }
@@ -0,0 +1,21 @@
1
+ import type { React } from '#dep/react/index'
2
+ import { MoonIcon, SunIcon } from '@radix-ui/react-icons'
3
+ import { IconButton } from '@radix-ui/themes'
4
+ import { useTheme } from '../contexts/ThemeContext.tsx'
5
+
6
+ export const ThemeToggle: React.FC = () => {
7
+ const { appearance, toggleTheme } = useTheme()
8
+
9
+ return (
10
+ <IconButton
11
+ size='2'
12
+ variant='ghost'
13
+ color='gray'
14
+ onClick={toggleTheme}
15
+ aria-label={`Switch to ${appearance === 'light' ? 'dark' : 'light'} theme`}
16
+ style={{ cursor: 'pointer' }}
17
+ >
18
+ {appearance === 'light' ? <MoonIcon width='18' height='18' /> : <SunIcon width='18' height='18' />}
19
+ </IconButton>
20
+ )
21
+ }
@@ -0,0 +1,60 @@
1
+ import type { React } from '#dep/react/index'
2
+ import { createContext, useContext, useEffect, useState } from 'react'
3
+
4
+ type ThemeAppearance = 'light' | 'dark'
5
+
6
+ interface ThemeContextValue {
7
+ appearance: ThemeAppearance
8
+ toggleTheme: () => void
9
+ }
10
+
11
+ const ThemeContext = createContext<ThemeContextValue | undefined>(undefined)
12
+
13
+ const THEME_STORAGE_KEY = 'polen-theme-preference'
14
+
15
+ export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
16
+ const [appearance, setAppearance] = useState<ThemeAppearance>(() => {
17
+ // Check if we're in the browser
18
+ if (typeof window === 'undefined') {
19
+ return 'light'
20
+ }
21
+
22
+ // Check localStorage first
23
+ const stored = localStorage.getItem(THEME_STORAGE_KEY)
24
+ if (stored === 'light' || stored === 'dark') {
25
+ return stored
26
+ }
27
+
28
+ // Check system preference
29
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
30
+ return 'dark'
31
+ }
32
+
33
+ return 'light'
34
+ })
35
+
36
+ useEffect(() => {
37
+ // Persist to localStorage
38
+ if (typeof window !== 'undefined') {
39
+ localStorage.setItem(THEME_STORAGE_KEY, appearance)
40
+ }
41
+ }, [appearance])
42
+
43
+ const toggleTheme = () => {
44
+ setAppearance(prev => prev === 'light' ? 'dark' : 'light')
45
+ }
46
+
47
+ return (
48
+ <ThemeContext.Provider value={{ appearance, toggleTheme }}>
49
+ {children}
50
+ </ThemeContext.Provider>
51
+ )
52
+ }
53
+
54
+ export const useTheme = () => {
55
+ const context = useContext(ThemeContext)
56
+ if (!context) {
57
+ throw new Error('useTheme must be used within a ThemeProvider')
58
+ }
59
+ return context
60
+ }
@@ -1,10 +1,10 @@
1
- import { assetUrl } from '#api/utils/asset-url/index'
2
1
  import type { ReactRouter } from '#dep/react-router/index'
3
2
  import { createRoute } from '#lib/react-router-aid/react-router-aid'
4
- import { Box, Button, Grid, Heading, Text } from '@radix-ui/themes'
3
+ import { Box, Grid } from '@radix-ui/themes'
5
4
  import { Flex, Theme } from '@radix-ui/themes'
6
5
  import radixStylesUrl from '@radix-ui/themes/styles.css?url'
7
6
  import { Arr } from '@wollybeard/kit'
7
+ import { useEffect, useState } from 'react'
8
8
  import { Link as LinkReactRouter } from 'react-router'
9
9
  import { Outlet, ScrollRestoration, useLocation } from 'react-router'
10
10
  import logoSrc from 'virtual:polen/project/assets/logo.svg'
@@ -13,13 +13,17 @@ import projectDataNavbar from 'virtual:polen/project/data/navbar.jsonsuper'
13
13
  import projectDataPages from 'virtual:polen/project/data/pages.jsonsuper'
14
14
  import { pages } from 'virtual:polen/project/pages.jsx'
15
15
  import { templateVariables } from 'virtual:polen/template/variables'
16
- import { Link } from '../components/Link.jsx'
17
- import { Logo } from '../components/Logo.jsx'
18
- import { Sidebar } from '../components/sidebar/Sidebar.jsx'
16
+ import { HamburgerMenu } from '../components/HamburgerMenu.tsx'
17
+ import { Link } from '../components/Link.tsx'
18
+ import { Logo } from '../components/Logo.tsx'
19
+ import { NotFound } from '../components/NotFound.tsx'
20
+ import { Sidebar } from '../components/sidebar/Sidebar.tsx'
21
+ import { ThemeToggle } from '../components/ThemeToggle.tsx'
22
+ import { ThemeProvider, useTheme } from '../contexts/ThemeContext.tsx'
19
23
  import entryClientUrl from '../entry.client.jsx?url'
20
- import { changelog } from './changelog.jsx'
21
- import { index } from './index.jsx'
22
- import { reference } from './reference.jsx'
24
+ import { changelog } from './changelog.tsx'
25
+ import { index } from './index.tsx'
26
+ import { reference } from './reference.tsx'
23
27
 
24
28
  // todo: not needed anymore because not using hono dev vite plugin right?
25
29
  const reactRefreshPreamble = `
@@ -45,7 +49,9 @@ export const Component = () => {
45
49
  {/* <meta name='theme-color' content='#000000' /> */}
46
50
  </head>
47
51
  <body style={{ margin: 0 }}>
48
- <Layout />
52
+ <ThemeProvider>
53
+ <Layout />
54
+ </ThemeProvider>
49
55
  <ScrollRestoration />
50
56
  {import.meta.env.DEV && <script type='module' src={entryClientUrl}></script>}
51
57
  </body>
@@ -55,6 +61,13 @@ export const Component = () => {
55
61
 
56
62
  const Layout = () => {
57
63
  const location = useLocation()
64
+ const { appearance } = useTheme()
65
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
66
+
67
+ // Close mobile menu on route change
68
+ useEffect(() => {
69
+ setMobileMenuOpen(false)
70
+ }, [location.pathname])
58
71
 
59
72
  // Determine if we should show sidebar based on current path
60
73
  const getCurrentNavPathExp = (): string | null => {
@@ -75,42 +88,75 @@ const Layout = () => {
75
88
  <Flex
76
89
  gridArea={'header'}
77
90
  align='center'
78
- gap='8'
91
+ gap={{ initial: '4', md: '8' }}
79
92
  pb='4'
80
- mb='8'
93
+ mb={{ initial: '4', md: '8' }}
81
94
  style={{
82
95
  borderBottom: `1px solid var(--gray-3)`,
83
96
  }}
84
97
  >
98
+ {/* Mobile menu - only show when sidebar exists */}
99
+ {isShowSidebar && (
100
+ <HamburgerMenu
101
+ isOpen={mobileMenuOpen}
102
+ onToggle={() => setMobileMenuOpen(!mobileMenuOpen)}
103
+ onClose={() => setMobileMenuOpen(false)}
104
+ sidebarData={sidebar.items}
105
+ />
106
+ )}
107
+
85
108
  <LinkReactRouter
86
109
  to='/'
87
110
  style={{ color: `inherit`, textDecoration: `none` }}
88
111
  >
89
- <Logo src={logoSrc} title={templateVariables.title} height={30} showTitle={true} />
112
+ <Box display={{ initial: 'block', md: 'block' }}>
113
+ <Logo src={logoSrc} title={templateVariables.title} height={30} showTitle={true} />
114
+ </Box>
90
115
  </LinkReactRouter>
91
- <Flex direction='row' gap='4'>
116
+ <Flex direction='row' gap='4' style={{ flex: 1 }}>
92
117
  {projectDataNavbar.map((item, key) => (
93
118
  <Link key={key} color='gray' to={item.pathExp}>
94
119
  {item.title}
95
120
  </Link>
96
121
  ))}
97
122
  </Flex>
123
+ <ThemeToggle />
98
124
  </Flex>
99
125
  )
100
126
 
101
127
  return (
102
- <Theme asChild>
128
+ <Theme asChild appearance={appearance}>
103
129
  <Grid
104
- width={{ initial: 'var(--container-4)' }}
105
- areas="'header header header header header header header header' 'sidebar sidebar . content content content content content'"
130
+ width={{ initial: '100%', sm: '100%', md: 'var(--container-4)' }}
131
+ maxWidth='100vw'
132
+ areas={{
133
+ initial: "'header' 'content'",
134
+ sm: "'header' 'content'",
135
+ md:
136
+ "'header header header header header header header header' 'sidebar sidebar . content content content content content'",
137
+ }}
106
138
  rows='min-content auto'
107
- columns='repeat(8, 1fr)'
108
- gapX='2'
109
- my='8'
139
+ columns={{ initial: '1fr', sm: '1fr', md: 'repeat(8, 1fr)' }}
140
+ gapX={{ initial: '0', sm: '0', md: '2' }}
141
+ my={{ initial: '0', sm: '0', md: '8' }}
110
142
  mx='auto'
143
+ px={{ initial: '4', sm: '4', md: '0' }}
144
+ py={{ initial: '4', sm: '4', md: '0' }}
111
145
  >
112
146
  <style>
113
147
  {`
148
+ /* Responsive container fixes */
149
+ @media (max-width: 768px) {
150
+ body {
151
+ overflow-x: hidden;
152
+ }
153
+ }
154
+
155
+ /* Ensure proper centering on all screen sizes */
156
+ .rt-Grid {
157
+ box-sizing: border-box;
158
+ }
159
+
114
160
  /* Shiki code blocks */
115
161
  pre.shiki {
116
162
  margin: 1rem 0;
@@ -144,15 +190,18 @@ const Layout = () => {
144
190
  `}
145
191
  </style>
146
192
  {header}
193
+
194
+ {/* Desktop Sidebar */}
147
195
  {isShowSidebar && (
148
- <Sidebar
196
+ <Box
197
+ display={{ initial: 'none', xs: 'none', sm: 'none', md: 'block' }}
149
198
  gridColumn='1 / 3'
150
199
  gridRow='2 / auto'
151
- data={sidebar.items}
152
- // ml='-100px'
153
- // style={{ transform: 'translate(calc(-100% - var(--space-8)))' }}
154
- />
200
+ >
201
+ <Sidebar data={sidebar.items} />
202
+ </Box>
155
203
  )}
204
+
156
205
  <Box gridArea='content / content / auto / 8'>
157
206
  <Outlet />
158
207
  </Box>
@@ -189,36 +238,10 @@ if (PROJECT_DATA.schema) {
189
238
  //
190
239
  //
191
240
 
192
- const NotFoundComponent = () => {
193
- return (
194
- <Flex direction='column' align='center' gap='6' style={{ textAlign: `center`, paddingTop: `4rem` }}>
195
- <Heading size='9' style={{ color: `var(--gray-12)` }}>404</Heading>
196
- <Box>
197
- <Heading size='5' mb='2'>Page Not Found</Heading>
198
- <Text size='3' color='gray'>
199
- The page you're looking for doesn't exist or has been moved.
200
- </Text>
201
- </Box>
202
- <Flex gap='3'>
203
- <LinkReactRouter to='/'>
204
- <Button variant='soft' size='3'>
205
- Go Home
206
- </Button>
207
- </LinkReactRouter>
208
- <LinkReactRouter to='/reference'>
209
- <Button variant='outline' size='3'>
210
- View API Reference
211
- </Button>
212
- </LinkReactRouter>
213
- </Flex>
214
- </Flex>
215
- )
216
- }
217
-
218
241
  const notFoundRoute = createRoute({
219
242
  id: `*_not_found`,
220
243
  path: `*`,
221
- Component: NotFoundComponent,
244
+ Component: NotFound,
222
245
  handle: {
223
246
  statusCode: 404,
224
247
  },