@raystack/chronicle 0.1.0-canary.323385a → 0.1.0-canary.3e58cd9

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 (80) hide show
  1. package/dist/cli/index.js +268 -9902
  2. package/package.json +20 -12
  3. package/src/cli/commands/build.ts +27 -25
  4. package/src/cli/commands/dev.ts +24 -25
  5. package/src/cli/commands/init.ts +38 -132
  6. package/src/cli/commands/serve.ts +36 -49
  7. package/src/cli/commands/start.ts +20 -25
  8. package/src/cli/index.ts +14 -14
  9. package/src/cli/utils/config.ts +25 -26
  10. package/src/cli/utils/index.ts +3 -3
  11. package/src/cli/utils/resolve.ts +9 -3
  12. package/src/cli/utils/scaffold.ts +11 -124
  13. package/src/components/mdx/code.tsx +10 -1
  14. package/src/components/mdx/details.module.css +1 -26
  15. package/src/components/mdx/details.tsx +2 -3
  16. package/src/components/mdx/image.tsx +5 -34
  17. package/src/components/mdx/index.tsx +15 -1
  18. package/src/components/mdx/link.tsx +18 -15
  19. package/src/components/ui/breadcrumbs.tsx +8 -42
  20. package/src/components/ui/search.tsx +63 -51
  21. package/src/lib/api-routes.ts +6 -8
  22. package/src/lib/config.ts +12 -35
  23. package/src/lib/head.tsx +49 -0
  24. package/src/lib/openapi.ts +8 -8
  25. package/src/lib/page-context.tsx +111 -0
  26. package/src/lib/source.ts +134 -63
  27. package/src/pages/ApiLayout.tsx +33 -0
  28. package/src/pages/ApiPage.tsx +73 -0
  29. package/src/pages/DocsLayout.tsx +18 -0
  30. package/src/pages/DocsPage.tsx +43 -0
  31. package/src/pages/NotFound.tsx +17 -0
  32. package/src/server/App.tsx +67 -0
  33. package/src/server/api/apis-proxy.ts +69 -0
  34. package/src/server/api/health.ts +5 -0
  35. package/src/server/api/page/[...slug].ts +17 -0
  36. package/src/server/api/search.ts +118 -0
  37. package/src/server/api/specs.ts +9 -0
  38. package/src/server/build-search-index.ts +117 -0
  39. package/src/server/entry-client.tsx +86 -0
  40. package/src/server/entry-server.tsx +100 -0
  41. package/src/server/routes/llms.txt.ts +21 -0
  42. package/src/server/routes/og.tsx +75 -0
  43. package/src/server/routes/robots.txt.ts +11 -0
  44. package/src/server/routes/sitemap.xml.ts +40 -0
  45. package/src/server/utils/safe-path.ts +17 -0
  46. package/src/server/vite-config.ts +126 -0
  47. package/src/themes/default/Layout.tsx +78 -48
  48. package/src/themes/default/Page.module.css +44 -0
  49. package/src/themes/default/Page.tsx +9 -11
  50. package/src/themes/default/Toc.tsx +25 -39
  51. package/src/themes/default/index.ts +7 -9
  52. package/src/themes/paper/ChapterNav.tsx +64 -45
  53. package/src/themes/paper/Layout.module.css +1 -1
  54. package/src/themes/paper/Layout.tsx +24 -12
  55. package/src/themes/paper/Page.module.css +16 -4
  56. package/src/themes/paper/Page.tsx +56 -63
  57. package/src/themes/paper/ReadingProgress.tsx +160 -139
  58. package/src/themes/paper/index.ts +5 -5
  59. package/src/themes/registry.ts +7 -7
  60. package/src/types/config.ts +11 -0
  61. package/src/types/content.ts +6 -21
  62. package/src/types/globals.d.ts +4 -0
  63. package/src/types/theme.ts +4 -3
  64. package/tsconfig.json +2 -3
  65. package/next.config.mjs +0 -10
  66. package/source.config.ts +0 -50
  67. package/src/app/[[...slug]]/layout.tsx +0 -15
  68. package/src/app/[[...slug]]/page.tsx +0 -57
  69. package/src/app/api/apis-proxy/route.ts +0 -59
  70. package/src/app/api/health/route.ts +0 -3
  71. package/src/app/api/search/route.ts +0 -90
  72. package/src/app/apis/[[...slug]]/layout.tsx +0 -26
  73. package/src/app/apis/[[...slug]]/page.tsx +0 -57
  74. package/src/app/layout.tsx +0 -26
  75. package/src/app/llms-full.txt/route.ts +0 -18
  76. package/src/app/llms.txt/route.ts +0 -15
  77. package/src/app/providers.tsx +0 -8
  78. package/src/cli/utils/process.ts +0 -7
  79. package/src/themes/default/font.ts +0 -6
  80. /package/src/{app/apis/[[...slug]]/layout.module.css → pages/ApiLayout.module.css} +0 -0
