@geenius/docs 0.1.0 → 0.4.1

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 (158) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +53 -1
  3. package/package.json +101 -13
  4. package/packages/convex/dist/index.d.ts +503 -0
  5. package/packages/convex/dist/index.js +482 -0
  6. package/packages/convex/dist/index.js.map +1 -0
  7. package/packages/react/dist/index.d.ts +439 -0
  8. package/packages/react/dist/index.js +4954 -0
  9. package/packages/react/dist/index.js.map +1 -0
  10. package/packages/react-css/{src/styles.css → dist/index.css} +183 -223
  11. package/packages/react-css/dist/index.css.map +1 -0
  12. package/packages/react-css/dist/index.d.ts +443 -0
  13. package/packages/react-css/dist/index.js +5058 -0
  14. package/packages/react-css/dist/index.js.map +1 -0
  15. package/packages/shared/dist/index.d.ts +684 -0
  16. package/packages/shared/dist/index.js +788 -0
  17. package/packages/shared/dist/index.js.map +1 -0
  18. package/packages/solidjs/dist/index.d.ts +435 -0
  19. package/packages/solidjs/dist/index.js +4584 -0
  20. package/packages/solidjs/dist/index.js.map +1 -0
  21. package/packages/solidjs-css/{src/styles.css → dist/index.css} +183 -223
  22. package/packages/solidjs-css/dist/index.css.map +1 -0
  23. package/packages/solidjs-css/dist/index.d.ts +432 -0
  24. package/packages/solidjs-css/dist/index.js +4934 -0
  25. package/packages/solidjs-css/dist/index.js.map +1 -0
  26. package/.changeset/config.json +0 -11
  27. package/.github/CODEOWNERS +0 -1
  28. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
  29. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
  30. package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
  31. package/.github/dependabot.yml +0 -11
  32. package/.github/workflows/ci.yml +0 -23
  33. package/.github/workflows/release.yml +0 -29
  34. package/.nvmrc +0 -1
  35. package/.project/ACCOUNT.yaml +0 -4
  36. package/.project/IDEAS.yaml +0 -7
  37. package/.project/PROJECT.yaml +0 -11
  38. package/.project/ROADMAP.yaml +0 -15
  39. package/CODE_OF_CONDUCT.md +0 -16
  40. package/CONTRIBUTING.md +0 -26
  41. package/SECURITY.md +0 -15
  42. package/SUPPORT.md +0 -8
  43. package/packages/convex/README.md +0 -1
  44. package/packages/convex/package.json +0 -12
  45. package/packages/convex/src/convex.config.ts +0 -3
  46. package/packages/convex/src/index.ts +0 -3
  47. package/packages/convex/src/mutations.ts +0 -270
  48. package/packages/convex/src/queries.ts +0 -175
  49. package/packages/convex/src/schema.ts +0 -55
  50. package/packages/react/README.md +0 -1
  51. package/packages/react/package.json +0 -36
  52. package/packages/react/src/DocsLayout.tsx +0 -116
  53. package/packages/react/src/DocsProvider.tsx +0 -93
  54. package/packages/react/src/RouterDocsContent.tsx +0 -148
  55. package/packages/react/src/RouterDocsLayout.tsx +0 -161
  56. package/packages/react/src/components/Breadcrumbs.tsx +0 -34
  57. package/packages/react/src/components/DocPage.tsx +0 -191
  58. package/packages/react/src/components/DocSearch.tsx +0 -140
  59. package/packages/react/src/components/DocSidebar.tsx +0 -86
  60. package/packages/react/src/components/DocsLayout.tsx +0 -62
  61. package/packages/react/src/components/EditButton.tsx +0 -26
  62. package/packages/react/src/components/PageNavigation.tsx +0 -45
  63. package/packages/react/src/components/TableOfContents.tsx +0 -46
  64. package/packages/react/src/components/VersionSelector.tsx +0 -60
  65. package/packages/react/src/components/index.ts +0 -9
  66. package/packages/react/src/hooks/index.ts +0 -8
  67. package/packages/react/src/hooks/useDocSearch.ts +0 -55
  68. package/packages/react/src/hooks/useDocs.ts +0 -57
  69. package/packages/react/src/hooks/useDocsAdmin.ts +0 -151
  70. package/packages/react/src/hooks/useTableOfContents.ts +0 -66
  71. package/packages/react/src/index.ts +0 -38
  72. package/packages/react/src/pages/DocSearchPage.tsx +0 -129
  73. package/packages/react/src/pages/DocViewPage.tsx +0 -158
  74. package/packages/react/src/pages/DocsAdminPage.tsx +0 -330
  75. package/packages/react/src/pages/DocsIndexPage.tsx +0 -172
  76. package/packages/react/src/pages/index.ts +0 -4
  77. package/packages/react/src/useDocs.ts +0 -58
  78. package/packages/react/tsup.config.ts +0 -12
  79. package/packages/react-css/README.md +0 -1
  80. package/packages/react-css/package.json +0 -37
  81. package/packages/react-css/src/DocsLayout.tsx +0 -117
  82. package/packages/react-css/src/DocsProvider.tsx +0 -93
  83. package/packages/react-css/src/RouterDocsContent.tsx +0 -60
  84. package/packages/react-css/src/RouterDocsLayout.tsx +0 -101
  85. package/packages/react-css/src/components/DocPage.tsx +0 -21
  86. package/packages/react-css/src/components/DocSearch.tsx +0 -55
  87. package/packages/react-css/src/components/DocSidebar.tsx +0 -56
  88. package/packages/react-css/src/components/DocsLayout.tsx +0 -28
  89. package/packages/react-css/src/components/common.tsx +0 -93
  90. package/packages/react-css/src/components/index.ts +0 -5
  91. package/packages/react-css/src/hooks/index.ts +0 -2
  92. package/packages/react-css/src/index.ts +0 -6
  93. package/packages/react-css/src/index.tsx +0 -3
  94. package/packages/react-css/src/pages/DocViewPage.tsx +0 -78
  95. package/packages/react-css/src/pages/DocsAdminPage.tsx +0 -101
  96. package/packages/react-css/src/pages/DocsIndexPage.tsx +0 -68
  97. package/packages/react-css/src/pages/index.ts +0 -3
  98. package/packages/react-css/src/useDocs.ts +0 -58
  99. package/packages/react-css/tsconfig.json +0 -19
  100. package/packages/react-css/tsup.config.ts +0 -10
  101. package/packages/shared/README.md +0 -1
  102. package/packages/shared/package.json +0 -31
  103. package/packages/shared/src/__tests__/docs.test.ts +0 -69
  104. package/packages/shared/src/config.ts +0 -80
  105. package/packages/shared/src/index.ts +0 -179
  106. package/packages/shared/src/providers/astro.ts +0 -94
  107. package/packages/shared/src/providers/fumadocs.ts +0 -116
  108. package/packages/shared/src/providers/internal.ts +0 -80
  109. package/packages/shared/src/types.ts +0 -73
  110. package/packages/shared/tsconfig.json +0 -18
  111. package/packages/shared/tsup.config.ts +0 -12
  112. package/packages/shared/vitest.config.ts +0 -4
  113. package/packages/solidjs/README.md +0 -1
  114. package/packages/solidjs/package.json +0 -33
  115. package/packages/solidjs/src/DocsLayout.tsx +0 -87
  116. package/packages/solidjs/src/DocsProvider.tsx +0 -95
  117. package/packages/solidjs/src/RouterDocsContent.tsx +0 -147
  118. package/packages/solidjs/src/RouterDocsLayout.tsx +0 -161
  119. package/packages/solidjs/src/components/Breadcrumbs.tsx +0 -27
  120. package/packages/solidjs/src/components/DocPage.tsx +0 -110
  121. package/packages/solidjs/src/components/DocSearch.tsx +0 -81
  122. package/packages/solidjs/src/components/DocSidebar.tsx +0 -92
  123. package/packages/solidjs/src/components/DocsLayout.tsx +0 -38
  124. package/packages/solidjs/src/components/EditButton.tsx +0 -15
  125. package/packages/solidjs/src/components/PageNavigation.tsx +0 -31
  126. package/packages/solidjs/src/components/TableOfContents.tsx +0 -41
  127. package/packages/solidjs/src/components/VersionSelector.tsx +0 -30
  128. package/packages/solidjs/src/components/index.ts +0 -9
  129. package/packages/solidjs/src/createDocs.ts +0 -62
  130. package/packages/solidjs/src/index.ts +0 -28
  131. package/packages/solidjs/src/pages/DocSearchPage.tsx +0 -72
  132. package/packages/solidjs/src/pages/DocViewPage.tsx +0 -80
  133. package/packages/solidjs/src/pages/DocsAdminPage.tsx +0 -123
  134. package/packages/solidjs/src/pages/DocsIndexPage.tsx +0 -85
  135. package/packages/solidjs/src/pages/index.ts +0 -4
  136. package/packages/solidjs/src/primitives/createDocSearch.ts +0 -42
  137. package/packages/solidjs/src/primitives/createDocs.ts +0 -35
  138. package/packages/solidjs/src/primitives/createDocsAdmin.ts +0 -63
  139. package/packages/solidjs/src/primitives/createTableOfContents.ts +0 -51
  140. package/packages/solidjs/src/primitives/index.ts +0 -4
  141. package/packages/solidjs/tsup.config.ts +0 -12
  142. package/packages/solidjs-css/README.md +0 -1
  143. package/packages/solidjs-css/package.json +0 -36
  144. package/packages/solidjs-css/src/DocsLayout.tsx +0 -106
  145. package/packages/solidjs-css/src/DocsProvider.tsx +0 -95
  146. package/packages/solidjs-css/src/RouterDocsContent.tsx +0 -54
  147. package/packages/solidjs-css/src/RouterDocsLayout.tsx +0 -104
  148. package/packages/solidjs-css/src/createDocs.ts +0 -62
  149. package/packages/solidjs-css/src/index.ts +0 -7
  150. package/packages/solidjs-css/src/index.tsx +0 -17
  151. package/packages/solidjs-css/src/pages/DocViewPage.tsx +0 -111
  152. package/packages/solidjs-css/src/pages/DocsAdminPage.tsx +0 -332
  153. package/packages/solidjs-css/src/pages/DocsIndexPage.tsx +0 -116
  154. package/packages/solidjs-css/src/pages/index.ts +0 -3
  155. package/packages/solidjs-css/src/primitives/index.ts +0 -1
  156. package/packages/solidjs-css/tsconfig.json +0 -20
  157. package/packages/solidjs-css/tsup.config.ts +0 -10
  158. package/pnpm-workspace.yaml +0 -2
