@geenius/docs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.github/CODEOWNERS +1 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  6. package/.github/dependabot.yml +11 -0
  7. package/.github/workflows/ci.yml +23 -0
  8. package/.github/workflows/release.yml +29 -0
  9. package/.nvmrc +1 -0
  10. package/.project/ACCOUNT.yaml +4 -0
  11. package/.project/IDEAS.yaml +7 -0
  12. package/.project/PROJECT.yaml +11 -0
  13. package/.project/ROADMAP.yaml +15 -0
  14. package/CHANGELOG.md +11 -0
  15. package/CODE_OF_CONDUCT.md +16 -0
  16. package/CONTRIBUTING.md +26 -0
  17. package/LICENSE +21 -0
  18. package/README.md +1 -0
  19. package/SECURITY.md +15 -0
  20. package/SUPPORT.md +8 -0
  21. package/package.json +58 -0
  22. package/packages/convex/README.md +1 -0
  23. package/packages/convex/package.json +12 -0
  24. package/packages/convex/src/convex.config.ts +3 -0
  25. package/packages/convex/src/index.ts +3 -0
  26. package/packages/convex/src/mutations.ts +270 -0
  27. package/packages/convex/src/queries.ts +175 -0
  28. package/packages/convex/src/schema.ts +55 -0
  29. package/packages/react/README.md +1 -0
  30. package/packages/react/package.json +36 -0
  31. package/packages/react/src/DocsLayout.tsx +116 -0
  32. package/packages/react/src/DocsProvider.tsx +93 -0
  33. package/packages/react/src/RouterDocsContent.tsx +148 -0
  34. package/packages/react/src/RouterDocsLayout.tsx +161 -0
  35. package/packages/react/src/components/Breadcrumbs.tsx +34 -0
  36. package/packages/react/src/components/DocPage.tsx +191 -0
  37. package/packages/react/src/components/DocSearch.tsx +140 -0
  38. package/packages/react/src/components/DocSidebar.tsx +86 -0
  39. package/packages/react/src/components/DocsLayout.tsx +62 -0
  40. package/packages/react/src/components/EditButton.tsx +26 -0
  41. package/packages/react/src/components/PageNavigation.tsx +45 -0
  42. package/packages/react/src/components/TableOfContents.tsx +46 -0
  43. package/packages/react/src/components/VersionSelector.tsx +60 -0
  44. package/packages/react/src/components/index.ts +9 -0
  45. package/packages/react/src/hooks/index.ts +8 -0
  46. package/packages/react/src/hooks/useDocSearch.ts +55 -0
  47. package/packages/react/src/hooks/useDocs.ts +57 -0
  48. package/packages/react/src/hooks/useDocsAdmin.ts +151 -0
  49. package/packages/react/src/hooks/useTableOfContents.ts +66 -0
  50. package/packages/react/src/index.ts +38 -0
  51. package/packages/react/src/pages/DocSearchPage.tsx +129 -0
  52. package/packages/react/src/pages/DocViewPage.tsx +158 -0
  53. package/packages/react/src/pages/DocsAdminPage.tsx +330 -0
  54. package/packages/react/src/pages/DocsIndexPage.tsx +172 -0
  55. package/packages/react/src/pages/index.ts +4 -0
  56. package/packages/react/src/useDocs.ts +58 -0
  57. package/packages/react/tsup.config.ts +12 -0
  58. package/packages/react-css/README.md +1 -0
  59. package/packages/react-css/package.json +37 -0
  60. package/packages/react-css/src/DocsLayout.tsx +117 -0
  61. package/packages/react-css/src/DocsProvider.tsx +93 -0
  62. package/packages/react-css/src/RouterDocsContent.tsx +60 -0
  63. package/packages/react-css/src/RouterDocsLayout.tsx +101 -0
  64. package/packages/react-css/src/components/DocPage.tsx +21 -0
  65. package/packages/react-css/src/components/DocSearch.tsx +55 -0
  66. package/packages/react-css/src/components/DocSidebar.tsx +56 -0
  67. package/packages/react-css/src/components/DocsLayout.tsx +28 -0
  68. package/packages/react-css/src/components/common.tsx +93 -0
  69. package/packages/react-css/src/components/index.ts +5 -0
  70. package/packages/react-css/src/hooks/index.ts +2 -0
  71. package/packages/react-css/src/index.ts +6 -0
  72. package/packages/react-css/src/index.tsx +3 -0
  73. package/packages/react-css/src/pages/DocViewPage.tsx +78 -0
  74. package/packages/react-css/src/pages/DocsAdminPage.tsx +101 -0
  75. package/packages/react-css/src/pages/DocsIndexPage.tsx +68 -0
  76. package/packages/react-css/src/pages/index.ts +3 -0
  77. package/packages/react-css/src/styles.css +1271 -0
  78. package/packages/react-css/src/useDocs.ts +58 -0
  79. package/packages/react-css/tsconfig.json +19 -0
  80. package/packages/react-css/tsup.config.ts +10 -0
  81. package/packages/shared/README.md +1 -0
  82. package/packages/shared/package.json +31 -0
  83. package/packages/shared/src/__tests__/docs.test.ts +69 -0
  84. package/packages/shared/src/config.ts +80 -0
  85. package/packages/shared/src/index.ts +179 -0
  86. package/packages/shared/src/providers/astro.ts +94 -0
  87. package/packages/shared/src/providers/fumadocs.ts +116 -0
  88. package/packages/shared/src/providers/internal.ts +80 -0
  89. package/packages/shared/src/types.ts +73 -0
  90. package/packages/shared/tsconfig.json +18 -0
  91. package/packages/shared/tsup.config.ts +12 -0
  92. package/packages/shared/vitest.config.ts +4 -0
  93. package/packages/solidjs/README.md +1 -0
  94. package/packages/solidjs/package.json +33 -0
  95. package/packages/solidjs/src/DocsLayout.tsx +87 -0
  96. package/packages/solidjs/src/DocsProvider.tsx +95 -0
  97. package/packages/solidjs/src/RouterDocsContent.tsx +147 -0
  98. package/packages/solidjs/src/RouterDocsLayout.tsx +161 -0
  99. package/packages/solidjs/src/components/Breadcrumbs.tsx +27 -0
  100. package/packages/solidjs/src/components/DocPage.tsx +110 -0
  101. package/packages/solidjs/src/components/DocSearch.tsx +81 -0
  102. package/packages/solidjs/src/components/DocSidebar.tsx +92 -0
  103. package/packages/solidjs/src/components/DocsLayout.tsx +38 -0
  104. package/packages/solidjs/src/components/EditButton.tsx +15 -0
  105. package/packages/solidjs/src/components/PageNavigation.tsx +31 -0
  106. package/packages/solidjs/src/components/TableOfContents.tsx +41 -0
  107. package/packages/solidjs/src/components/VersionSelector.tsx +30 -0
  108. package/packages/solidjs/src/components/index.ts +9 -0
  109. package/packages/solidjs/src/createDocs.ts +62 -0
  110. package/packages/solidjs/src/index.ts +28 -0
  111. package/packages/solidjs/src/pages/DocSearchPage.tsx +72 -0
  112. package/packages/solidjs/src/pages/DocViewPage.tsx +80 -0
  113. package/packages/solidjs/src/pages/DocsAdminPage.tsx +123 -0
  114. package/packages/solidjs/src/pages/DocsIndexPage.tsx +85 -0
  115. package/packages/solidjs/src/pages/index.ts +4 -0
  116. package/packages/solidjs/src/primitives/createDocSearch.ts +42 -0
  117. package/packages/solidjs/src/primitives/createDocs.ts +35 -0
  118. package/packages/solidjs/src/primitives/createDocsAdmin.ts +63 -0
  119. package/packages/solidjs/src/primitives/createTableOfContents.ts +51 -0
  120. package/packages/solidjs/src/primitives/index.ts +4 -0
  121. package/packages/solidjs/tsup.config.ts +12 -0
  122. package/packages/solidjs-css/README.md +1 -0
  123. package/packages/solidjs-css/package.json +36 -0
  124. package/packages/solidjs-css/src/DocsLayout.tsx +106 -0
  125. package/packages/solidjs-css/src/DocsProvider.tsx +95 -0
  126. package/packages/solidjs-css/src/RouterDocsContent.tsx +54 -0
  127. package/packages/solidjs-css/src/RouterDocsLayout.tsx +104 -0
  128. package/packages/solidjs-css/src/createDocs.ts +62 -0
  129. package/packages/solidjs-css/src/index.ts +7 -0
  130. package/packages/solidjs-css/src/index.tsx +17 -0
  131. package/packages/solidjs-css/src/pages/DocViewPage.tsx +111 -0
  132. package/packages/solidjs-css/src/pages/DocsAdminPage.tsx +332 -0
  133. package/packages/solidjs-css/src/pages/DocsIndexPage.tsx +116 -0
  134. package/packages/solidjs-css/src/pages/index.ts +3 -0
  135. package/packages/solidjs-css/src/primitives/index.ts +1 -0
  136. package/packages/solidjs-css/src/styles.css +1271 -0
  137. package/packages/solidjs-css/tsconfig.json +20 -0
  138. package/packages/solidjs-css/tsup.config.ts +10 -0
  139. package/pnpm-workspace.yaml +2 -0