@@ -1,46 +1,46 @@
1
- 'use client'
1
+ 'use client';
2
2
 
3
- import { cx } from 'class-variance-authority'
4
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
5
- import type { TocItem } from '@/types'
6
- import styles from './ReadingProgress.module.css'
3
+ import { cx } from 'class-variance-authority';
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import type { TOCItemType } from 'fumadocs-core/toc';
6
+ import styles from './ReadingProgress.module.css';
7
7
 
8
8
  interface Heading {
9
- title: string
10
- level: number
11
- id: string
12
- url: string
13
- yPosition: number
9
+ title: string;
10
+ level: number;
11
+ id: string;
12
+ url: string;
13
+ yPosition: number;
14
14
  }
15
15
 
16
- const ARTICLE_SELECTOR = '[data-article-content]'
17
- const TICK_HEIGHT = 20
18
- const NAV_HEIGHT = 60
16
+ const ARTICLE_SELECTOR = '[data-article-content]';
17
+ const TICK_HEIGHT = 20;
18
+ const NAV_HEIGHT = 60;
19
19
 
20
20
  function calculateTickBounds(containerHeight: number) {
21
- const numTicks = Math.floor(containerHeight / TICK_HEIGHT) + 1
22
- const maxPosition = (numTicks - 1) * TICK_HEIGHT
23
- return { numTicks, maxPosition }
21
+ const numTicks = Math.floor(containerHeight / TICK_HEIGHT) + 1;
22
+ const maxPosition = (numTicks - 1) * TICK_HEIGHT;
23
+ return { numTicks, maxPosition };
24
24
  }
25
25
 
26
26
  function snapToTick(value: number, maxPosition: number): number {
27
- const snapped = Math.round(value / TICK_HEIGHT) * TICK_HEIGHT
28
- return Math.max(0, Math.min(snapped, maxPosition))
27
+ const snapped = Math.round(value / TICK_HEIGHT) * TICK_HEIGHT;
28
+ return Math.max(0, Math.min(snapped, maxPosition));
29
29
  }
30
30
 