@@ -1,161 +0,0 @@
1
- // src/components/docs/DocsLayout.tsx
2
-
3
- import React, { useState } from 'react'
4
- import { Link, useLocation } from '@tanstack/react-router'
5
- import { Book, Menu, X, Search, ChevronRight } from 'lucide-react'
6
-
7
- export interface DocItem {
8
- slug: string
9
- title: string
10
- description: string
11
- category: string
12
- order: number
13
- }
14
-
15
- interface DocsLayoutProps {
16
- children: React.ReactNode
17
- docs: DocItem[]
18
- currentSlug?: string
19
- }
20
-
21
- export const DocsLayout: React.FC<DocsLayoutProps> = ({
22
- children,
23
- docs,
24
- currentSlug,
25
- }) => {
26
- const [isSidebarOpen, setIsSidebarOpen] = useState(false)
27
- const location = useLocation()
28
-
29
- // Group docs by category
30
- const groupedDocs = docs.reduce(
31
- (acc, doc) => {
32
- if (!acc[doc.category]) {
33
- acc[doc.category] = []
34
- }
35
- acc[doc.category].push(doc)
36
- return acc
37
- },
38
- {} as Record<string, DocItem[]>,
39
- )
40
-
41
- // Sort categories and docs within each category
42
- const sortedCategories = Object.entries(groupedDocs).sort(([a], [b]) => {
43
- const categoryOrder = [
44
- 'Introduction',
45
- 'Getting Started',
46
- 'Guides',
47
- 'API',
48
- 'Advanced',
49
- ]
50
- return categoryOrder.indexOf(a) - categoryOrder.indexOf(b)
51
- })
52
-
53
- return (
54
- <div className="min-h-screen bg-bg">
55
- {/* Mobile Header */}
56
- <div className="lg:hidden sticky top-0 z-40 flex items-center justify-between px-4 py-3 bg-card border-b border-border">
57
- <Link to="/" className="flex items-center gap-2 text-primary">
58
- <Book className="w-5 h-5" />
59
- <span className="font-bold">Documentation</span>
60
- </Link>
61
- <button
62
- onClick={() => setIsSidebarOpen(!isSidebarOpen)}
63
- className="p-2 rounded-lg hover:bg-bg-muted transition-colors"
64
- >
65
- {isSidebarOpen ? (
66
- <X className="w-5 h-5" />
67
- ) : (
68
- <Menu className="w-5 h-5" />
69
- )}
70
- </button>
71
- </div>
72
-
73
- <div className="flex">
74
- {/* Sidebar */}
75
- <aside
76
- className={`
77
- fixed lg:sticky top-16 left-0 z-30 w-72 h-[calc(100vh-4rem)] overflow-y-auto
78
- bg-card border-r border-border transition-transform duration-300
79
- lg:translate-x-0
80
- ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}
81
- `}
82
- >
83
- <div className="p-6">
84
- {/* Logo */}
85
- <Link
86
- to="/"
87
- className="hidden lg:flex items-center gap-2 text-primary mb-8"
88
- >
89
- <Book className="w-6 h-6" />
90
- <span className="font-bold text-lg">Documentation</span>
91
- </Link>
92
-
93
- {/* Search */}
94
- <div className="relative mb-6">
95
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-text-muted" />
96
- <input
97
- type="text"
98
- placeholder="Search docs..."
99
- className="w-full pl-10 pr-4 py-2.5 bg-bg-muted border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all"
100
- />
101
- </div>
102
-
103
- {/* Navigation */}
104
- <nav className="space-y-6">
105
- {sortedCategories.map(([category, categoryDocs]) => (
106
- <div key={category}>
107
- <h3 className="text-xs font-bold text-text-muted uppercase tracking-wider mb-3">
108
- {category}
109
- </h3>
110
- <ul className="space-y-1">
111
- {categoryDocs
112
- .sort((a, b) => a.order - b.order)
113
- .map((doc) => {
114
- const isActive = currentSlug === doc.slug
115
- return (
116
- <li key={doc.slug}>
117
- <Link
118
- to="/docs/$slug"
119
- params={{ slug: doc.slug }}
120
- activeOptions={{ exact: true }}
121
- onClick={() => setIsSidebarOpen(false)}
122
- className={`
123
- flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all
124
- ${
125
- isActive
126
- ? 'bg-primary/10 text-primary'
127
- : 'text-text-muted hover:bg-bg-muted hover:text-text-main'
128
- }
129
- `}
130
- >
131
- <ChevronRight
132
- className={`w-4 h-4 transition-transform ${isActive ? 'rotate-90' : ''}`}
133
- />
134
- {doc.title}
135
- </Link>
136
- </li>
137
- )
138
- })}
139
- </ul>
140
- </div>
141
- ))}
142
- </nav>
143
- </div>
144
- </aside>
145
-
146
- {/* Overlay for mobile */}
147
- {isSidebarOpen && (
148
- <div
149
- className="fixed inset-0 bg-black/50 z-20 lg:hidden"
150
- onClick={() => setIsSidebarOpen(false)}
151
- />
152
- )}
153
-
154
- {/* Main Content */}
155
- <main className="flex-1 min-w-0">
156
- <div className="max-w-4xl mx-auto px-6 py-12">{children}</div>
157
- </main>
158
- </div>
159
- </div>
160
- )
161
- }
@@ -1,34 +0,0 @@
1
- import React from 'react'
2
- import type { BreadcrumbItem } from '@geenius-docs/shared'
3
-
4
- interface BreadcrumbsProps {
5
- items: BreadcrumbItem[]
6
- }
7
-
8
- export function Breadcrumbs({ items }: BreadcrumbsProps) {
9
- if (items.length === 0) return null
10
-
11
- return (
12
- <nav className="flex items-center gap-1.5 text-sm" aria-label="Breadcrumb">
13
- {items.map((item, idx) => (
14
- <React.Fragment key={idx}>
15
- {idx > 0 && (
16
- <svg className="h-3.5 w-3.5 shrink-0 text-white/20" viewBox="0 0 16 16" fill="none">
17
- <path d="M6 4l4 4-4 4" stroke="currentColor" strokeWidth="1.5" />
18
- </svg>
19
- )}
20
- {idx === items.length - 1 ? (
21
- <span className="truncate text-white/60">{item.title}</span>
22
- ) : (
23
- <a
24
- href={item.href}
25
- className="truncate text-white/40 transition-colors hover:text-white/70"
26
- >
27
- {item.title}
28
- </a>
29
- )}
30
- </React.Fragment>
31
- ))}
32
- </nav>
33
- )
34
- }
@@ -1,191 +0,0 @@
1
- import React from 'react'
2
- import type { DocPage as DocPageType } from '@geenius-docs/shared'
3
- import { slugify } from '@geenius-docs/shared'
4
-
5
- interface DocPageProps {
6
- page: DocPageType
7
- }
8
-
9
- function renderCallout(type: string, content: string) {
10
- const styles: Record<string, { bg: string; border: string; icon: string; label: string }> = {
11
- NOTE: { bg: 'bg-blue-500/10', border: 'border-blue-500/30', icon: 'ℹ️', label: 'Note' },
12
- WARNING: { bg: 'bg-amber-500/10', border: 'border-amber-500/30', icon: '⚠️', label: 'Warning' },
13
- TIP: { bg: 'bg-emerald-500/10', border: 'border-emerald-500/30', icon: '💡', label: 'Tip' },
14
- IMPORTANT: { bg: 'bg-purple-500/10', border: 'border-purple-500/30', icon: '❗', label: 'Important' },
15
- CAUTION: { bg: 'bg-red-500/10', border: 'border-red-500/30', icon: '🔴', label: 'Caution' },
16
- }
17
- const s = styles[type] ?? styles.NOTE
18
-
19
- return (
20
- <div className={`${s.bg} ${s.border} my-4 rounded-lg border-l-4 p-4`}>
21
- <p className="mb-1 text-sm font-semibold">
22
- {s.icon} {s.label}
23
- </p>
24
- <p className="text-sm leading-relaxed text-white/80">{content}</p>
25
- </div>
26
- )
27
- }
28
-
29
- function renderMdxContent(content: string) {
30
- const lines = content.split('\n')
31
- const elements: React.ReactNode[] = []
32
- let i = 0
33
- let codeBlock: string[] | null = null
34
- let codeLang = ''
35
-
36
- while (i < lines.length) {
37
- const line = lines[i]
38
-
39
- // Fenced code blocks
40
- if (line.startsWith('```')) {
41
- if (codeBlock === null) {
42
- codeBlock = []
43
- codeLang = line.slice(3).trim()
44
- } else {
45
- elements.push(
46
- <div key={i} className="group relative my-4">
47
- <div className="flex items-center justify-between rounded-t-lg bg-white/5 px-4 py-2 text-xs text-white/50">
48
- <span>{codeLang || 'code'}</span>
49
- </div>
50
- <pre className="overflow-x-auto rounded-b-lg bg-black/30 p-4 text-sm leading-relaxed">
51
- <code>{codeBlock.join('\n')}</code>
52
- </pre>
53
- </div>
54
- )
55
- codeBlock = null
56
- codeLang = ''
57
- }
58
- i++
59
- continue
60
- }
61
-
62
- if (codeBlock !== null) {
63
- codeBlock.push(line)
64
- i++
65
- continue
66
- }
67
-
68
- // Callouts [!NOTE], [!WARNING], etc.
69
- const calloutMatch = line.match(/^>\s*\[!(NOTE|WARNING|TIP|IMPORTANT|CAUTION)\]/)
70
- if (calloutMatch) {
71
- const type = calloutMatch[1]
72
- const contentLines: string[] = []
73
- i++
74
- while (i < lines.length && lines[i].startsWith('>')) {
75
- contentLines.push(lines[i].replace(/^>\s?/, ''))
76
- i++
77
- }
78
- elements.push(
79
- <React.Fragment key={i}>{renderCallout(type, contentLines.join(' '))}</React.Fragment>
80
- )
81
- continue
82
- }
83
-
84
- // Headings
85
- const headingMatch = line.match(/^(#{1,4})\s+(.+)$/)
86
- if (headingMatch) {
87
- const level = headingMatch[1].length
88
- const text = headingMatch[2]
89
- const id = slugify(text)
90
- const Tag = `h${level}` as keyof JSX.IntrinsicElements
91
-
92
- const headingClasses: Record<number, string> = {
93
- 1: 'text-3xl font-bold mt-8 mb-4',
94
- 2: 'text-2xl font-bold mt-8 mb-3 pb-2 border-b border-white/10',
95
- 3: 'text-xl font-semibold mt-6 mb-2',
96
- 4: 'text-lg font-medium mt-4 mb-2',
97
- }
98
-
99
- elements.push(
100
- <Tag key={i} id={id} className={`${headingClasses[level]} scroll-mt-20 group`}>
101
- <a href={`#${id}`} className="hover:text-indigo-400 transition-colors">
102
- {text}
103
- </a>
104
- </Tag>
105
- )
106
- i++
107
- continue
108
- }
109
-
110
- // Blockquotes
111
- if (line.startsWith('>')) {
112
- const quoteLines: string[] = []
113
- while (i < lines.length && lines[i].startsWith('>')) {
114
- quoteLines.push(lines[i].replace(/^>\s?/, ''))
115
- i++
116
- }
117
- elements.push(
118
- <blockquote key={i} className="my-4 border-l-4 border-indigo-500/40 bg-white/5 py-3 pl-4 pr-4 text-white/70 italic rounded-r-lg">
119
- {quoteLines.join(' ')}
120
- </blockquote>
121
- )
122
- continue
123
- }
124
-
125
- // Tables
126
- if (line.includes('|') && i + 1 < lines.length && lines[i + 1]?.match(/^\|[\s-:|]+\|$/)) {
127
- const headers = line.split('|').filter(Boolean).map((h) => h.trim())
128
- i += 2 // skip header and separator
129
- const rows: string[][] = []
130
- while (i < lines.length && lines[i].includes('|')) {
131
- rows.push(lines[i].split('|').filter(Boolean).map((c) => c.trim()))
132
- i++
133
- }
134
- elements.push(
135
- <div key={i} className="my-4 overflow-x-auto rounded-lg border border-white/10">
136
- <table className="w-full text-sm">
137
- <thead>
138
- <tr className="border-b border-white/10 bg-white/5">
139
- {headers.map((h, idx) => (
140
- <th key={idx} className="px-4 py-2.5 text-left font-semibold">{h}</th>
141
- ))}
142
- </tr>
143
- </thead>
144
- <tbody>
145
- {rows.map((row, rIdx) => (
146
- <tr key={rIdx} className="border-b border-white/5 last:border-none">
147
- {row.map((c, cIdx) => (
148
- <td key={cIdx} className="px-4 py-2 text-white/70">{c}</td>
149
- ))}
150
- </tr>
151
- ))}
152
- </tbody>
153
- </table>
154
- </div>
155
- )
156
- continue
157
- }
158
-
159
- // Empty line
160
- if (!line.trim()) {
161
- i++
162
- continue
163
- }
164
-
165
- // Paragraph with inline formatting
166
- const formatted = line
167
- .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
168
- .replace(/\*(.+?)\*/g, '<em>$1</em>')
169
- .replace(/`(.+?)`/g, '<code class="rounded bg-white/10 px-1.5 py-0.5 text-sm text-indigo-300">$1</code>')
170
- .replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" class="text-indigo-400 hover:text-indigo-300 underline underline-offset-2 transition-colors">$1</a>')
171
-
172
- elements.push(
173
- <p
174
- key={i}
175
- className="my-3 leading-relaxed text-white/80"
176
- dangerouslySetInnerHTML={{ __html: formatted }}
177
- />
178
- )
179
- i++
180
- }
181
-
182
- return elements
183
- }
184
-
185
- export function DocPage({ page }: DocPageProps) {
186
- return (
187
- <article className="prose-custom max-w-none">
188
- {renderMdxContent(page.content)}
189
- </article>
190
- )
191
- }
@@ -1,140 +0,0 @@
1
- import React, { useState, useEffect, useCallback, useRef } from 'react'
2
- import type { SearchResult } from '@geenius-docs/shared'
3
- import { highlightMatch } from '@geenius-docs/shared'
4
-
5
- interface DocSearchProps {
6
- results: SearchResult[]
7
- query: string
8
- onQuery: (q: string) => void
9
- onSelect: (result: SearchResult) => void
10
- isOpen: boolean
11
- onClose: () => void
12
- }
13
-
14
- export function DocSearch({ results, query, onQuery, onSelect, isOpen, onClose }: DocSearchProps) {
15
- const [activeIndex, setActiveIndex] = useState(0)
16
- const inputRef = useRef<HTMLInputElement>(null)
17
-
18
- useEffect(() => {
19
- if (isOpen) {
20
- inputRef.current?.focus()
21
- setActiveIndex(0)
22
- }
23
- }, [isOpen])
24
-
25
- useEffect(() => {
26
- setActiveIndex(0)
27
- }, [results])
28
-
29
- const handleKeyDown = useCallback(
30
- (e: React.KeyboardEvent) => {
31
- if (e.key === 'ArrowDown') {
32
- e.preventDefault()
33
- setActiveIndex((i) => Math.min(i + 1, results.length - 1))
34
- } else if (e.key === 'ArrowUp') {
35
- e.preventDefault()
36
- setActiveIndex((i) => Math.max(i - 1, 0))
37
- } else if (e.key === 'Enter' && results[activeIndex]) {
38
- e.preventDefault()
39
- onSelect(results[activeIndex])
40
- } else if (e.key === 'Escape') {
41
- e.preventDefault()
42
- onClose()
43
- }
44
- },
45
- [results, activeIndex, onSelect, onClose]
46
- )
47
-
48
- if (!isOpen) return null
49
-
50
- return (
51
- <div className="fixed inset-0 z-50 flex items-start justify-center pt-[15vh]" onClick={onClose}>
52
- {/* Backdrop */}
53
- <div className="fixed inset-0 bg-black/60 backdrop-blur-sm" />
54
-
55
- {/* Modal */}
56
- <div
57
- className="relative z-10 w-full max-w-xl overflow-hidden rounded-2xl border border-white/10 bg-[#0d0e14] shadow-2xl"
58
- onClick={(e) => e.stopPropagation()}
59
- >
60
- {/* Search input */}
61
- <div className="flex items-center gap-3 border-b border-white/10 px-5 py-4">
62
- <svg className="h-5 w-5 shrink-0 text-white/30" viewBox="0 0 20 20" fill="currentColor">
63
- <path fillRule="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" clipRule="evenodd" />
64
- </svg>
65
- <input
66
- ref={inputRef}
67
- type="text"
68
- value={query}
69
- onChange={(e) => onQuery(e.target.value)}
70
- onKeyDown={handleKeyDown}
71
- placeholder="Search documentation…"
72
- className="flex-1 bg-transparent text-sm text-white placeholder-white/30 outline-none"
73
- />
74
- <kbd className="rounded border border-white/10 bg-white/5 px-1.5 py-0.5 text-[11px] text-white/30">
75
- ESC
76
- </kbd>
77
- </div>
78
-
79
- {/* Results */}
80
- <div className="max-h-80 overflow-y-auto p-2">
81
- {results.length === 0 && query.trim() && (
82
- <div className="flex flex-col items-center py-10 text-center text-white/30">
83
- <svg className="mb-3 h-10 w-10 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor">
84
- <circle cx="11" cy="11" r="8" strokeWidth="1.5" />
85
- <path d="M21 21l-4.35-4.35" strokeWidth="1.5" />
86
- </svg>
87
- <p className="text-sm">No results for &ldquo;{query}&rdquo;</p>
88
- <p className="mt-1 text-xs opacity-60">Try different keywords</p>
89
- </div>
90
- )}
91
-
92
- {results.length === 0 && !query.trim() && (
93
- <div className="py-8 text-center text-sm text-white/30">
94
- Start typing to search…
95
- </div>
96
- )}
97
-
98
- {results.map((result, idx) => (
99
- <button
100
- key={result.pageId}
101
- type="button"
102
- onClick={() => onSelect(result)}
103
- className={`flex w-full flex-col gap-1 rounded-xl px-4 py-3 text-left transition-colors ${
104
- idx === activeIndex
105
- ? 'bg-indigo-500/15 text-white'
106
- : 'text-white/70 hover:bg-white/5'
107
- }`}
108
- >
109
- <div className="flex items-center gap-2">
110
- <span className="rounded bg-indigo-500/20 px-1.5 py-0.5 text-[10px] font-medium text-indigo-300">
111
- {result.sectionTitle}
112
- </span>
113
- <span className="text-sm font-medium">{result.pageTitle}</span>
114
- </div>
115
- <p className="truncate text-xs text-white/40">
116
- {highlightMatch(result.highlight, query)}
117
- </p>
118
- {result.tags.length > 0 && (
119
- <div className="flex gap-1">
120
- {result.tags.slice(0, 3).map((tag) => (
121
- <span key={tag} className="rounded bg-white/5 px-1.5 py-0.5 text-[10px] text-white/30">
122
- {tag}
123
- </span>
124
- ))}
125
- </div>
126
- )}
127
- </button>
128
- ))}
129
- </div>
130
-
131
- {/* Footer hint */}
132
- <div className="flex items-center gap-4 border-t border-white/5 px-5 py-2.5 text-[11px] text-white/20">
133
- <span>↑↓ navigate</span>
134
- <span>↵ select</span>
135
- <span>esc close</span>
136
- </div>
137
- </div>
138
- </div>
139
- )
140
- }
@@ -1,86 +0,0 @@
1
- import React, { useState, useCallback } from 'react'
2
- import type { DocSection, DocPage } from '@geenius-docs/shared'
3
-
4
- interface DocSidebarProps {
5
- sections: (DocSection & { pages?: DocPage[]; pageCount?: number })[]
6
- currentPageId?: string
7
- onNavigate: (page: DocPage, section: DocSection) => void
8
- }
9
-
10
- export function DocSidebar({ sections, currentPageId, onNavigate }: DocSidebarProps) {
11
- const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())
12
-
13
- const toggle = useCallback((id: string) => {
14
- setExpandedIds((prev) => {
15
- const next = new Set(prev)
16
- if (next.has(id)) next.delete(id)
17
- else next.add(id)
18
- return next
19
- })
20
- }, [])
21
-
22
- const topLevel = sections.filter((s) => !s.parentId)
23
- const childrenOf = (parentId: string) =>
24
- sections.filter((s) => s.parentId === parentId)
25
-
26
- const renderSection = (section: DocSection & { pages?: DocPage[]; pageCount?: number }, depth: number) => {
27
- const children = childrenOf(section.id)
28
- const isExpanded = expandedIds.has(section.id)
29
- const pages = section.pages ?? []
30
- const hasContent = children.length > 0 || pages.length > 0
31
-
32
- return (
33
- <div key={section.id} className="mb-1" style={{ paddingLeft: depth * 12 }}>
34
- <button
35
- type="button"
36
- onClick={() => toggle(section.id)}
37
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-medium transition-colors hover:bg-white/5"
38
- >
39
- {section.icon && <span className="text-base">{section.icon}</span>}
40
- <span className="flex-1 truncate">{section.title}</span>
41
- {section.pageCount != null && (
42
- <span className="text-xs tabular-nums opacity-50">{section.pageCount}</span>
43
- )}
44
- {hasContent && (
45
- <svg
46
- className={`h-3.5 w-3.5 shrink-0 transition-transform ${isExpanded ? 'rotate-90' : ''}`}
47
- viewBox="0 0 16 16"
48
- fill="currentColor"
49
- >
50
- <path d="M6 4l4 4-4 4" stroke="currentColor" strokeWidth="2" fill="none" />
51
- </svg>
52
- )}
53
- </button>
54
-
55
- {isExpanded && (
56
- <div className="ml-2 border-l border-white/10 pl-2">
57
- {pages.map((page) => (
58
- <button
59
- key={page.id}
60
- type="button"
61
- onClick={() => onNavigate(page, section)}
62
- className={`flex w-full items-center gap-2 rounded-md px-3 py-1.5 text-left text-sm transition-colors ${
63
- currentPageId === page.id
64
- ? 'bg-indigo-500/20 text-indigo-300 font-medium'
65
- : 'text-white/60 hover:text-white/90 hover:bg-white/5'
66
- }`}
67
- >
68
- <span className="truncate">{page.title}</span>
69
- </button>
70
- ))}
71
- {children.map((child) => renderSection(child, depth + 1))}
72
- </div>
73
- )}
74
- </div>
75
- )
76
- }
77
-
78
- return (
79
- <nav className="flex flex-col gap-0.5 py-4">
80
- <div className="px-4 pb-3 text-xs font-semibold uppercase tracking-widest text-white/40">
81
- Documentation
82
- </div>
83
- {topLevel.map((s) => renderSection(s, 0))}
84
- </nav>
85
- )
86
- }
@@ -1,62 +0,0 @@
1
- import React from 'react'
2
- import type { DocPage, DocSection, TocItem, BreadcrumbItem } from '@geenius-docs/shared'
3
- import { DocSidebar } from './DocSidebar'
4
- import { TableOfContents } from './TableOfContents'
5
- import { Breadcrumbs } from './Breadcrumbs'
6
-
7
- interface DocsLayoutProps {
8
- sections: (DocSection & { pages?: DocPage[] })[]
9
- currentPage?: DocPage
10
- toc?: TocItem[]
11
- activeHeadingId?: string
12
- breadcrumbs?: BreadcrumbItem[]
13
- currentPageId?: string
14
- onNavigate: (page: DocPage, section: DocSection) => void
15
- children: React.ReactNode
16
- }
17
-
18
- export function DocsLayout({
19
- sections,
20
- currentPage,
21
- toc,
22
- activeHeadingId,
23
- breadcrumbs,
24
- currentPageId,
25
- onNavigate,
26
- children,
27
- }: DocsLayoutProps) {
28
- return (
29
- <div className="flex min-h-screen bg-[#090a0f] text-white">
30
- {/* Sidebar */}
31
- <aside className="sticky top-0 hidden h-screen w-[260px] shrink-0 overflow-y-auto border-r border-white/5 bg-[#0b0c12] lg:block">
32
- <DocSidebar
33
- sections={sections}
34
- currentPageId={currentPageId}
35
- onNavigate={onNavigate}
36
- />
37
- </aside>
38
-
39
- {/* Main content */}
40
- <main className="flex-1 overflow-hidden">
41
- <div className="mx-auto flex max-w-6xl gap-8 px-6 py-8 lg:px-10">
42
- {/* Content area */}
43
- <div className="min-w-0 flex-1">
44
- {breadcrumbs && breadcrumbs.length > 0 && (
45
- <div className="mb-6">
46
- <Breadcrumbs items={breadcrumbs} />
47
- </div>
48
- )}
49
- {children}
50
- </div>
51
-
52
- {/* Table of contents */}
53
- {toc && toc.length > 0 && (
54
- <aside className="hidden w-[220px] shrink-0 xl:block">
55
- <TableOfContents toc={toc} activeId={activeHeadingId} />
56
- </aside>
57
- )}
58
- </div>
59
- </main>
60
- </div>
61
- )
62
- }