@raystack/chronicle 0.1.0-canary.1f5227c

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 (124) hide show
  1. package/bin/chronicle.js +2 -0
  2. package/dist/cli/index.js +543 -0
  3. package/package.json +68 -0
  4. package/src/cli/__tests__/config.test.ts +25 -0
  5. package/src/cli/__tests__/scaffold.test.ts +10 -0
  6. package/src/cli/commands/build.ts +52 -0
  7. package/src/cli/commands/dev.ts +21 -0
  8. package/src/cli/commands/init.ts +154 -0
  9. package/src/cli/commands/serve.ts +55 -0
  10. package/src/cli/commands/start.ts +24 -0
  11. package/src/cli/index.ts +21 -0
  12. package/src/cli/utils/config.ts +43 -0
  13. package/src/cli/utils/index.ts +2 -0
  14. package/src/cli/utils/resolve.ts +6 -0
  15. package/src/cli/utils/scaffold.ts +20 -0
  16. package/src/components/api/code-snippets.module.css +7 -0
  17. package/src/components/api/code-snippets.tsx +76 -0
  18. package/src/components/api/endpoint-page.module.css +58 -0
  19. package/src/components/api/endpoint-page.tsx +283 -0
  20. package/src/components/api/field-row.module.css +126 -0
  21. package/src/components/api/field-row.tsx +204 -0
  22. package/src/components/api/field-section.module.css +24 -0
  23. package/src/components/api/field-section.tsx +100 -0
  24. package/src/components/api/index.ts +8 -0
  25. package/src/components/api/json-editor.module.css +9 -0
  26. package/src/components/api/json-editor.tsx +61 -0
  27. package/src/components/api/key-value-editor.module.css +13 -0
  28. package/src/components/api/key-value-editor.tsx +62 -0
  29. package/src/components/api/method-badge.module.css +4 -0
  30. package/src/components/api/method-badge.tsx +29 -0
  31. package/src/components/api/response-panel.module.css +8 -0
  32. package/src/components/api/response-panel.tsx +44 -0
  33. package/src/components/common/breadcrumb.tsx +3 -0
  34. package/src/components/common/button.tsx +3 -0
  35. package/src/components/common/callout.module.css +7 -0
  36. package/src/components/common/callout.tsx +27 -0
  37. package/src/components/common/code-block.tsx +3 -0
  38. package/src/components/common/dialog.tsx +3 -0
  39. package/src/components/common/index.ts +10 -0
  40. package/src/components/common/input-field.tsx +3 -0
  41. package/src/components/common/sidebar.tsx +3 -0
  42. package/src/components/common/switch.tsx +3 -0
  43. package/src/components/common/table.tsx +3 -0
  44. package/src/components/common/tabs.tsx +3 -0
  45. package/src/components/mdx/code.module.css +42 -0
  46. package/src/components/mdx/code.tsx +36 -0
  47. package/src/components/mdx/details.module.css +14 -0
  48. package/src/components/mdx/details.tsx +17 -0
  49. package/src/components/mdx/image.tsx +24 -0
  50. package/src/components/mdx/index.tsx +35 -0
  51. package/src/components/mdx/link.tsx +37 -0
  52. package/src/components/mdx/mermaid.module.css +9 -0
  53. package/src/components/mdx/mermaid.tsx +37 -0
  54. package/src/components/mdx/paragraph.module.css +8 -0
  55. package/src/components/mdx/paragraph.tsx +19 -0
  56. package/src/components/mdx/table.tsx +40 -0
  57. package/src/components/ui/breadcrumbs.tsx +72 -0
  58. package/src/components/ui/client-theme-switcher.tsx +18 -0
  59. package/src/components/ui/footer.module.css +27 -0
  60. package/src/components/ui/footer.tsx +31 -0
  61. package/src/components/ui/search.module.css +111 -0
  62. package/src/components/ui/search.tsx +174 -0
  63. package/src/lib/api-routes.ts +120 -0
  64. package/src/lib/config.ts +56 -0
  65. package/src/lib/head.tsx +45 -0
  66. package/src/lib/index.ts +2 -0
  67. package/src/lib/openapi.ts +188 -0
  68. package/src/lib/page-context.tsx +95 -0
  69. package/src/lib/remark-unused-directives.ts +30 -0
  70. package/src/lib/schema.ts +99 -0
  71. package/src/lib/snippet-generators.ts +87 -0
  72. package/src/lib/source.ts +138 -0
  73. package/src/pages/ApiLayout.module.css +22 -0
  74. package/src/pages/ApiLayout.tsx +29 -0
  75. package/src/pages/ApiPage.tsx +68 -0
  76. package/src/pages/DocsLayout.tsx +18 -0
  77. package/src/pages/DocsPage.tsx +43 -0
  78. package/src/pages/NotFound.tsx +10 -0
  79. package/src/pages/__tests__/head.test.tsx +57 -0
  80. package/src/server/App.tsx +59 -0
  81. package/src/server/__tests__/entry-server.test.tsx +35 -0
  82. package/src/server/__tests__/handlers.test.ts +77 -0
  83. package/src/server/__tests__/og.test.ts +23 -0
  84. package/src/server/__tests__/router.test.ts +72 -0
  85. package/src/server/__tests__/vite-config.test.ts +25 -0
  86. package/src/server/dev.ts +156 -0
  87. package/src/server/entry-client.tsx +74 -0
  88. package/src/server/entry-prod.ts +127 -0
  89. package/src/server/entry-server.tsx +35 -0
  90. package/src/server/handlers/apis-proxy.ts +52 -0
  91. package/src/server/handlers/health.ts +3 -0
  92. package/src/server/handlers/llms.ts +58 -0
  93. package/src/server/handlers/og.ts +87 -0
  94. package/src/server/handlers/robots.ts +11 -0
  95. package/src/server/handlers/search.ts +140 -0
  96. package/src/server/handlers/sitemap.ts +39 -0
  97. package/src/server/handlers/specs.ts +9 -0
  98. package/src/server/index.html +12 -0
  99. package/src/server/prod.ts +18 -0
  100. package/src/server/router.ts +42 -0
  101. package/src/server/vite-config.ts +71 -0
  102. package/src/themes/default/Layout.module.css +81 -0
  103. package/src/themes/default/Layout.tsx +132 -0
  104. package/src/themes/default/Page.module.css +102 -0
  105. package/src/themes/default/Page.tsx +21 -0
  106. package/src/themes/default/Toc.module.css +48 -0
  107. package/src/themes/default/Toc.tsx +66 -0
  108. package/src/themes/default/font.ts +4 -0
  109. package/src/themes/default/index.ts +13 -0
  110. package/src/themes/paper/ChapterNav.module.css +71 -0
  111. package/src/themes/paper/ChapterNav.tsx +95 -0
  112. package/src/themes/paper/Layout.module.css +33 -0
  113. package/src/themes/paper/Layout.tsx +25 -0
  114. package/src/themes/paper/Page.module.css +174 -0
  115. package/src/themes/paper/Page.tsx +106 -0
  116. package/src/themes/paper/ReadingProgress.module.css +132 -0
  117. package/src/themes/paper/ReadingProgress.tsx +294 -0
  118. package/src/themes/paper/index.ts +8 -0
  119. package/src/themes/registry.ts +14 -0
  120. package/src/types/config.ts +80 -0
  121. package/src/types/content.ts +36 -0
  122. package/src/types/index.ts +3 -0
  123. package/src/types/theme.ts +22 -0
  124. package/tsconfig.json +29 -0