31
31
  function resolveOverlaps(headings: Heading[], maxPosition: number): Heading[] {
32
- if (headings.length <= 1) return headings
32
+ if (headings.length <= 1) return headings;
33
33
 
34
- const resolved: Heading[] = []
35
- let lastUsedPos = -TICK_HEIGHT
34
+ const resolved: Heading[] = [];
35
+ let lastUsedPos = -TICK_HEIGHT;
36
36
 
37
37
  for (const heading of headings) {
38
- let newPos = heading.yPosition
38
+ let newPos = heading.yPosition;
39
39
  if (newPos <= lastUsedPos) {
40
- newPos = lastUsedPos + TICK_HEIGHT
40
+ newPos = lastUsedPos + TICK_HEIGHT;
41
41
  }
42
- resolved.push({ ...heading, yPosition: newPos })
43
- lastUsedPos = newPos
42
+ resolved.push({ ...heading, yPosition: newPos });
43
+ lastUsedPos = newPos;
44
44
  }
45
45
 
46
46
  // Backward pass: clamp-and-shift to prevent overlapping positions
@@ -48,193 +48,212 @@ function resolveOverlaps(headings: Heading[], maxPosition: number): Heading[] {
48
48
  const maxAllowed =
49
49
  i === resolved.length - 1
50
50
  ? maxPosition
51
- : resolved[i + 1].yPosition - TICK_HEIGHT
51
+ : resolved[i + 1].yPosition - TICK_HEIGHT;
52
52
 
53
- const clampedPos = Math.max(0, maxAllowed)
53
+ const clampedPos = Math.max(0, maxAllowed);
54
54
  if (resolved[i].yPosition > clampedPos) {
55
- resolved[i] = { ...resolved[i], yPosition: clampedPos }
55
+ resolved[i] = { ...resolved[i], yPosition: clampedPos };
56
56
  for (let j = i - 1; j >= 0; j--) {
57
- const upperBound = resolved[j + 1].yPosition - TICK_HEIGHT
57
+ const upperBound = resolved[j + 1].yPosition - TICK_HEIGHT;
58
58
  if (resolved[j].yPosition > upperBound) {
59
- resolved[j] = { ...resolved[j], yPosition: Math.max(0, upperBound) }
59
+ resolved[j] = { ...resolved[j], yPosition: Math.max(0, upperBound) };
60
60
  } else {
61
- break
61
+ break;
62
62
  }
63
63
  }
64
64
  }
65
65
  }
66
66
 
67
- return resolved
67
+ return resolved;
68
68
  }
69
69
 
70
70
  interface ReadingProgressProps {
71
- items: TocItem[]
71
+ items: TOCItemType[];
72
72
  }
73
73
 
74
74
  export function ReadingProgress({ items }: ReadingProgressProps) {
75
- const [headings, setHeadings] = useState<Heading[]>([])
76
- const [containerHeight, setContainerHeight] = useState<number>(0)
77
- const [ready, setReady] = useState<boolean>(false)
78
- const [isScrollable, setIsScrollable] = useState<boolean>(true)
79
- const containerRef = useRef<HTMLDivElement>(null)
80
- const scrollMarkerRef = useRef<HTMLDivElement>(null)
81
- const scrollPosRef = useRef<number>(0)
75
+ const [headings, setHeadings] = useState<Heading[]>([]);
76
+ const [containerHeight, setContainerHeight] = useState<number>(0);
77
+ const [ready, setReady] = useState<boolean>(false);
78
+ const [isScrollable, setIsScrollable] = useState<boolean>(true);
79
+ const containerRef = useRef<HTMLDivElement>(null);
80
+ const scrollMarkerRef = useRef<HTMLDivElement>(null);
81
+ const scrollPosRef = useRef<number>(0);
82
82
 
83
83
  const { numTicks, maxPosition } = useMemo(
84
84
  () => calculateTickBounds(containerHeight),
85
85
  [containerHeight]
86
- )
86
+ );
87
87
 
