polen 0.10.0-next.18 → 0.10.0-next.20

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 (128) hide show
  1. package/README.md +2 -2
  2. package/build/api/api.d.ts +1 -0
  3. package/build/api/api.d.ts.map +1 -1
  4. package/build/api/api.js +1 -0
  5. package/build/api/api.js.map +1 -1
  6. package/build/api/builder/builder.d.ts +8 -2
  7. package/build/api/builder/builder.d.ts.map +1 -1
  8. package/build/api/builder/builder.js +5 -18
  9. package/build/api/builder/builder.js.map +1 -1
  10. package/build/api/config/configurator.d.ts +31 -8
  11. package/build/api/config/configurator.d.ts.map +1 -1
  12. package/build/api/config/configurator.js +9 -10
  13. package/build/api/config/configurator.js.map +1 -1
  14. package/build/api/config/merge.d.ts.map +1 -1
  15. package/build/api/config/merge.js +9 -16
  16. package/build/api/config/merge.js.map +1 -1
  17. package/build/api/project/index.d.ts +2 -0
  18. package/build/api/project/index.d.ts.map +1 -0
  19. package/build/api/project/index.js +2 -0
  20. package/build/api/project/index.js.map +1 -0
  21. package/build/api/project/validate.d.ts +11 -0
  22. package/build/api/project/validate.d.ts.map +1 -0
  23. package/build/api/project/validate.js +30 -0
  24. package/build/api/project/validate.js.map +1 -0
  25. package/build/api/vite/plugins/core.d.ts.map +1 -1
  26. package/build/api/vite/plugins/core.js +1 -0
  27. package/build/api/vite/plugins/core.js.map +1 -1
  28. package/build/api/vite/plugins/pages.d.ts.map +1 -1
  29. package/build/api/vite/plugins/pages.js +12 -0
  30. package/build/api/vite/plugins/pages.js.map +1 -1
  31. package/build/api/vite/plugins/serve.js +1 -1
  32. package/build/api/vite/plugins/serve.js.map +1 -1
  33. package/build/cli/_/parameters.d.ts +6 -0
  34. package/build/cli/_/parameters.d.ts.map +1 -0
  35. package/build/cli/_/parameters.js +9 -0
  36. package/build/cli/_/parameters.js.map +1 -0
  37. package/build/cli/commands/build.js +17 -10
  38. package/build/cli/commands/build.js.map +1 -1
  39. package/build/cli/commands/config/create.js +12 -1
  40. package/build/cli/commands/config/create.js.map +1 -1
  41. package/build/cli/commands/create.js +3 -5
  42. package/build/cli/commands/create.js.map +1 -1
  43. package/build/cli/commands/dev.js +14 -4
  44. package/build/cli/commands/dev.js.map +1 -1
  45. package/build/exports/mdx.d.ts +2 -0
  46. package/build/exports/mdx.d.ts.map +1 -0
  47. package/build/exports/mdx.js +2 -0
  48. package/build/exports/mdx.js.map +1 -0
  49. package/build/lib/graphql-document/components/GraphQLDocument.d.ts +2 -0
  50. package/build/lib/graphql-document/components/GraphQLDocument.d.ts.map +1 -1
  51. package/build/lib/graphql-document/components/GraphQLDocument.js +4 -2
  52. package/build/lib/graphql-document/components/GraphQLDocument.js.map +1 -1
  53. package/build/lib/kit-temp.d.ts +33 -0
  54. package/build/lib/kit-temp.d.ts.map +1 -1
  55. package/build/lib/kit-temp.js +48 -0
  56. package/build/lib/kit-temp.js.map +1 -1
  57. package/build/project-data.d.ts +1 -0
  58. package/build/project-data.d.ts.map +1 -1
  59. package/build/template/components/CodeBlock.d.ts +6 -3
  60. package/build/template/components/CodeBlock.d.ts.map +1 -1
  61. package/build/template/components/CodeBlock.js +19 -2
  62. package/build/template/components/CodeBlock.js.map +1 -1
  63. package/build/template/components/CodeHikePre.d.ts +16 -0
  64. package/build/template/components/CodeHikePre.d.ts.map +1 -0
  65. package/build/template/components/CodeHikePre.js +37 -0
  66. package/build/template/components/CodeHikePre.js.map +1 -0
  67. package/build/template/layouts/SidebarLayout.d.ts.map +1 -0
  68. package/build/template/{components/layouts → layouts}/SidebarLayout.js +3 -3
  69. package/build/template/layouts/SidebarLayout.js.map +1 -0
  70. package/build/template/layouts/index.d.ts.map +1 -0
  71. package/build/template/layouts/index.js.map +1 -0
  72. package/build/template/routes/reference.d.ts.map +1 -1
  73. package/build/template/routes/reference.js +1 -2
  74. package/build/template/routes/reference.js.map +1 -1
  75. package/build/template/routes/root.d.ts.map +1 -1
  76. package/build/template/routes/root.js +64 -7
  77. package/build/template/routes/root.js.map +1 -1
  78. package/build/template/server/main.js +2 -1
  79. package/build/template/server/main.js.map +1 -1
  80. package/package.json +7 -6
  81. package/src/api/api.ts +1 -0
  82. package/src/api/builder/builder.ts +12 -21
  83. package/src/api/config/configurator.ts +41 -19
  84. package/src/api/config/merge.ts +13 -16
  85. package/src/api/project/index.ts +1 -0
  86. package/src/api/project/validate.ts +41 -0
  87. package/src/api/vite/plugins/core.ts +1 -0
  88. package/src/api/vite/plugins/pages.ts +13 -0
  89. package/src/api/vite/plugins/serve.ts +1 -1
  90. package/src/cli/_/parameters.ts +10 -0
  91. package/src/cli/commands/build.ts +25 -10
  92. package/src/cli/commands/config/create.ts +18 -1
  93. package/src/cli/commands/create.ts +4 -4
  94. package/src/cli/commands/dev.ts +19 -5
  95. package/src/exports/mdx.ts +1 -0
  96. package/src/lib/graphql-document/components/GraphQLDocument.tsx +12 -3
  97. package/src/lib/kit-temp.test.ts +85 -1
  98. package/src/lib/kit-temp.ts +51 -0
  99. package/src/project-data.ts +1 -0
  100. package/src/template/components/CodeBlock.tsx +29 -13
  101. package/src/template/components/CodeHikePre.tsx +51 -0
  102. package/src/template/{components/layouts → layouts}/SidebarLayout.tsx +3 -3
  103. package/src/template/routes/reference.tsx +1 -2
  104. package/src/template/routes/root.tsx +99 -8
  105. package/src/template/server/main.ts +2 -1
  106. package/build/exports/components.d.ts +0 -5
  107. package/build/exports/components.d.ts.map +0 -1
  108. package/build/exports/components.js +0 -5
  109. package/build/exports/components.js.map +0 -1
  110. package/build/template/components/MDXComponents.d.ts +0 -10
  111. package/build/template/components/MDXComponents.d.ts.map +0 -1
  112. package/build/template/components/MDXComponents.js +0 -12
  113. package/build/template/components/MDXComponents.js.map +0 -1
  114. package/build/template/components/TestComponent.d.ts +0 -5
  115. package/build/template/components/TestComponent.d.ts.map +0 -1
  116. package/build/template/components/TestComponent.js +0 -7
  117. package/build/template/components/TestComponent.js.map +0 -1
  118. package/build/template/components/layouts/SidebarLayout.d.ts.map +0 -1
  119. package/build/template/components/layouts/SidebarLayout.js.map +0 -1
  120. package/build/template/components/layouts/index.d.ts.map +0 -1
  121. package/build/template/components/layouts/index.js.map +0 -1
  122. package/src/exports/components.ts +0 -4
  123. package/src/template/components/MDXComponents.tsx +0 -17
  124. package/src/template/components/TestComponent.tsx +0 -6
  125. /package/build/template/{components/layouts → layouts}/SidebarLayout.d.ts +0 -0
  126. /package/build/template/{components/layouts → layouts}/index.d.ts +0 -0
  127. /package/build/template/{components/layouts → layouts}/index.js +0 -0
  128. /package/src/template/{components/layouts → layouts}/index.ts +0 -0