@@ -0,0 +1,132 @@
1
+ .container {
2
+ position: fixed;
3
+ right: var(--rs-space-4);
4
+ top: 100px;
5
+ width: 200px;
6
+ height: calc(100vh - 200px);
7
+ z-index: 10;
8
+ }
9
+
10
+ .inner {
11
+ position: absolute;
12
+ inset: 0;
13
+ }
14
+
15
+ .tickContainer {
16
+ position: absolute;
17
+ right: 0;
18
+ display: grid;
19
+ width: 6rem;
20
+ align-items: center;
21
+ justify-content: flex-end;
22
+ }
23
+
24
+ .tickLine {
25
+ height: 1px;
26
+ width: 0.5rem;
27
+ transition: all 100ms;
28
+ }
29
+
30
+ .tickLineBefore {
31
+ background-color: var(--rs-color-foreground-accent-primary);
32
+ }
33
+
34
+ .tickLineAfter {
35
+ background-color: var(--rs-color-background-neutral-tertiary);
36
+ }
37
+
38
+ .tickContainer:hover .tickLine {
39
+ width: 1rem;
40
+ }
41
+
42
+ .tickClickable {
43
+ position: absolute;
44
+ inset-inline: 0;
45
+ height: 0.5rem;
46
+ cursor: pointer;
47
+ }
48
+
49
+ .headingContainer {
50
+ transition: transform 150ms;
51
+ }
52
+
53
+ .headingContainer:hover {
54
+ transform: translateX(-0.125rem);
55
+ }
56
+
57
+ .headingLabel {
58
+ position: absolute;
59
+ display: flex;
60
+ height: 0.75rem;
61
+ align-items: center;
62
+ font-family: var(--rs-font-mono);
63
+ font-size: 0.75rem;
64
+ color: var(--rs-color-foreground-base-primary);
65
+ text-transform: capitalize;
66
+ opacity: 0;
67
+ transition: opacity 300ms;
68
+ }
69
+
70
+ .headingLink {
71
+ color: var(--rs-color-foreground-base-primary);
72
+ text-align: right;
73
+ font-family: var(--rs-font-mono);
74
+ font-size: var(--rs-font-size-mini);
75
+ font-weight: var(--rs-font-weight-regular);
76
+ line-height: var(--rs-line-height-mini);
77
+ letter-spacing: var(--rs-letter-spacing-mini);
78
+ text-decoration: none;
79
+ cursor: pointer;
80
+ }
81
+
82
+ .headingLink:hover {
83
+ color: var(--rs-color-foreground-accent-primary);
84
+ }
85
+
86
+ .container:hover .headingLabel {
87
+ opacity: 1;
88
+ }
89
+
90
+ .connectingLine {
91
+ position: absolute;
92
+ right: 0;
93
+ height: 1px;
94
+ background-color: var(--rs-color-background-neutral-emphasis);
95
+ }
96
+
97
+ .scrollMarkerContainer {
98
+ position: absolute;
99
+ right: 0;
100
+ z-index: 20;
101
+ transition: opacity 300ms;
102
+ pointer-events: none;
103
+ }
104
+
105
+ .scrollMarkerContainerReady {
106
+ opacity: 1;
107
+ }
108
+
109
+ .scrollMarkerContainerNotReady {
110
+ opacity: 0;
111
+ }
112
+
113
+ .scrollMarkerLine {
114
+ height: 1px;
115
+ width: 1rem;
116
+ background-color: var(--rs-color-foreground-accent-primary);
117
+ }
118
+
119
+ .scrollMarkerText {
120
+ position: absolute;
121
+ top: 0;
122
+ left: -2.5rem;
123
+ transform: translateY(-50%);
124
+ font-family: var(--rs-font-mono);
125
+ font-size: 0.75rem;
126
+ color: var(--rs-color-foreground-accent-primary);
127
+ transition: opacity 300ms;
128
+ }
129
+
130
+ .container:hover .scrollMarkerText {
131
+ opacity: 0;
132
+ }
@@ -0,0 +1,294 @@
1
+ 'use client'
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'
7
+
8
+ interface Heading {
9
+ title: string
10
+ level: number
11
+ id: string
12
+ url: string
13
+ yPosition: number
14
+ }
15
+
16
+ const ARTICLE_SELECTOR = '[data-article-content]'
17
+ const TICK_HEIGHT = 20
18
+ const NAV_HEIGHT = 60
19
+
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 }
24
+ }
25
+
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))
29
+ }
30
+
31
+ function resolveOverlaps(headings: Heading[], maxPosition: number): Heading[] {
32
+ if (headings.length <= 1) return headings
33
+
34
+ const resolved: Heading[] = []
35
+ let lastUsedPos = -TICK_HEIGHT
36
+
37
+ for (const heading of headings) {
38
+ let newPos = heading.yPosition
39
+ if (newPos <= lastUsedPos) {
40
+ newPos = lastUsedPos + TICK_HEIGHT
41
+ }
42
+ resolved.push({ ...heading, yPosition: newPos })
43
+ lastUsedPos = newPos
44
+ }
45
+
46
+ // Backward pass: clamp-and-shift to prevent overlapping positions
47
+ for (let i = resolved.length - 1; i >= 0; i--) {
48
+ const maxAllowed =
49
+ i === resolved.length - 1
50
+ ? maxPosition
51
+ : resolved[i + 1].yPosition - TICK_HEIGHT
52
+
53
+ const clampedPos = Math.max(0, maxAllowed)
54
+ if (resolved[i].yPosition > clampedPos) {
55
+ resolved[i] = { ...resolved[i], yPosition: clampedPos }
56
+ for (let j = i - 1; j >= 0; j--) {
57
+ const upperBound = resolved[j + 1].yPosition - TICK_HEIGHT
58
+ if (resolved[j].yPosition > upperBound) {
59
+ resolved[j] = { ...resolved[j], yPosition: Math.max(0, upperBound) }
60
+ } else {
61
+ break
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ return resolved
68
+ }
69
+
70
+ interface ReadingProgressProps {
71
+ items: TocItem[]
72
+ }
73
+
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)
82
+
83
+ const { numTicks, maxPosition } = useMemo(
84
+ () => calculateTickBounds(containerHeight),
85
+ [containerHeight]
86
+ )
87
+
88
+ const recalcHeadings = useCallback(() => {
89
+ const article = document.querySelector(ARTICLE_SELECTOR)
90
+ const container = containerRef.current
91
+ if (!article || !container || !items.length) return
92
+
93
+ const articleBox = article.getBoundingClientRect()
94
+ const containerBox = container.getBoundingClientRect()
95
+ const articleTop = articleBox.top + window.scrollY
96
+
97
+ const hasScroll = articleBox.height > window.innerHeight
98
+ setIsScrollable(hasScroll)
99
+ setContainerHeight(containerBox.height)
100
+
101
+ const { maxPosition: maxPos } = calculateTickBounds(containerBox.height)
102
+
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)
114
+
115
+ return {
116
+ title: tocItem.title,
117
+ level: tocItem.depth,
118
+ id,
119
+ url: tocItem.url,
120
+ yPosition: yPos,
121
+ }
122
+ })
123
+ .filter((item): item is Heading => item !== null)
124
+
125
+ const resolvedItems = resolveOverlaps(mapped, maxPos)
126
+ setHeadings(resolvedItems)
127
+ }, [items])
128
+
129
+ // Imperative DOM updates to avoid React re-render on every scroll event
130
+ 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
135
+
136
+ const { top, height } = article.getBoundingClientRect()
137
+ const { height: cHeight } = container.getBoundingClientRect()
138
+ const viewportHeight = window.innerHeight
139
+ const { maxPosition: maxPos } = calculateTickBounds(cHeight)
140
+
141
+ let newScrollPos: number
142
+ if (top > 0) {
143
+ newScrollPos = 0
144
+ } 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)
150
+ }
151
+
152
+ const prevScrollPos = scrollPosRef.current
153
+ if (newScrollPos !== prevScrollPos) {
154
+ scrollPosRef.current = newScrollPos
155
+ scrollMarker.style.top = `${newScrollPos}px`
156
+
157
+ const textEl = scrollMarker.querySelector('[data-scroll-text]')
158
+ if (textEl) {
159
+ textEl.textContent = (maxPos > 0 ? newScrollPos / maxPos : 0).toFixed(2)
160
+ }
161
+
162
+ const tickLines = container.querySelectorAll('[data-tick-line]')
163
+ tickLines.forEach((tick) => {
164
+ const tickPos = Number(tick.getAttribute('data-tick-pos'))
165
+ if (tickPos < newScrollPos) {
166
+ tick.classList.remove(styles.tickLineAfter)
167
+ tick.classList.add(styles.tickLineBefore)
168
+ } else {
169
+ tick.classList.remove(styles.tickLineBefore)
170
+ tick.classList.add(styles.tickLineAfter)
171
+ }
172
+ })
173
+ }
174
+ }, [])
175
+
176
+ useEffect(() => {
177
+ recalcHeadings()
178
+ handleScroll()
179
+ setReady(true)
180
+
181
+ const article = document.querySelector(ARTICLE_SELECTOR)
182
+ let ro: ResizeObserver | undefined
183
+ if (article) {
184
+ ro = new ResizeObserver(() => {
185
+ recalcHeadings()
186
+ handleScroll()
187
+ })
188
+ ro.observe(article)
189
+ }
190
+
191
+ window.addEventListener('resize', recalcHeadings)
192
+ window.addEventListener('scroll', handleScroll, { passive: true })
193
+
194
+ return () => {
195
+ ro?.disconnect()
196
+ window.removeEventListener('resize', recalcHeadings)
197
+ window.removeEventListener('scroll', handleScroll)
198
+ }
199
+ }, [recalcHeadings, handleScroll])
200
+
201
+ const scrollToTick = (y: number): void => {
202
+ const article = document.querySelector(ARTICLE_SELECTOR)
203
+ if (!article || maxPosition === 0) return
204
+
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
+
211
+ window.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' })
212
+ }
213
+
214
+ const scrollToHeading = (id: string): void => {
215
+ const element = document.getElementById(id)
216
+ if (!element) return
217
+
218
+ const elementTop = element.getBoundingClientRect().top + window.scrollY
219
+ window.scrollTo({ top: Math.max(0, elementTop - NAV_HEIGHT), behavior: 'smooth' })
220
+ }
221
+
222
+ const ticks = useMemo(
223
+ () => Array.from({ length: numTicks }, (_, i) => i * TICK_HEIGHT),
224
+ [numTicks]
225
+ )
226
+
227
+ if (!isScrollable || ticks.length < 2) {
228
+ return <div ref={containerRef} className={styles.container} />
229
+ }
230
+
231
+ return (
232
+ <div ref={containerRef} className={styles.container}>
233
+ <div className={styles.inner}>
234
+ {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)} />
238
+ </div>
239
+ ))}
240
+
241
+ {headings.map((h, i) => (
242
+ <div key={h.id || i} className={styles.headingContainer}>
243
+ <div
244
+ className={styles.headingLabel}
245
+ style={{
246
+ top: `${h.yPosition - 6}px`,
247
+ right: '24px',
248
+ zIndex: h.level < 4 ? 10 : 0,
249
+ transitionDelay: `${50 * i}ms`,
250
+ }}
251
+ >
252
+ <a
253
+ href={h.url}
254
+ className={styles.headingLink}
255
+ onClick={(e) => {
256
+ e.preventDefault()
257
+ e.stopPropagation()
258
+ scrollToHeading(h.id)
259
+ }}
260
+ >
261
+ {h.title}
262
+ </a>
263
+ </div>
264
+ </div>
265
+ ))}
266
+
267
+ {headings.map((h, i) => (
268
+ <div
269
+ key={`line-${i}`}
270
+ className={styles.connectingLine}
271
+ style={{
272
+ top: `${h.yPosition}px`,
273
+ width: `${Math.max(4, (3 - h.level) * 4 + 12)}px`,
274
+ }}
275
+ />
276
+ ))}
277
+
278
+ <div
279
+ ref={scrollMarkerRef}
280
+ className={cx(
281
+ styles.scrollMarkerContainer,
282
+ ready ? styles.scrollMarkerContainerReady : styles.scrollMarkerContainerNotReady
283
+ )}
284
+ style={{ top: '0px' }}
285
+ >
286
+ <div className={styles.scrollMarkerLine} />
287
+ <span data-scroll-text className={styles.scrollMarkerText}>
288
+ 0.00
289
+ </span>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ )
294
+ }
@@ -0,0 +1,8 @@
1
+ import { Layout } from './Layout'
2
+ import { Page } from './Page'
3
+ import type { Theme } from '@/types'
4
+
5
+ export const paperTheme: Theme = {
6
+ Layout,
7
+ Page,
8
+ }
@@ -0,0 +1,14 @@
1
+ import type { Theme } from '@/types'
2
+ import { defaultTheme } from './default'
3
+ import { paperTheme } from './paper'
4
+
5
+ const themes: Record<string, Theme> = {
6
+ default: defaultTheme,
7
+ paper: paperTheme,
8
+ }
9
+
10
+ export function getTheme(name?: string): Theme {
11
+ if (!name || !themes[name]) return defaultTheme
12
+
13
+ return themes[name]
14
+ }
@@ -0,0 +1,80 @@
1
+ export interface ChronicleConfig {
2
+ title: string
3
+ description?: string
4
+ url?: string
5
+ logo?: LogoConfig
6
+ theme?: ThemeConfig
7
+ navigation?: NavigationConfig
8
+ search?: SearchConfig
9
+ footer?: FooterConfig
10
+ api?: ApiConfig[]
11
+ llms?: LlmsConfig
12
+ analytics?: AnalyticsConfig
13
+ }
14
+
15
+ export interface LlmsConfig {
16
+ enabled?: boolean
17
+ }
18
+
19
+ export interface AnalyticsConfig {
20
+ enabled?: boolean
21
+ googleAnalytics?: GoogleAnalyticsConfig
22
+ }
23
+
24
+ export interface GoogleAnalyticsConfig {
25
+ measurementId: string
26
+ }
27
+
28
+ export interface ApiConfig {
29
+ name: string
30
+ spec: string
31
+ basePath: string
32
+ server: ApiServerConfig
33
+ auth?: ApiAuthConfig
34
+ }
35
+
36
+ export interface ApiServerConfig {
37
+ url: string
38
+ description?: string
39
+ }
40
+
41
+ export interface ApiAuthConfig {
42
+ type: string
43
+ header: string
44
+ placeholder?: string
45
+ }
46
+
47
+ export interface LogoConfig {
48
+ light?: string
49
+ dark?: string
50
+ }
51
+
52
+ export interface ThemeConfig {
53
+ name: 'default' | 'paper'
54
+ colors?: Record<string, string>
55
+ }
56
+
57
+ export interface NavigationConfig {
58
+ links?: NavLink[]
59
+ social?: SocialLink[]
60
+ }
61
+
62
+ export interface NavLink {
63
+ label: string
64
+ href: string
65
+ }
66
+
67
+ export interface SocialLink {
68
+ type: 'github' | 'twitter' | 'discord' | string
69
+ href: string
70
+ }
71
+
72
+ export interface SearchConfig {
73
+ enabled?: boolean
74
+ placeholder?: string
75
+ }
76
+
77
+ export interface FooterConfig {
78
+ copyright?: string
79
+ links?: NavLink[]
80
+ }
@@ -0,0 +1,36 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ export interface Frontmatter {
4
+ title: string
5
+ description?: string
6
+ order?: number
7
+ icon?: string
8
+ lastModified?: string
9
+ }
10
+
11
+ export interface Page {
12
+ slug: string[]
13
+ frontmatter: Frontmatter
14
+ content: ReactNode
15
+ toc: TocItem[]
16
+ }
17
+
18
+ export interface TocItem {
19
+ title: string
20
+ url: string
21
+ depth: number
22
+ }
23
+
24
+ export interface PageTreeItem {
25
+ type: 'page' | 'folder' | 'separator'
26
+ name: string
27
+ url?: string
28
+ order?: number
29
+ icon?: string
30
+ children?: PageTreeItem[]
31
+ }
32
+
33
+ export interface PageTree {
34
+ name: string
35
+ children: PageTreeItem[]
36
+ }
@@ -0,0 +1,3 @@
1
+ export * from './config'
2
+ export * from './content'
3
+ export * from './theme'
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from 'react'
2
+ import type { ChronicleConfig } from './config'
3
+ import type { Page, PageTree } from './content'
4
+
5
+ export interface ThemeLayoutProps {
6
+ children: ReactNode
7
+ config: ChronicleConfig
8
+ tree: PageTree
9
+ classNames?: { layout?: string; body?: string; sidebar?: string; content?: string }
10
+ }
11
+
12
+ export interface ThemePageProps {
13
+ page: Page
14
+ config: ChronicleConfig
15
+ tree: PageTree
16
+ }
17
+
18
+ export interface Theme {
19
+ Layout: React.ComponentType<ThemeLayoutProps>
20
+ Page: React.ComponentType<ThemePageProps>
21
+ className?: string
22
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": false,
4
+ "declaration": true,
5
+ "declarationMap": true,
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "inlineSources": false,
9
+ "isolatedModules": true,
10
+ "noUnusedLocals": false,
11
+ "noUnusedParameters": false,
12
+ "preserveWatchOutput": true,
13
+ "skipLibCheck": true,
14
+ "strict": true,
15
+ "jsx": "react-jsx",
16
+ "module": "ESNext",
17
+ "target": "es6",
18
+ "outDir": "dist",
19
+ "rootDir": ".",
20
+ "baseUrl": ".",
21
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
22
+ "moduleResolution": "bundler",
23
+ "paths": {
24
+ "@/*": ["./src/*"]
25
+ }
26
+ },
27
+ "include": ["src"],
28
+ "exclude": ["node_modules", "dist"]
29
+ }