88
88
  const recalcHeadings = useCallback(() => {
89
- const article = document.querySelector(ARTICLE_SELECTOR)
90
- const container = containerRef.current
91
- if (!article || !container || !items.length) return
89
+ const article = document.querySelector(ARTICLE_SELECTOR);
90
+ const container = containerRef.current;
91
+ if (!article || !container || !items.length) return;
92
92
 
93
- const articleBox = article.getBoundingClientRect()
94
- const containerBox = container.getBoundingClientRect()
95
- const articleTop = articleBox.top + window.scrollY
93
+ const articleBox = article.getBoundingClientRect();
94
+ const containerBox = container.getBoundingClientRect();
95
+ const articleTop = articleBox.top + window.scrollY;
96
96
 
97
- const hasScroll = articleBox.height > window.innerHeight
98
- setIsScrollable(hasScroll)
99
- setContainerHeight(containerBox.height)
97
+ const hasScroll = articleBox.height > window.innerHeight;
98
+ setIsScrollable(hasScroll);
99
+ setContainerHeight(containerBox.height);
100
100
 
101
- const { maxPosition: maxPos } = calculateTickBounds(containerBox.height)
101
+ const { maxPosition: maxPos } = calculateTickBounds(containerBox.height);
102
102
 
103
103
  const mapped = items
104
- .map((tocItem) => {
105
- const id = tocItem.url.startsWith('#') ? tocItem.url.slice(1) : tocItem.url
106
- const node = document.getElementById(id)
107
- if (!node) return null
108
-
109
- const { top } = node.getBoundingClientRect()
110
- const headingPosInArticle = top + window.scrollY - articleTop
111
- const progress = headingPosInArticle / articleBox.height
112
- const rawY = progress * maxPos
113
- const yPos = snapToTick(rawY, maxPos)
104
+ .map(tocItem => {
105
+ const id = tocItem.url.startsWith('#')
106
+ ? tocItem.url.slice(1)
107
+ : tocItem.url;
108
+ const node = document.getElementById(id);
109
+ if (!node) return null;
110
+
111
+ const { top } = node.getBoundingClientRect();
112
+ const headingPosInArticle = top + window.scrollY - articleTop;
113
+ const progress = headingPosInArticle / articleBox.height;
114
+ const rawY = progress * maxPos;
115
+ const yPos = snapToTick(rawY, maxPos);
114
116
 
115
117
  return {
116
118
  title: tocItem.title,
117
119
  level: tocItem.depth,
118
120
  id,
119
121
  url: tocItem.url,
120
- yPosition: yPos,
121
- }
122
+ yPosition: yPos
123
+ };
122
124
  })
123
- .filter((item): item is Heading => item !== null)
125
+ .filter((item): item is Heading => item !== null);
124
126
 
125
- const resolvedItems = resolveOverlaps(mapped, maxPos)
126
- setHeadings(resolvedItems)
127
- }, [items])
127
+ const resolvedItems = resolveOverlaps(mapped, maxPos);
128
+ setHeadings(resolvedItems);
129
+ }, [items]);
128
130
 
129
131
  // Imperative DOM updates to avoid React re-render on every scroll event
130
132
  const handleScroll = useCallback(() => {
131
- const article = document.querySelector(ARTICLE_SELECTOR)
132
- const container = containerRef.current
133
- const scrollMarker = scrollMarkerRef.current
134
- if (!article || !container || !scrollMarker) return
133
+ const article = document.querySelector(ARTICLE_SELECTOR);
134
+ const container = containerRef.current;
135
+ const scrollMarker = scrollMarkerRef.current;
136
+ if (!article || !container || !scrollMarker) return;
135
137
 
136
- const { top, height } = article.getBoundingClientRect()
137
- const { height: cHeight } = container.getBoundingClientRect()
138
- const viewportHeight = window.innerHeight
139
- const { maxPosition: maxPos } = calculateTickBounds(cHeight)
138
+ const { top, height } = article.getBoundingClientRect();
139
+ const { height: cHeight } = container.getBoundingClientRect();
140
+ const viewportHeight = window.innerHeight;
141
+ const { maxPosition: maxPos } = calculateTickBounds(cHeight);
140
142
 
141
- let newScrollPos: number
143
+ let newScrollPos: number;
142
144
  if (top > 0) {
143
- newScrollPos = 0
145
+ newScrollPos = 0;
144
146
  } else {
145
- const scrolled = Math.abs(top)
146
- const scrollRange = height - viewportHeight
147
- const progress = scrollRange > 0 ? Math.min(1, scrolled / scrollRange) : 0
148
- const rawPos = progress * maxPos
149
- newScrollPos = snapToTick(rawPos, maxPos)
147
+ const scrolled = Math.abs(top);
148
+ const scrollRange = height - viewportHeight;
149
+ const progress =
150
+ scrollRange > 0 ? Math.min(1, scrolled / scrollRange) : 0;
151
+ const rawPos = progress * maxPos;
152
+ newScrollPos = snapToTick(rawPos, maxPos);
150
153
  }
151
154
 
152
- const prevScrollPos = scrollPosRef.current
155
+ const prevScrollPos = scrollPosRef.current;
153
156
  if (newScrollPos !== prevScrollPos) {
154
- scrollPosRef.current = newScrollPos
155
- scrollMarker.style.top = `${newScrollPos}px`
157
+ scrollPosRef.current = newScrollPos;
158
+ scrollMarker.style.top = `${newScrollPos}px`;
156
159
 
157
- const textEl = scrollMarker.querySelector('[data-scroll-text]')
160
+ const textEl = scrollMarker.querySelector('[data-scroll-text]');
158
161
  if (textEl) {
159
- textEl.textContent = (maxPos > 0 ? newScrollPos / maxPos : 0).toFixed(2)
162
+ textEl.textContent = (maxPos > 0 ? newScrollPos / maxPos : 0).toFixed(
163
+ 2
164
+ );
160
165
  }
161
166
 
162
- const tickLines = container.querySelectorAll('[data-tick-line]')
163
- tickLines.forEach((tick) => {
164
- const tickPos = Number(tick.getAttribute('data-tick-pos'))
167
+ const tickLines = container.querySelectorAll('[data-tick-line]');
168
+ tickLines.forEach(tick => {
169
+ const tickPos = Number(tick.getAttribute('data-tick-pos'));
165
170
  if (tickPos < newScrollPos) {
166
- tick.classList.remove(styles.tickLineAfter)
167
- tick.classList.add(styles.tickLineBefore)
171
+ tick.classList.remove(styles.tickLineAfter);
172
+ tick.classList.add(styles.tickLineBefore);
168
173
  } else {
169
- tick.classList.remove(styles.tickLineBefore)
170
- tick.classList.add(styles.tickLineAfter)
174
+ tick.classList.remove(styles.tickLineBefore);
175
+ tick.classList.add(styles.tickLineAfter);
171
176
  }
172
- })
177
+ });
173
178
  }
174
- }, [])
179
+ }, []);
175
180
 