@@ -1,6 +1,23 @@
1
+ import { Api } from '#api/index'
2
+ import { projectParameter } from '#cli/_/parameters'
3
+ import { ensureOptionalAbsoluteWithCwd } from '#lib/kit-temp'
4
+ import { Command } from '@molt/command'
1
5
  import { Fs, Path } from '@wollybeard/kit'
2
6
  import consola from 'consola'
3
7
 
8
+ const args = Command.create()
9
+ .parameter(
10
+ `--project -p`,
11
+ projectParameter,
12
+ )
13
+ .parse()
14
+
15
+ const dir = ensureOptionalAbsoluteWithCwd(args.project)
16
+
17
+ if (!await Api.Project.validateProjectDirectory(dir)) {
18
+ process.exit(1)
19
+ }
20
+
4
21
  const fileName = 'polen.config.ts'
5
22
  const fileContent = `import { Polen } from 'polen'
6
23
 
@@ -9,7 +26,7 @@ export default Polen.defineConfig({
9
26
  })
10
27
  `
11
28
 
12
- const filePath = Path.join(process.cwd(), fileName)
29
+ const filePath = Path.join(dir, fileName)
13
30
 
14
31
  const exists = await Fs.exists(filePath)
15
32
  if (exists) {
@@ -1,4 +1,5 @@
1
1
  // @ts-nocheck
2
+ import { Api } from '#api/index'
2
3
  import { Command } from '@molt/command'
3
4
  import { Err, Fs, Manifest, Name, Path, Str } from '@wollybeard/kit'
4
5
  import * as Ansis from 'ansis'
@@ -48,10 +49,9 @@ const args = Command
48
49
 
49
50
  const getProjectRoot = async (): Promise<string> => {
50
51
  if (args.path) {
51
- const stat = await Fs.stat(args.path)
52
- if (Fs.isNotFoundError(stat)) return args.path
53
- if (stat.isDirectory() && await Fs.isEmptyDir(args.path)) return args.path
54
- consola.error(`The given path ${args.path} already exists and is not an empty directory`)
52
+ if (await Api.Project.validateProjectDirectory(args.path, { mustExist: false, mustBeEmpty: true })) {
53
+ return args.path
54
+ }
55
55
  process.exit(1)
56
56
  }
57
57
 
@@ -1,9 +1,10 @@
1
1
  // @ts-nocheck
2
2
  import { Api } from '#api/index'
3
+ import { projectParameter } from '#cli/_/parameters'
3
4
  import { Vite } from '#dep/vite/index'
4
- import { ensureOptionalAbsolute, ensureOptionalAbsoluteWithCwd } from '#lib/kit-temp'
5
+ import { ensureOptionalAbsoluteWithCwd } from '#lib/kit-temp'
5
6
  import { Command } from '@molt/command'
6
- import { Err, Path } from '@wollybeard/kit'
7
+ import { Err } from '@wollybeard/kit'
7
8
  import { z } from 'zod'
8
9
 
9
10
  const args = Command.create()
@@ -11,12 +12,16 @@ const args = Command.create()
11
12
  .parameter(
12
13
  `--project -p`,
13
14
  // @ts-expect-error
14
- z.string().optional().describe(`The path to the project directory. Default is CWD (current working directory).`),
15
+ projectParameter,
15
16
  )
16
17
  .parameter(
17
18
  `--base -b`,
18
19
  z.string().optional().describe('Base public path for deployment (e.g., /my-project/)'),
19
20
  )
21
+ .parameter(
22
+ `--port`,
23
+ z.number().optional().describe('Port to run the development server on'),
24
+ )
20
25
  .settings({
21
26
  parameters: {
22
27
  environment: {
@@ -30,12 +35,21 @@ const args = Command.create()
30
35
  })
31
36
  .parse()
32
37
 
33
- const dir = ensureOptionalAbsoluteWithCwd(args.project) as string
38
+ const dir = ensureOptionalAbsoluteWithCwd(args.project)
39
+
40
+ if (!await Api.Project.validateProjectDirectory(dir)) {
41
+ process.exit(1)
42
+ }
34
43
 
35
44
  const viteUserConfig = await Api.ConfigResolver.fromFile({
36
45
  dir,
37
46
  overrides: {
38
- ...(args.base ? { build: { base: args.base } } : {}),
47
+ build: {
48
+ base: args.base,
49
+ },
50
+ server: {
51
+ port: args.port,
52
+ },
39
53
  advanced: {
40
54
  debug: args.debug,
41
55
  },
@@ -0,0 +1 @@
1
+ export { MDXProvider, useMDXComponents } from '@mdx-js/react'
@@ -24,6 +24,8 @@ export interface GraphQLDocumentOptions {
24
24
  validate?: boolean
25
25
  /** Custom class name for the container */
26
26
  className?: string
27
+ /** Custom render function for the code block */
28
+ renderCode?: () => React.ReactNode
27
29
  }
28
30
 
29
31
  /**
@@ -55,6 +57,7 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
55
57
  onNavigate,
56
58
  validate = true,
57
59
  className = ``,
60
+ renderCode,
58
61
  } = options
59
62
 
60
63
  const navigate = useNavigate()
@@ -199,9 +202,15 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
199
202
  data-testid='graphql-document'
200
203
  >
201
204
  {/* Base code block */}
202
- <pre className='code-block'>
203
- <code>{children}</code>
204
- </pre>
205
+ {renderCode
206
+ ? (
207
+ renderCode()
208
+ )
209
+ : (
210
+ <pre className='code-block'>
211
+ <code>{children}</code>
212
+ </pre>
213
+ )}
205
214
 
206
215
  {/* Interactive overlay layer */}
207
216
  {!plain && isReady && (
@@ -1,6 +1,6 @@
1
1
  import * as fc from 'fast-check'
2
2
  import { describe, expect, test } from 'vitest'
3
- import { objFilter, ObjOmit, ObjPick, objPolicyFilter } from './kit-temp.js'
3
+ import { objFilter, ObjOmit, ObjPick, objPolicyFilter, spreadShallow } from './kit-temp.js'
4
4
 
5
5
  describe('objPolicyFilter', () => {
6
6
  const testObj = { a: 1, b: 2, c: 3, d: 4 }
@@ -137,3 +137,87 @@ describe('property-based tests', () => {
137
137
  )
138
138
  })
139
139
  })
140
+
141
+ describe('mergeShallow', () => {
142
+ test('merges objects while omitting undefined values', () => {
143
+ const base = { a: 1, b: 2, c: 3 }
144
+ const override = { b: undefined, c: 4, d: 5 }
145
+
146
+ expect(spreadShallow(base, override)).toEqual({ a: 1, b: 2, c: 4, d: 5 })
147
+ })
148
+
149
+ test('handles multiple objects', () => {
150
+ const obj1 = { a: 1, b: 2 }
151
+ const obj2 = { b: undefined, c: 3 }
152
+ const obj3 = { c: undefined, d: 4 }
153
+
154
+ expect(spreadShallow(obj1, obj2, obj3)).toEqual({ a: 1, b: 2, c: 3, d: 4 })
155
+ })
156
+
157
+ test('handles empty objects', () => {
158
+ expect(spreadShallow({}, {})).toEqual({})
159
+ expect(spreadShallow({ a: 1 }, {})).toEqual({ a: 1 })
160
+ expect(spreadShallow({}, { a: 1 })).toEqual({ a: 1 })
161
+ })
162
+
163
+ test('handles single object', () => {
164
+ const obj = { a: 1, b: undefined, c: 3 }
165
+ expect(spreadShallow(obj)).toEqual({ a: 1, c: 3 })
166
+ })
167
+
168
+ test('handles no objects', () => {
169
+ expect(spreadShallow()).toEqual({})
170
+ })
171
+
172
+ test('handles undefined objects', () => {
173
+ const obj = { a: 1, b: 2 }
174
+ expect(spreadShallow(undefined, obj, undefined)).toEqual({ a: 1, b: 2 })
175
+ expect(spreadShallow(obj, undefined)).toEqual({ a: 1, b: 2 })
176
+ expect(spreadShallow(undefined, undefined)).toEqual({})
177
+ })
178
+
179
+ test('preserves null values', () => {
180
+ const obj1 = { a: 1, b: null }
181
+ const obj2 = { b: 2, c: null }
182
+ expect(spreadShallow(obj1, obj2)).toEqual({ a: 1, b: 2, c: null })
183
+ })
184
+
185
+ test('preserves false and 0 values', () => {
186
+ const obj1 = { a: true, b: 1 }
187
+ const obj2 = { a: false, b: 0 }
188
+ expect(spreadShallow(obj1, obj2)).toEqual({ a: false, b: 0 })
189
+ })
190
+
191
+ test('property-based: never includes undefined values', () => {
192
+ fc.assert(
193
+ fc.property(
194
+ fc.array(fc.object({ withUndefined: true })),
195
+ (objects) => {
196
+ const result = spreadShallow(...objects)
197
+ Object.values(result).forEach(value => {
198
+ expect(value).not.toBe(undefined)
199
+ })
200
+ },
201
+ ),
202
+ )
203
+ })
204
+
205
+ test('property-based: later objects override earlier ones', () => {
206
+ fc.assert(
207
+ fc.property(
208
+ fc.object(),
209
+ fc.object(),
210
+ fc.string(),
211
+ fc.anything({ withUndefined: false }),
212
+ (obj1, obj2, key, value) => {
213
+ // Set the same key in both objects
214
+ obj1[key] = 'first'
215
+ obj2[key] = value
216
+
217
+ const result = spreadShallow(obj1, obj2)
218
+ expect(result[key]).toBe(value)
219
+ },
220
+ ),
221
+ )
222
+ })
223
+ })
@@ -592,3 +592,54 @@ export const brand = <$BaseType, $BrandName extends string>(
592
592
  ): Brand<$BaseType, $BrandName> => {
593
593
  return value as Brand<$BaseType, $BrandName>
594
594
  }
595
+
596
+ /**
597
+ * Shallow merge objects while omitting undefined values.
598
+ *
599
+ * This utility simplifies the common pattern of conditionally spreading objects
600
+ * to avoid including undefined values that would override existing values.
601
+ *
602
+ * @param objects - Objects to merge (later objects override earlier ones). Undefined objects are ignored.
603
+ * @returns Merged object with undefined values omitted
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * // Instead of:
608
+ * const overrides = {
609
+ * ...(value1 ? { key1: value1 } : {}),
610
+ * ...(value2 ? { key2: value2 } : {}),
611
+ * }
612
+ *
613
+ * // Use:
614
+ * const overrides = mergeShallow({
615
+ * key1: value1,
616
+ * key2: value2,
617
+ * })
618
+ *
619
+ * // Example with config merging:
620
+ * const config = mergeShallow(
621
+ * defaultConfig,
622
+ * userConfig,
623
+ * { debug: args.debug, base: args.base }
624
+ * )
625
+ * // undefined values in the last object won't override earlier values
626
+ * ```
627
+ */
628
+ export const spreadShallow = <T extends object>(...objects: (T | undefined)[]): T => {
629
+ const result = {} as T
630
+
631
+ for (const obj of objects) {
632
+ if (obj === undefined) continue
633
+
634
+ for (const key in obj) {
635
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
636
+ const value = obj[key]
637
+ if (value !== undefined) {
638
+ result[key] = value
639
+ }
640
+ }
641
+ }
642
+ }
643
+
644
+ return result
645
+ }
@@ -8,6 +8,7 @@ export interface ProjectData {
8
8
  paths: Config.Config[`paths`][`project`]
9
9
  navbar: NavbarItem[]
10
10
  server: {
11
+ port: number
11
12
  static: {
12
13
  directory: string
13
14
  route: string
@@ -1,19 +1,35 @@
1
+ import { type HighlightedCode, Pre } from 'codehike/code'
1
2
  import React from 'react'
3
+ import { GraphQLDocument } from '../../lib/graphql-document/components/GraphQLDocument.js'
2
4
 
3
5
  interface CodeBlockProps {
4
- children: string
5
- language?: string
6
- className?: string
6
+ codeblock: HighlightedCode
7
7
  }
8
8
 
9
- export const CodeBlock: React.FC<CodeBlockProps> = ({
10
- children,
11
- language = `text`,
12
- className = ``,
13
- }) => {
14
- return (
15
- <pre className={`code-block ${className}`}>
16
- <code className={`language-${language}`}>{children}</code>
17
- </pre>
18
- )
9
+ /**
10
+ * Code block component for Code Hike
11
+ * Handles pre-highlighted code blocks and interactive GraphQL blocks
12
+ */
13
+ export const CodeBlock: React.FC<CodeBlockProps> = ({ codeblock }) => {
14
+ // Check if this is an interactive GraphQL block
15
+ if (codeblock.lang === 'graphql' && codeblock.meta?.includes('interactive')) {
16
+ const schema = typeof window !== 'undefined'
17
+ ? (window as any).__POLEN_GRAPHQL_SCHEMA__
18
+ : null
19
+
20
+ return (
21
+ <GraphQLDocument
22
+ schema={schema}
23
+ options={{
24
+ className: 'ch-code-container',
25
+ renderCode: () => <Pre code={codeblock} />,
26
+ }}
27
+ >
28
+ {codeblock.value}
29
+ </GraphQLDocument>
30
+ )
31
+ }
32
+
33
+ // For regular code blocks, use Code Hike's Pre component with pre-highlighted code
34
+ return <Pre code={codeblock} />
19
35
  }
@@ -0,0 +1,51 @@
1
+ import { Pre as CodeHikePre } from 'codehike/code'
2
+ import React from 'react'
3
+ import { GraphQLDocument } from '../../lib/graphql-document/components/GraphQLDocument.js'
4
+
5
+ type CodeHikePreProps = React.ComponentProps<typeof CodeHikePre>
6
+ type HTMLPreProps = React.ComponentPropsWithoutRef<'pre'>
7
+ type PreProps = CodeHikePreProps | HTMLPreProps
8
+
9
+ /**
10
+ * Custom Pre component that adds interactive GraphQL support to Code Hike
11
+ *
12
+ * Usage in MDX:
13
+ * ```graphql interactive
14
+ * query { ... }
15
+ * ```
16
+ */
17
+ export const Pre: React.FC<PreProps> = (props) => {
18
+ // Check if this is a Code Hike pre component (has 'code' prop)
19
+ if ('code' in props && props.code) {
20
+ const { code } = props
21
+
22
+ // Check if this is an interactive GraphQL block
23
+ if (code.lang === 'graphql' && code.meta?.includes('interactive')) {
24
+ // Extract the GraphQL schema if available
25
+ const schema = typeof window !== 'undefined'
26
+ ? (window as any).__POLEN_GRAPHQL_SCHEMA__
27
+ : null
28
+
29
+ // For interactive GraphQL blocks, we need to apply Code Hike's styling
30
+ // but add GraphQLDocument's interactive features
31
+ return (
32
+ <GraphQLDocument
33
+ schema={schema}
34
+ options={{
35
+ className: 'ch-code-container',
36
+ // Use Code Hike's Pre component for rendering
37
+ renderCode: () => <CodeHikePre {...props as CodeHikePreProps} />,
38
+ }}
39
+ >
40
+ {code.code}
41
+ </GraphQLDocument>
42
+ )
43
+ }
44
+
45
+ // For other Code Hike code blocks, use Code Hike's Pre
46
+ return <CodeHikePre {...props as CodeHikePreProps} />
47
+ }
48
+
49
+ // For standard HTML pre elements, render as-is
50
+ return <pre {...props as HTMLPreProps} />
51
+ }
@@ -3,8 +3,8 @@ import { Box, Grid } from '@radix-ui/themes'
3
3
  import type React from 'react'
4
4
  import { useEffect, useState } from 'react'
5
5
  import { useLocation } from 'react-router'
6
- import { HamburgerMenu } from '../HamburgerMenu.js'
7
- import { Sidebar } from '../sidebar/Sidebar.js'
6
+ import { HamburgerMenu } from '../components/HamburgerMenu.js'
7
+ import { Sidebar } from '../components/sidebar/Sidebar.js'
8
8
 
9
9
  interface SidebarLayoutProps {
10
10
  children: React.ReactNode
@@ -60,7 +60,7 @@ export const SidebarLayout: React.FC<SidebarLayoutProps> = ({ children, sidebar
60
60
  </Box>
61
61
  )}
62
62
 
63
- <Box gridArea='content / content / auto / 8' className='prose'>
63
+ <Box gridArea='content / content / auto / 8'>
64
64
  {children}
65
65
  </Box>
66
66
  </Grid>
@@ -2,11 +2,10 @@ import type { Content } from '#api/content/$'
2
2
  import { GrafaidOld } from '#lib/grafaid-old/index'
3
3
  import { createRoute } from '#lib/react-router-aid/react-router-aid'
4
4
  import { createLoader, useLoaderData } from '#lib/react-router-loader/react-router-loader'
5
- import { Box } from '@radix-ui/themes'
6
5
  import { Outlet } from 'react-router'
7
6
  import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
8
- import { SidebarLayout } from '../components/layouts/index.js'
9
7
  import { MissingSchema } from '../components/MissingSchema.js'
8
+ import { SidebarLayout } from '../layouts/index.js'
10
9
  import { reference$type } from './reference.$type.js'
11
10
 
12
11
  const loader = createLoader(() => {
@@ -1,15 +1,39 @@
1
1
  import type { ReactRouter } from '#dep/react-router/index'
2
2
  import { createRoute } from '#lib/react-router-aid/react-router-aid'
3
- import { Box } from '@radix-ui/themes'
4
- import { Flex, Theme } from '@radix-ui/themes'
5
- import { Link as LinkReactRouter } from 'react-router'
3
+ import { SidebarLayout } from '#template/layouts/index'
4
+ import { MDXProvider } from '@mdx-js/react'
5
+ import {
6
+ Badge,
7
+ Box,
8
+ Button,
9
+ Callout,
10
+ Card,
11
+ Code,
12
+ DataList,
13
+ Em,
14
+ Flex,
15
+ Heading,
16
+ Link,
17
+ Quote,
18
+ Separator,
19
+ Strong,
20
+ Table,
21
+ Tabs,
22
+ Text,
23
+ Theme,
24
+ Tooltip,
25
+ } from '@radix-ui/themes'
26
+ import { Link as LinkReactRouter, useLocation } from 'react-router'
6
27
  import { Outlet, ScrollRestoration } from 'react-router'
7
28
  import logoSrc from 'virtual:polen/project/assets/logo.svg'
8
29
  import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
30
+ import PROJECT_DATA_PAGES_CATALOG from 'virtual:polen/project/data/pages-catalog.jsonsuper'
9
31
  import { routes } from 'virtual:polen/project/routes.jsx'
10
32
  import { templateVariables } from 'virtual:polen/template/variables'
11
33
  import { GraphQLSchemaProvider } from '../../lib/graphql-document/schema-context.js'
12
- import { Link } from '../components/Link.js'
34
+ import { CodeBlock } from '../components/CodeBlock.js'
35
+ import { Pre } from '../components/CodeHikePre.js'
36
+ import { Link as PolenLink } from '../components/Link.js'
13
37
  import { Logo } from '../components/Logo.js'
14
38
  import { NotFound } from '../components/NotFound.js'
15
39
  import { ThemeToggle } from '../components/ThemeToggle.js'
@@ -61,9 +85,9 @@ const Layout = () => {
61
85
  </LinkReactRouter>
62
86
  <Flex direction='row' gap='4' style={{ flex: 1 }}>
63
87
  {PROJECT_DATA.navbar.map((item, key) => (
64
- <Link key={key} color='gray' to={item.pathExp}>
88
+ <PolenLink key={key} color='gray' to={item.pathExp}>
65
89
  {item.title}
66
- </Link>
90
+ </PolenLink>
67
91
  ))}
68
92
  </Flex>
69
93
  <ThemeToggle />
@@ -81,15 +105,82 @@ const Layout = () => {
81
105
  py={{ initial: `4`, sm: `4`, md: `0` }}
82
106
  >
83
107
  {header}
84
- <Outlet />
108
+ <MDXProvider
109
+ components={{
110
+ // Map markdown elements to Radix with spacing
111
+ p: (props) => <Text as='p' mb='4' {...props} />,
112
+ h1: (props) => <Heading size='8' mt='6' mb='4' {...props} />,
113
+ h2: (props) => <Heading size='7' mt='6' mb='3' {...props} />,
114
+ h3: (props) => <Heading size='6' mt='5' mb='3' {...props} />,
115
+ h4: (props) => <Heading size='5' mt='5' mb='2' {...props} />,
116
+ h5: (props) => <Heading size='4' mt='4' mb='2' {...props} />,
117
+ h6: (props) => <Heading size='3' mt='4' mb='2' {...props} />,
118
+ strong: Strong,
119
+ em: Em,
120
+ code: Code,
121
+ blockquote: (props) => <Quote my='4' {...props} />,
122
+ a: Link,
123
+ hr: (props) => <Separator my='6' {...props} />,
124
+ pre: Pre,
125
+ table: Table.Root,
126
+ thead: Table.Header,
127
+ tbody: Table.Body,
128
+ tr: Table.Row,
129
+ th: Table.ColumnHeaderCell,
130
+ td: Table.Cell,
131
+ // Lists need spacing too
132
+ ul: (props) => <Box as='ul' mb='4' style={{ paddingLeft: '1.5rem' }} {...props} />,
133
+ ol: (props) => <Box as='ol' mb='4' style={{ paddingLeft: '1.5rem' }} {...props} />,
134
+ li: (props) => <Box as='li' mb='2' {...props} />,
135
+
136
+ // Direct Radix components for MDX
137
+ Badge,
138
+ Button,
139
+ // @ts-expect-error
140
+ Callout,
141
+ Card,
142
+ // @ts-expect-error
143
+ DataList,
144
+ // @ts-expect-error
145
+ Tabs,
146
+ Tooltip,
147
+
148
+ // Code Hike component
149
+ CodeBlock,
150
+ }}
151
+ >
152
+ <Outlet />
153
+ </MDXProvider>
85
154
  </Box>
86
155
  </Theme>
87
156
  )
88
157
  }
89
158
 
159
+ const PagesLayout = () => {
160
+ const location = useLocation() // Add this line
161
+
162
+ // Build sidebar from pages catalog
163
+ // Get the top-level path segment (e.g., '/guide/foo' -> '/guide')
164
+ const pathSegments = location.pathname.split('/').filter(Boolean)
165
+ const topLevelPath = pathSegments[0] ? `/${pathSegments[0]}` : '/'
166
+
167
+ // Get the sidebar for this section
168
+ const sidebar = PROJECT_DATA_PAGES_CATALOG.sidebarIndex[topLevelPath]?.items || []
169
+
170
+ return (
171
+ <SidebarLayout sidebar={sidebar}>
172
+ <Outlet />
173
+ </SidebarLayout>
174
+ )
175
+ }
176
+
90
177
  const children: ReactRouter.RouteObject[] = [
91
178
  index,
92
- ...routes,
179
+ {
180
+ // Pathless layout route - doesn't affect URL paths
181
+ Component: PagesLayout,
182
+ children: [...routes], // All MDX page routes go here
183
+ },
93
184
  ]
94
185
 
95
186
  //
@@ -1,5 +1,6 @@
1
1
  import { serve } from '@hono/node-server' // TODO: support non-node platforms.
2
2
  import { neverCase } from '@wollybeard/kit/language'
3
+ import PROJECT_DATA from 'virtual:polen/project/data.jsonsuper'
3
4
  import { createApp } from './app.js'
4
5
  import { generate } from './ssg/generate.js'
5
6
  import { view } from './view.js'
@@ -10,7 +11,7 @@ if (__BUILDING__) {
10
11
  await generate(view)
11
12
  break
12
13
  case `ssr`:
13
- const port = process.env[`PORT`] ? parseInt(process.env[`PORT`]) : 3001 // todo viteConfigResolved.server.port + 1
14
+ const port = process.env[`PORT`] ? parseInt(process.env[`PORT`]) : PROJECT_DATA.server.port
14
15
  const app = createApp()
15
16
  serve({ fetch: app.fetch, port })
16
17
  break
@@ -1,5 +0,0 @@
1
- export { Callout, Tabs } from '@radix-ui/themes';
2
- export { GraphQLDocumentWithSchema } from '../template/components/content/GraphQLDocumentWrapper.js';
3
- export { mdxComponents } from '../template/components/MDXComponents.js';
4
- export { TestComponent } from '../template/components/TestComponent.js';
5
- //# sourceMappingURL=components.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/exports/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0DAA0D,CAAA;AACpG,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA"}
@@ -1,5 +0,0 @@
1
- export { Callout, Tabs } from '@radix-ui/themes';
2
- export { GraphQLDocumentWithSchema } from '../template/components/content/GraphQLDocumentWrapper.js';
3
- export { mdxComponents } from '../template/components/MDXComponents.js';
4
- export { TestComponent } from '../template/components/TestComponent.js';
5
- //# sourceMappingURL=components.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/exports/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0DAA0D,CAAA;AACpG,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA"}
@@ -1,10 +0,0 @@
1
- import React from 'react';
2
- interface PreProps {
3
- children: React.ReactNode;
4
- className?: string;
5
- }
6
- export declare const mdxComponents: {
7
- pre: React.FC<PreProps>;
8
- };
9
- export {};
10
- //# sourceMappingURL=MDXComponents.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MDXComponents.d.ts","sourceRoot":"","sources":["../../../src/template/components/MDXComponents.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,UAAU,QAAQ;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AASD,eAAO,MAAM,aAAa;;CAEzB,CAAA"}
@@ -1,12 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import React from 'react';
3
- /**
4
- * Simple pre component that renders code blocks as-is
5
- */
6
- const Pre = ({ children, className, ...props }) => {
7
- return _jsx("pre", { className: className, ...props, children: children });
8
- };
9
- export const mdxComponents = {
10
- pre: Pre,
11
- };
12
- //# sourceMappingURL=MDXComponents.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MDXComponents.js","sourceRoot":"","sources":["../../../src/template/components/MDXComponents.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;GAEG;AACH,MAAM,GAAG,GAAuB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE;IACpE,OAAO,cAAK,SAAS,EAAE,SAAS,KAAM,KAAK,YAAG,QAAQ,GAAO,CAAA;AAC/D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,GAAG;CACT,CAAA"}
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- export declare const TestComponent: React.FC<{
3
- children: React.ReactNode;
4
- }>;
5
- //# sourceMappingURL=TestComponent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TestComponent.d.ts","sourceRoot":"","sources":["../../../src/template/components/TestComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAGjE,CAAA"}