@@ -0,0 +1,332 @@
1
+ import { createSignal, createMemo, Show } from 'solid-js'
2
+ import type { DocPage, DocSection } from '@geenius-docs/shared'
3
+ import type { DocsAdminActions } from '@geenius-docs/react'
4
+ import '../styles.css'
5
+
6
+ interface DocsAdminPageProps {
7
+ tree: (DocSection & { pages: DocPage[]; pageCount: number })[] | undefined
8
+ allPages?: DocPage[]
9
+ admin: DocsAdminActions
10
+ }
11
+
12
+ export function DocsAdminPage(props: DocsAdminPageProps) {
13
+ const sections = createMemo(() => props.tree ?? [])
14
+ const [selectedId, setSelectedId] = createSignal<string | null>(null)
15
+ const [showSF, setShowSF] = createSignal(false)
16
+ const [showPF, setShowPF] = createSignal(false)
17
+ const [sf, setSf] = createSignal({ title: '', slug: '', description: '', icon: '', access: 'team' as const })
18
+ const [pf, setPf] = createSignal({ title: '', slug: '', content: '', access: 'team' as const, tags: '' })
19
+
20
+ const selected = createMemo(() => sections().find(s => s.id === selectedId()))
21
+ const pages = createMemo(() => {
22
+ if (!selected()) return []
23
+ if (props.allPages) return props.allPages.filter(p => p.sectionId === selectedId())
24
+ return selected()!.pages ?? []
25
+ })
26
+
27
+ return (
28
+ <Show
29
+ when={props.tree !== undefined}
30
+ fallback={
31
+ <div style={{ 'min-height': '100vh', background: 'var(--docs-bg)', padding: '3rem 1.5rem' }}>
32
+ <div style={{ 'max-width': '72rem', margin: '0 auto' }}>
33
+ <div class="docs__skeleton" style={{ width: '192px', height: '40px', 'margin-bottom': '32px' }} />
34
+ <div class="docs__admin-grid">
35
+ <div class="docs__skeleton" style={{ height: '384px' }} />
36
+ <div class="docs__skeleton" style={{ height: '384px' }} />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ }
41
+ >
42
+ <div style={{ 'min-height': '100vh', background: 'var(--docs-bg)', color: 'var(--docs-text)' }}>
43
+ <div style={{ 'max-width': '72rem', margin: '0 auto', padding: '3rem 1.5rem' }}>
44
+ <h1 style={{ 'font-size': '1.5rem', 'font-weight': '700', 'margin-bottom': '2rem' }}>Docs Admin</h1>
45
+ <div class="docs__admin-grid">
46
+ <div class="docs__admin-panel">
47
+ <div class="docs__admin-panel-header">
48
+ <h2 class="docs__admin-panel-title">Sections</h2>
49
+ <button
50
+ type="button"
51
+ class="docs__admin-add-btn"
52
+ onClick={() => setShowSF(!showSF())}
53
+ >
54
+ + Add
55
+ </button>
56
+ </div>
57
+ <Show when={showSF()}>
58
+ <div class="docs__admin-form">
59
+ <input
60
+ class="docs__admin-input"
61
+ placeholder="Title"
62
+ value={sf().title}
63
+ onChange={e => setSf({ ...sf(), title: e.target.value })}
64
+ />
65
+ <input
66
+ class="docs__admin-input"
67
+ placeholder="Slug"
68
+ value={sf().slug}
69
+ onChange={e => setSf({ ...sf(), slug: e.target.value })}
70
+ />
71
+ <input
72
+ class="docs__admin-input"
73
+ placeholder="Icon"
74
+ value={sf().icon}
75
+ onChange={e => setSf({ ...sf(), icon: e.target.value })}
76
+ />
77
+ <input
78
+ class="docs__admin-input"
79
+ placeholder="Description"
80
+ value={sf().description}
81
+ onChange={e => setSf({ ...sf(), description: e.target.value })}
82
+ />
83
+ <div class="docs__admin-form-actions">
84
+ <button
85
+ type="button"
86
+ class="docs__admin-add-btn"
87
+ onClick={async () => {
88
+ await props.admin.createSection({
89
+ ...sf(),
90
+ order: sections().length,
91
+ icon: sf().icon || undefined,
92
+ description: sf().description || undefined,
93
+ })
94
+ setSf({ title: '', slug: '', description: '', icon: '', access: 'team' })
95
+ setShowSF(false)
96
+ }}
97
+ >
98
+ Create
99
+ </button>
100
+ <button
101
+ type="button"
102
+ style={{
103
+ padding: '0.375rem 0.75rem',
104
+ border: '1px solid var(--docs-border)',
105
+ 'border-radius': 'var(--docs-radius)',
106
+ background: 'transparent',
107
+ color: 'var(--docs-text)',
108
+ 'font-size': '0.6875rem',
109
+ cursor: 'pointer',
110
+ }}
111
+ onClick={() => setShowSF(false)}
112
+ >
113
+ Cancel
114
+ </button>
115
+ </div>
116
+ </div>
117
+ </Show>
118
+ <Show
119
+ when={sections().length > 0}
120
+ fallback={
121
+ <p
122
+ style={{
123
+ padding: '2rem',
124
+ 'text-align': 'center',
125
+ 'font-size': '0.875rem',
126
+ color: 'var(--docs-text-muted)',
127
+ }}
128
+ >
129
+ No sections
130
+ </p>
131
+ }
132
+ >
133
+ {sections().map(s => (
134
+ <div
135
+ key={s.id}
136
+ class={`docs__admin-section-item ${selectedId() === s.id ? 'docs__admin-section-item--selected' : ''}`}
137
+ onClick={() => setSelectedId(s.id)}
138
+ >
139
+ {s.icon && <span>{s.icon}</span>}
140
+ <span
141
+ style={{
142
+ flex: '1',
143
+ 'font-size': '0.875rem',
144
+ 'font-weight': '500',
145
+ overflow: 'hidden',
146
+ 'text-overflow': 'ellipsis',
147
+ 'white-space': 'nowrap',
148
+ }}
149
+ >
150
+ {s.title}
151
+ </span>
152
+ <span style={{ 'font-size': '0.6875rem', opacity: '0.4' }}>{s.pageCount ?? 0}</span>
153
+ <button
154
+ type="button"
155
+ style={{
156
+ background: 'transparent',
157
+ border: 'none',
158
+ color: 'oklch(1 0 0/0.2)',
159
+ cursor: 'pointer',
160
+ padding: '4px',
161
+ }}
162
+ onClick={e => {
163
+ e.stopPropagation()
164
+ if (confirm(`Delete "${s.title}"?`)) props.admin.deleteSection(s.id)
165
+ }}
166
+ >
167
+ ✕
168
+ </button>
169
+ </div>
170
+ ))}
171
+ </Show>
172
+ </div>
173
+ <div class="docs__admin-panel">
174
+ <div class="docs__admin-panel-header">
175
+ <h2 class="docs__admin-panel-title">
176
+ {selected() ? `Pages — ${selected()!.title}` : 'Pages'}
177
+ </h2>
178
+ {selected() && (
179
+ <button
180
+ type="button"
181
+ class="docs__admin-add-btn"
182
+ onClick={() => setShowPF(!showPF())}
183
+ >
184
+ + Add
185
+ </button>
186
+ )}
187
+ </div>
188
+ <Show
189
+ when={!selected()}
190
+ fallback={
191
+ <>
192
+ <Show when={showPF() && selected()}>
193
+ <div class="docs__admin-form">
194
+ <input
195
+ class="docs__admin-input"
196
+ placeholder="Title"
197
+ value={pf().title}
198
+ onChange={e => setPf({ ...pf(), title: e.target.value })}
199
+ />
200
+ <input
201
+ class="docs__admin-input"
202
+ placeholder="Slug"
203
+ value={pf().slug}
204
+ onChange={e => setPf({ ...pf(), slug: e.target.value })}
205
+ />
206
+ <textarea
207
+ class="docs__admin-input docs__admin-textarea"
208
+ placeholder="Content (MDX)"
209
+ value={pf().content}
210
+ onChange={e => setPf({ ...pf(), content: e.target.value })}
211
+ />
212
+ <input
213
+ class="docs__admin-input"
214
+ placeholder="Tags (comma)"
215
+ value={pf().tags}
216
+ onChange={e => setPf({ ...pf(), tags: e.target.value })}
217
+ />
218
+ <div class="docs__admin-form-actions">
219
+ <button
220
+ type="button"
221
+ class="docs__admin-add-btn"
222
+ onClick={async () => {
223
+ await props.admin.createPage({
224
+ title: pf().title,
225
+ slug: pf().slug,
226
+ content: pf().content,
227
+ sectionId: selectedId()!,
228
+ access: pf().access,
229
+ tags: pf().tags ? pf().tags.split(',').map(t => t.trim()) : [],
230
+ order: pages().length,
231
+ })
232
+ setPf({ title: '', slug: '', content: '', access: 'team', tags: '' })
233
+ setShowPF(false)
234
+ }}
235
+ >
236
+ Create
237
+ </button>
238
+ <button
239
+ type="button"
240
+ style={{
241
+ padding: '0.375rem 0.75rem',
242
+ border: '1px solid var(--docs-border)',
243
+ 'border-radius': 'var(--docs-radius)',
244
+ background: 'transparent',
245
+ color: 'var(--docs-text)',
246
+ 'font-size': '0.6875rem',
247
+ cursor: 'pointer',
248
+ }}
249
+ onClick={() => setShowPF(false)}
250
+ >
251
+ Cancel
252
+ </button>
253
+ </div>
254
+ </div>
255
+ </Show>
256
+ <Show
257
+ when={pages().length > 0}
258
+ fallback={
259
+ <p
260
+ style={{
261
+ padding: '3rem',
262
+ 'text-align': 'center',
263
+ 'font-size': '0.875rem',
264
+ color: 'var(--docs-text-muted)',
265
+ }}
266
+ >
267
+ No pages
268
+ </p>
269
+ }
270
+ >
271
+ {pages().map(page => (
272
+ <div key={page.id} class="docs__admin-page-item">
273
+ <div class="docs__admin-page-info">
274
+ <p class="docs__admin-page-title">{page.title}</p>
275
+ <p class="docs__admin-page-slug">/{page.slug}</p>
276
+ </div>
277
+ <span class={`docs__status-badge docs__status-badge--${page.status}`}>
278
+ {page.status}
279
+ </span>
280
+ <div class="docs__admin-actions">
281
+ {page.status === 'draft' && (
282
+ <button
283
+ type="button"
284
+ class="docs__admin-action-btn docs__admin-action-btn--publish"
285
+ onClick={() => props.admin.publishPage(page.id)}
286
+ >
287
+ Publish
288
+ </button>
289
+ )}
290
+ {page.status === 'published' && (
291
+ <button
292
+ type="button"
293
+ class="docs__admin-action-btn docs__admin-action-btn--archive"
294
+ onClick={() => props.admin.archivePage(page.id)}
295
+ >
296
+ Archive
297
+ </button>
298
+ )}
299
+ <button
300
+ type="button"
301
+ class="docs__admin-action-btn docs__admin-action-btn--delete"
302
+ onClick={() => {
303
+ if (confirm(`Delete "${page.title}"?`)) props.admin.deletePage(page.id)
304
+ }}
305
+ >
306
+ ✕
307
+ </button>
308
+ </div>
309
+ </div>
310
+ ))}
311
+ </Show>
312
+ </>
313
+ }
314
+ >
315
+ <p
316
+ style={{
317
+ padding: '4rem',
318
+ 'text-align': 'center',
319
+ 'font-size': '0.875rem',
320
+ color: 'var(--docs-text-muted)',
321
+ }}
322
+ >
323
+ Select a section
324
+ </p>
325
+ </Show>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+ </Show>
331
+ )
332
+ }
@@ -0,0 +1,116 @@
1
+ import { createSignal, createEffect, createMemo, Show } from 'solid-js'
2
+ import type { DocPage, DocSection, SearchResult } from '@geenius-docs/shared'
3
+ import { buildDocsIndex, searchDocs } from '@geenius-docs/shared'
4
+ import { useDocs, useDocSearch } from '../hooks'
5
+ import { DocSearch } from '../components/DocSearch'
6
+ import '../styles.css'
7
+
8
+ interface DocsIndexPageProps {
9
+ tree: (DocSection & { pages: DocPage[]; pageCount: number })[] | undefined
10
+ onSelectPage?: (page: DocPage, section: DocSection) => void
11
+ }
12
+
13
+ export function DocsIndexPage(props: DocsIndexPageProps) {
14
+ const docs = useDocs(() => props.tree)
15
+ const [isSearchOpen, setIsSearchOpen] = createSignal(false)
16
+
17
+ const searchFn = createMemo(() => (q: string): SearchResult[] => {
18
+ const idx = buildDocsIndex(docs().flatPages, docs().sections)
19
+ return searchDocs(q, idx)
20
+ })
21
+
22
+ const search = useDocSearch(searchFn)
23
+
24
+ createEffect(() => {
25
+ const handler = (e: KeyboardEvent) => {
26
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
27
+ e.preventDefault()
28
+ setIsSearchOpen(true)
29
+ }
30
+ }
31
+ document.addEventListener('keydown', handler)
32
+ return () => document.removeEventListener('keydown', handler)
33
+ })
34
+
35
+ return (
36
+ <Show
37
+ when={!docs().isLoading}
38
+ fallback={
39
+ <div style={{ 'min-height': '100vh', background: 'var(--docs-bg)', padding: '4rem 1.5rem' }}>
40
+ <div style={{ 'max-width': '64rem', margin: '0 auto' }}>
41
+ <div class="docs__skeleton" style={{ width: '256px', height: '40px', 'margin-bottom': '40px' }} />
42
+ <div class="docs__skeleton" style={{ 'max-width': '560px', height: '48px', 'margin-bottom': '32px' }} />
43
+ <div class="docs__section-grid">
44
+ {Array.from({ length: 6 }).map((_, i) => (
45
+ <div key={i} class="docs__skeleton" style={{ height: '144px' }} />
46
+ ))}
47
+ </div>
48
+ </div>
49
+ </div>
50
+ }
51
+ >
52
+ <Show
53
+ when={docs().sections.length > 0}
54
+ fallback={
55
+ <div class="docs__empty" style={{ 'min-height': '100vh', background: 'var(--docs-bg)' }}>
56
+ <div class="docs__empty-icon">📚</div>
57
+ <h2 class="docs__empty-title">No documentation yet</h2>
58
+ <p class="docs__empty-desc">Create your first section and pages to get started.</p>
59
+ </div>
60
+ }
61
+ >
62
+ <div style={{ 'min-height': '100vh', background: 'var(--docs-bg)', color: 'var(--docs-text)' }}>
63
+ <div style={{ 'max-width': '64rem', margin: '0 auto', padding: '4rem 1.5rem' }}>
64
+ <h1 style={{ 'font-size': '2.25rem', 'font-weight': '700', 'letter-spacing': '-0.02em', 'margin-bottom': '0.5rem' }}>Documentation</h1>
65
+ <p style={{ 'font-size': '1.125rem', color: 'var(--docs-text-muted)', 'margin-bottom': '2.5rem' }}>Browse guides, API references, and tutorials.</p>
66
+
67
+ <button
68
+ type="button"
69
+ class="docs__search-trigger"
70
+ onClick={() => setIsSearchOpen(true)}
71
+ >
72
+ <svg class="docs__search-trigger-icon" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd" /></svg>
73
+ <span class="docs__search-trigger-text">Search documentation…</span>
74
+ <kbd class="docs__search-trigger-kbd">⌘K</kbd>
75
+ </button>
76
+
77
+ <div class="docs__section-grid">
78
+ {docs()
79
+ .sections.filter(s => !s.parentId)
80
+ .map(section => (
81
+ <button
82
+ key={section.id}
83
+ type="button"
84
+ class="docs__section-card"
85
+ onClick={() => {
86
+ const fp = section.pages?.[0]
87
+ if (fp && props.onSelectPage) props.onSelectPage(fp, section)
88
+ }}
89
+ >
90
+ {section.icon && <div class="docs__section-card-icon">{section.icon}</div>}
91
+ <h3 class="docs__section-card-title">{section.title}</h3>
92
+ {section.description && <p class="docs__section-card-desc">{section.description}</p>}
93
+ <div class="docs__section-card-meta">{section.pageCount ?? 0} pages</div>
94
+ </button>
95
+ ))}
96
+ </div>
97
+ </div>
98
+ <DocSearch
99
+ results={search.results()}
100
+ query={search.query()}
101
+ onQuery={search.setQuery}
102
+ onSelect={r => {
103
+ setIsSearchOpen(false)
104
+ search.clearSearch()
105
+ const sec = docs().sections.find(s => s.slug === r.sectionSlug)
106
+ const pg = docs().flatPages.find(p => p.id === r.pageId)
107
+ if (pg && sec && props.onSelectPage) props.onSelectPage(pg, sec)
108
+ }}
109
+ isOpen={isSearchOpen()}
110
+ onClose={() => setIsSearchOpen(false)}
111
+ />
112
+ </div>
113
+ </Show>
114
+ </Show>
115
+ )
116
+ }
@@ -0,0 +1,3 @@
1
+ export { DocViewPage } from './DocViewPage'
2
+ export { DocsIndexPage } from './DocsIndexPage'
3
+ export { DocsAdminPage } from './DocsAdminPage'
@@ -0,0 +1 @@
1
+ export * from '@geenius-docs/solidjs';