176
181
  useEffect(() => {
177
- recalcHeadings()
178
- handleScroll()
179
- setReady(true)
182
+ recalcHeadings();
183
+ handleScroll();
184
+ setReady(true);
180
185
 
181
- const article = document.querySelector(ARTICLE_SELECTOR)
182
- let ro: ResizeObserver | undefined
186
+ const article = document.querySelector(ARTICLE_SELECTOR);
187
+ let ro: ResizeObserver | undefined;
183
188
  if (article) {
184
189
  ro = new ResizeObserver(() => {
185
- recalcHeadings()
186
- handleScroll()
187
- })
188
- ro.observe(article)
190
+ recalcHeadings();
191
+ handleScroll();
192
+ });
193
+ ro.observe(article);
189
194
  }
190
195
 
191
- window.addEventListener('resize', recalcHeadings)
192
- window.addEventListener('scroll', handleScroll, { passive: true })
196
+ window.addEventListener('resize', recalcHeadings);
197
+ window.addEventListener('scroll', handleScroll, { passive: true });
193
198
 
194
199
  return () => {
195
- ro?.disconnect()
196
- window.removeEventListener('resize', recalcHeadings)
197
- window.removeEventListener('scroll', handleScroll)
198
- }
199
- }, [recalcHeadings, handleScroll])
200
+ ro?.disconnect();
201
+ window.removeEventListener('resize', recalcHeadings);
202
+ window.removeEventListener('scroll', handleScroll);
203
+ };
204
+ }, [recalcHeadings, handleScroll]);
200
205
 
201
206
  const scrollToTick = (y: number): void => {
202
- const article = document.querySelector(ARTICLE_SELECTOR)
203
- if (!article || maxPosition === 0) return
207
+ const article = document.querySelector(ARTICLE_SELECTOR);
208
+ if (!article || maxPosition === 0) return;
204
209
 
205
- const articleBox = article.getBoundingClientRect()
206
- const articleTop = articleBox.top + window.scrollY
207
- const progress = y / maxPosition
208
- const articlePos = progress * articleBox.height
209
- const targetScroll = articleTop + articlePos - NAV_HEIGHT
210
+ const articleBox = article.getBoundingClientRect();
211
+ const articleTop = articleBox.top + window.scrollY;
212
+ const progress = y / maxPosition;
213
+ const articlePos = progress * articleBox.height;
214
+ const targetScroll = articleTop + articlePos - NAV_HEIGHT;
210
215
 
211
- window.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' })
212
- }
216
+ window.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' });
217
+ };
213
218
 
214
219
  const scrollToHeading = (id: string): void => {
215
- const element = document.getElementById(id)
216
- if (!element) return
220
+ const element = document.getElementById(id);
221
+ if (!element) return;
217
222
 
218
- const elementTop = element.getBoundingClientRect().top + window.scrollY
219
- window.scrollTo({ top: Math.max(0, elementTop - NAV_HEIGHT), behavior: 'smooth' })
220
- }
223
+ const elementTop = element.getBoundingClientRect().top + window.scrollY;
224
+ window.scrollTo({
225
+ top: Math.max(0, elementTop - NAV_HEIGHT),
226
+ behavior: 'smooth'
227
+ });
228
+ };
221
229
 
222
230
  const ticks = useMemo(
223
231
  () => Array.from({ length: numTicks }, (_, i) => i * TICK_HEIGHT),
224
232
  [numTicks]
225
- )
233
+ );
226
234
 
227
235
  if (!isScrollable || ticks.length < 2) {
228
- return <div ref={containerRef} className={styles.container} />
236
+ return <div ref={containerRef} className={styles.container} />;
229
237
  }
230
238
 
231
239
  return (
232
240
  <div ref={containerRef} className={styles.container}>
233
241
  <div className={styles.inner}>
234
242
  {ticks.map((y, i) => (
235
- <div key={`tick-${i}`} style={{ top: `${y}px` }} className={styles.tickContainer}>
236
- <div data-tick-line data-tick-pos={y} className={cx(styles.tickLine, styles.tickLineAfter)} />
237
- <div className={styles.tickClickable} onClick={() => scrollToTick(y)} />
243
+ <div
244
+ key={`tick-${i}`}
245
+ style={{ top: `${y}px` }}
246
+ className={styles.tickContainer}
247
+ >
248
+ <div
249
+ data-tick-line
250
+ data-tick-pos={y}
251
+ className={cx(styles.tickLine, styles.tickLineAfter)}
252
+ />
253
+ <div
254
+ className={styles.tickClickable}
255
+ onClick={() => scrollToTick(y)}
256
+ />
238
257
  </div>
239
258
  ))}
240
259
 
@@ -246,16 +265,16 @@ export function ReadingProgress({ items }: ReadingProgressProps) {
246
265
  top: `${h.yPosition - 6}px`,
247
266
  right: '24px',
248
267
  zIndex: h.level < 4 ? 10 : 0,
249
- transitionDelay: `${50 * i}ms`,
268
+ transitionDelay: `${50 * i}ms`
250
269
  }}
251
270
  >
252
271
  <a
253
272
  href={h.url}
254
273
  className={styles.headingLink}
255
- onClick={(e) => {
256
- e.preventDefault()
257
- e.stopPropagation()
258
- scrollToHeading(h.id)
274
+ onClick={e => {
275
+ e.preventDefault();
276
+ e.stopPropagation();
277
+ scrollToHeading(h.id);
259
278
  }}
260
279
  >
261
280
  {h.title}
@@ -270,7 +289,7 @@ export function ReadingProgress({ items }: ReadingProgressProps) {
270
289
  className={styles.connectingLine}
271
290
  style={{
272
291
  top: `${h.yPosition}px`,
273
- width: `${Math.max(4, (3 - h.level) * 4 + 12)}px`,
292
+ width: `${Math.max(4, (3 - h.level) * 4 + 12)}px`
274
293
  }}
275
294
  />
276
295
  ))}
@@ -279,7 +298,9 @@ export function ReadingProgress({ items }: ReadingProgressProps) {
279
298
  ref={scrollMarkerRef}
280
299
  className={cx(
281
300
  styles.scrollMarkerContainer,
282
- ready ? styles.scrollMarkerContainerReady : styles.scrollMarkerContainerNotReady
301
+ ready
302
+ ? styles.scrollMarkerContainerReady
303
+ : styles.scrollMarkerContainerNotReady
283
304
  )}
284
305
  style={{ top: '0px' }}
285
306
  >
@@ -290,5 +311,5 @@ export function ReadingProgress({ items }: ReadingProgressProps) {
290
311
  </div>
291
312
  </div>
292
313
  </div>
293
- )
314
+ );
294
315
  }
@@ -1,8 +1,8 @@
1
- import { Layout } from './Layout'
2
- import { Page } from './Page'
3
- import type { Theme } from '@/types'
1
+ import type { Theme } from '@/types';
2
+ import { Layout } from './Layout';
3
+ import { Page } from './Page';
4
4
 
5
5
  export const paperTheme: Theme = {
6
6
  Layout,
7
- Page,
8
- }
7
+ Page
8
+ };
@@ -1,14 +1,14 @@
1
- import type { Theme } from '@/types'
2
- import { defaultTheme } from './default'
3
- import { paperTheme } from './paper'
1
+ import type { Theme } from '@/types';
2
+ import { defaultTheme } from './default';
3
+ import { paperTheme } from './paper';
4
4
 
5
5
  const themes: Record<string, Theme> = {
6
6
  default: defaultTheme,
7
- paper: paperTheme,
8
- }
7
+ paper: paperTheme
8
+ };
9
9
 
10
10
  export function getTheme(name?: string): Theme {
11
- if (!name || !themes[name]) return defaultTheme
11
+ if (!name || !themes[name]) return defaultTheme;
12
12
 
13
- return themes[name]
13
+ return themes[name];
14
14
  }
@@ -1,6 +1,7 @@
1
1
  export interface ChronicleConfig {
2
2
  title: string
3
3
  description?: string
4
+ url?: string
4
5
  logo?: LogoConfig
5
6
  theme?: ThemeConfig
6
7
  navigation?: NavigationConfig
@@ -8,12 +9,22 @@ export interface ChronicleConfig {
8
9
  footer?: FooterConfig
9
10
  api?: ApiConfig[]
10
11
  llms?: LlmsConfig
12
+ analytics?: AnalyticsConfig
11
13
  }
12
14
 
13
15
  export interface LlmsConfig {
14
16
  enabled?: boolean
15
17
  }
16
18
 
19
+ export interface AnalyticsConfig {
20
+ enabled?: boolean
21
+ googleAnalytics?: GoogleAnalyticsConfig
22
+ }
23
+
24
+ export interface GoogleAnalyticsConfig {
25
+ measurementId: string
26
+ }
27
+
17
28
  export interface ApiConfig {
18
29
  name: string
19
30
  spec: string
@@ -1,35 +1,20 @@
1
1
  import type { ReactNode } from 'react'
2
+ import type { TableOfContents } from 'fumadocs-core/toc'
3
+
4
+ export type { Root, Node, Item, Folder, Separator } from 'fumadocs-core/page-tree'
5
+ export type { TOCItemType, TableOfContents } from 'fumadocs-core/toc'
2
6
 
3
7
  export interface Frontmatter {
4
8
  title: string
5
9
  description?: string
6
10
  order?: number
7
11
  icon?: string
12
+ lastModified?: string
8
13
  }
9
14
 
10
15
  export interface Page {
11
16
  slug: string[]
12
17
  frontmatter: Frontmatter
13
18
  content: ReactNode
14
- toc: TocItem[]
15
- }
16
-
17
- export interface TocItem {
18
- title: string
19
- url: string
20
- depth: number
21
- }
22
-
23
- export interface PageTreeItem {
24
- type: 'page' | 'folder' | 'separator'
25
- name: string
26
- url?: string
27
- order?: number
28
- icon?: string
29
- children?: PageTreeItem[]
30
- }
31
-
32
- export interface PageTree {
33
- name: string
34
- children: PageTreeItem[]
19
+ toc: TableOfContents
35
20
  }
@@ -0,0 +1,4 @@
1
+ // Vite build-time constants (injected via define in vite-config.ts)
2
+ declare const __CHRONICLE_CONTENT_DIR__: string
3
+ declare const __CHRONICLE_PROJECT_ROOT__: string
4
+ declare const __CHRONICLE_CONFIG_RAW__: string | null
@@ -1,18 +1,19 @@
1
1
  import type { ReactNode } from 'react'
2
+ import type { Root } from 'fumadocs-core/page-tree'
2
3
  import type { ChronicleConfig } from './config'
3
- import type { Page, PageTree } from './content'
4
+ import type { Page } from './content'
4
5
 
5
6
  export interface ThemeLayoutProps {
6
7
  children: ReactNode
7
8
  config: ChronicleConfig
8
- tree: PageTree
9
+ tree: Root
9
10
  classNames?: { layout?: string; body?: string; sidebar?: string; content?: string }
10
11
  }
11
12
 
12
13
  export interface ThemePageProps {
13
14
  page: Page
14
15
  config: ChronicleConfig
15
- tree: PageTree
16
+ tree: Root
16
17
  }
17
18
 
18
19
  export interface Theme {
package/tsconfig.json CHANGED
@@ -21,10 +21,9 @@
21
21
  "lib": ["ES2022", "DOM", "DOM.Iterable"],
22
22
  "moduleResolution": "bundler",
23
23
  "paths": {
24
- "@/*": ["./src/*"],
25
- "@/.source/*": ["./.source/*"]
24
+ "@/*": ["./src/*"]
26
25
  }
27
26
  },
28
- "include": ["src", ".source", "source.config.ts"],
27
+ "include": ["src"],
29
28
  "exclude": ["node_modules", "dist"]
30
29
  }
package/next.config.mjs DELETED
@@ -1,10 +0,0 @@
1
- import { createMDX } from 'fumadocs-mdx/next'
2
-
3
- const withMDX = createMDX()
4
-
5
- /** @type {import('next').NextConfig} */
6
- const nextConfig = {
7
- reactStrictMode: true,
8
- }
9
-
10
- export default withMDX(nextConfig)
package/source.config.ts DELETED
@@ -1,50 +0,0 @@
1
- import { defineDocs, defineConfig, frontmatterSchema } from 'fumadocs-mdx/config'
2
- import { z } from 'zod'
3
- import remarkDirective from 'remark-directive'
4
- import { remarkDirectiveAdmonition, remarkMdxMermaid } from 'fumadocs-core/mdx-plugins'
5
- import remarkUnusedDirectives from './src/lib/remark-unused-directives'
6
-
7
- const contentDir = process.env.CHRONICLE_CONTENT_DIR || './content'
8
-
9
- export const docs = defineDocs({
10
- dir: contentDir,
11
- docs: {
12
- schema: frontmatterSchema.extend({
13
- order: z.number().optional(),
14
- }),
15
- postprocess: {
16
- includeProcessedMarkdown: true,
17
- },
18
- files: ['**/*.mdx', '**/*.md', '!**/node_modules/**'],
19
- },
20
- })
21
-
22
- export default defineConfig({
23
- mdxOptions: {
24
- remarkPlugins: [
25
- remarkDirective,
26
- [
27
- remarkDirectiveAdmonition,
28
- {
29
- tags: {
30
- CalloutContainer: 'Callout',
31
- CalloutTitle: 'CalloutTitle',
32
- CalloutDescription: 'CalloutDescription',
33
- },
34
- types: {
35
- note: 'accent',
36
- tip: 'accent',
37
- info: 'accent',
38
- warn: 'attention',
39
- warning: 'attention',
40
- danger: 'alert',
41
- caution: 'alert',
42
- success: 'success',
43
- },
44
- },
45
- ],
46
- remarkUnusedDirectives,
47
- remarkMdxMermaid,
48
- ],
49
- },
50
- })
@@ -1,15 +0,0 @@
1
- import { loadConfig } from '@/lib/config'
2
- import { buildPageTree } from '@/lib/source'
3
- import { getTheme } from '@/themes/registry'
4
-
5
- export default function DocsLayout({ children }: { children: React.ReactNode }) {
6
- const config = loadConfig()
7
- const tree = buildPageTree()
8
- const { Layout, className } = getTheme(config.theme?.name)
9
-
10
- return (
11
- <Layout config={config} tree={tree} classNames={{ layout: className }}>
12
- {children}
13
- </Layout>
14
- )
15
- }