@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.
- package/.changeset/config.json +11 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +23 -0
- package/.github/workflows/release.yml +29 -0
- package/.nvmrc +1 -0
- package/.project/ACCOUNT.yaml +4 -0
- package/.project/IDEAS.yaml +7 -0
- package/.project/PROJECT.yaml +11 -0
- package/.project/ROADMAP.yaml +15 -0
- package/CHANGELOG.md +11 -0
- package/CODE_OF_CONDUCT.md +16 -0
- package/CONTRIBUTING.md +26 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/SECURITY.md +15 -0
- package/SUPPORT.md +8 -0
- package/package.json +58 -0
- package/packages/convex/README.md +1 -0
- package/packages/convex/package.json +12 -0
- package/packages/convex/src/convex.config.ts +3 -0
- package/packages/convex/src/index.ts +3 -0
- package/packages/convex/src/mutations.ts +270 -0
- package/packages/convex/src/queries.ts +175 -0
- package/packages/convex/src/schema.ts +55 -0
- package/packages/react/README.md +1 -0
- package/packages/react/package.json +36 -0
- package/packages/react/src/DocsLayout.tsx +116 -0
- package/packages/react/src/DocsProvider.tsx +93 -0
- package/packages/react/src/RouterDocsContent.tsx +148 -0
- package/packages/react/src/RouterDocsLayout.tsx +161 -0
- package/packages/react/src/components/Breadcrumbs.tsx +34 -0
- package/packages/react/src/components/DocPage.tsx +191 -0
- package/packages/react/src/components/DocSearch.tsx +140 -0
- package/packages/react/src/components/DocSidebar.tsx +86 -0
- package/packages/react/src/components/DocsLayout.tsx +62 -0
- package/packages/react/src/components/EditButton.tsx +26 -0
- package/packages/react/src/components/PageNavigation.tsx +45 -0
- package/packages/react/src/components/TableOfContents.tsx +46 -0
- package/packages/react/src/components/VersionSelector.tsx +60 -0
- package/packages/react/src/components/index.ts +9 -0
- package/packages/react/src/hooks/index.ts +8 -0
- package/packages/react/src/hooks/useDocSearch.ts +55 -0
- package/packages/react/src/hooks/useDocs.ts +57 -0
- package/packages/react/src/hooks/useDocsAdmin.ts +151 -0
- package/packages/react/src/hooks/useTableOfContents.ts +66 -0
- package/packages/react/src/index.ts +38 -0
- package/packages/react/src/pages/DocSearchPage.tsx +129 -0
- package/packages/react/src/pages/DocViewPage.tsx +158 -0
- package/packages/react/src/pages/DocsAdminPage.tsx +330 -0
- package/packages/react/src/pages/DocsIndexPage.tsx +172 -0
- package/packages/react/src/pages/index.ts +4 -0
- package/packages/react/src/useDocs.ts +58 -0
- package/packages/react/tsup.config.ts +12 -0
- package/packages/react-css/README.md +1 -0
- package/packages/react-css/package.json +37 -0
- package/packages/react-css/src/DocsLayout.tsx +117 -0
- package/packages/react-css/src/DocsProvider.tsx +93 -0
- package/packages/react-css/src/RouterDocsContent.tsx +60 -0
- package/packages/react-css/src/RouterDocsLayout.tsx +101 -0
- package/packages/react-css/src/components/DocPage.tsx +21 -0
- package/packages/react-css/src/components/DocSearch.tsx +55 -0
- package/packages/react-css/src/components/DocSidebar.tsx +56 -0
- package/packages/react-css/src/components/DocsLayout.tsx +28 -0
- package/packages/react-css/src/components/common.tsx +93 -0
- package/packages/react-css/src/components/index.ts +5 -0
- package/packages/react-css/src/hooks/index.ts +2 -0
- package/packages/react-css/src/index.ts +6 -0
- package/packages/react-css/src/index.tsx +3 -0
- package/packages/react-css/src/pages/DocViewPage.tsx +78 -0
- package/packages/react-css/src/pages/DocsAdminPage.tsx +101 -0
- package/packages/react-css/src/pages/DocsIndexPage.tsx +68 -0
- package/packages/react-css/src/pages/index.ts +3 -0
- package/packages/react-css/src/styles.css +1271 -0
- package/packages/react-css/src/useDocs.ts +58 -0
- package/packages/react-css/tsconfig.json +19 -0
- package/packages/react-css/tsup.config.ts +10 -0
- package/packages/shared/README.md +1 -0
- package/packages/shared/package.json +31 -0
- package/packages/shared/src/__tests__/docs.test.ts +69 -0
- package/packages/shared/src/config.ts +80 -0
- package/packages/shared/src/index.ts +179 -0
- package/packages/shared/src/providers/astro.ts +94 -0
- package/packages/shared/src/providers/fumadocs.ts +116 -0
- package/packages/shared/src/providers/internal.ts +80 -0
- package/packages/shared/src/types.ts +73 -0
- package/packages/shared/tsconfig.json +18 -0
- package/packages/shared/tsup.config.ts +12 -0
- package/packages/shared/vitest.config.ts +4 -0
- package/packages/solidjs/README.md +1 -0
- package/packages/solidjs/package.json +33 -0
- package/packages/solidjs/src/DocsLayout.tsx +87 -0
- package/packages/solidjs/src/DocsProvider.tsx +95 -0
- package/packages/solidjs/src/RouterDocsContent.tsx +147 -0
- package/packages/solidjs/src/RouterDocsLayout.tsx +161 -0
- package/packages/solidjs/src/components/Breadcrumbs.tsx +27 -0
- package/packages/solidjs/src/components/DocPage.tsx +110 -0
- package/packages/solidjs/src/components/DocSearch.tsx +81 -0
- package/packages/solidjs/src/components/DocSidebar.tsx +92 -0
- package/packages/solidjs/src/components/DocsLayout.tsx +38 -0
- package/packages/solidjs/src/components/EditButton.tsx +15 -0
- package/packages/solidjs/src/components/PageNavigation.tsx +31 -0
- package/packages/solidjs/src/components/TableOfContents.tsx +41 -0
- package/packages/solidjs/src/components/VersionSelector.tsx +30 -0
- package/packages/solidjs/src/components/index.ts +9 -0
- package/packages/solidjs/src/createDocs.ts +62 -0
- package/packages/solidjs/src/index.ts +28 -0
- package/packages/solidjs/src/pages/DocSearchPage.tsx +72 -0
- package/packages/solidjs/src/pages/DocViewPage.tsx +80 -0
- package/packages/solidjs/src/pages/DocsAdminPage.tsx +123 -0
- package/packages/solidjs/src/pages/DocsIndexPage.tsx +85 -0
- package/packages/solidjs/src/pages/index.ts +4 -0
- package/packages/solidjs/src/primitives/createDocSearch.ts +42 -0
- package/packages/solidjs/src/primitives/createDocs.ts +35 -0
- package/packages/solidjs/src/primitives/createDocsAdmin.ts +63 -0
- package/packages/solidjs/src/primitives/createTableOfContents.ts +51 -0
- package/packages/solidjs/src/primitives/index.ts +4 -0
- package/packages/solidjs/tsup.config.ts +12 -0
- package/packages/solidjs-css/README.md +1 -0
- package/packages/solidjs-css/package.json +36 -0
- package/packages/solidjs-css/src/DocsLayout.tsx +106 -0
- package/packages/solidjs-css/src/DocsProvider.tsx +95 -0
- package/packages/solidjs-css/src/RouterDocsContent.tsx +54 -0
- package/packages/solidjs-css/src/RouterDocsLayout.tsx +104 -0
- package/packages/solidjs-css/src/createDocs.ts +62 -0
- package/packages/solidjs-css/src/index.ts +7 -0
- package/packages/solidjs-css/src/index.tsx +17 -0
- package/packages/solidjs-css/src/pages/DocViewPage.tsx +111 -0
- package/packages/solidjs-css/src/pages/DocsAdminPage.tsx +332 -0
- package/packages/solidjs-css/src/pages/DocsIndexPage.tsx +116 -0
- package/packages/solidjs-css/src/pages/index.ts +3 -0
- package/packages/solidjs-css/src/primitives/index.ts +1 -0
- package/packages/solidjs-css/src/styles.css +1271 -0
- package/packages/solidjs-css/tsconfig.json +20 -0
- package/packages/solidjs-css/tsup.config.ts +10 -0
- package/pnpm-workspace.yaml +2 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { DocsProvider, DocsPage, DocsSidebar, DocsSection, DocsSearchResult, TocEntry } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Internal docs provider — renders docs from an in-memory page array.
|
|
5
|
+
* Use when loading docs from CMS, API, or static JSON.
|
|
6
|
+
*/
|
|
7
|
+
export class InternalDocsProvider implements DocsProvider {
|
|
8
|
+
readonly name = 'internal' as const
|
|
9
|
+
private pages: DocsPage[] = []
|
|
10
|
+
|
|
11
|
+
constructor(pages?: DocsPage[]) { if (pages) this.pages = pages }
|
|
12
|
+
|
|
13
|
+
setPages(pages: DocsPage[]): void { this.pages = this.linkPages(pages) }
|
|
14
|
+
|
|
15
|
+
private linkPages(pages: DocsPage[]): DocsPage[] {
|
|
16
|
+
const sorted = [...pages].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
17
|
+
return sorted.map((page, i) => ({
|
|
18
|
+
...page,
|
|
19
|
+
prev: i > 0 ? { slug: sorted[i - 1].slug, title: sorted[i - 1].title } : undefined,
|
|
20
|
+
next: i < sorted.length - 1 ? { slug: sorted[i + 1].slug, title: sorted[i + 1].title } : undefined,
|
|
21
|
+
toc: page.toc ?? this.extractToc(page.content),
|
|
22
|
+
}))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private extractToc(content: string): TocEntry[] {
|
|
26
|
+
const regex = /^(#{2,4})\s+(.+)$/gm
|
|
27
|
+
const entries: TocEntry[] = []
|
|
28
|
+
let match
|
|
29
|
+
while ((match = regex.exec(content)) !== null) {
|
|
30
|
+
const title = match[2].trim()
|
|
31
|
+
entries.push({ id: title.toLowerCase().replace(/[^a-z0-9]+/g, '-'), title, depth: match[1].length })
|
|
32
|
+
}
|
|
33
|
+
return entries
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async getSidebar(): Promise<DocsSidebar> {
|
|
37
|
+
const sectionMap = new Map<string, DocsPage[]>()
|
|
38
|
+
for (const page of this.pages.filter(p => !p.draft)) {
|
|
39
|
+
const section = page.section || 'General'
|
|
40
|
+
if (!sectionMap.has(section)) sectionMap.set(section, [])
|
|
41
|
+
sectionMap.get(section)!.push(page)
|
|
42
|
+
}
|
|
43
|
+
const sections: DocsSection[] = [...sectionMap.entries()].map(([title, pages]) => ({
|
|
44
|
+
title, slug: title.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
|
|
45
|
+
pages: pages.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
|
|
46
|
+
}))
|
|
47
|
+
return { sections }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getPage(slug: string): Promise<DocsPage | null> {
|
|
51
|
+
return this.pages.find(p => p.slug === slug) ?? null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getAllPages(): Promise<DocsPage[]> {
|
|
55
|
+
return this.pages.filter(p => !p.draft)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async search(query: string): Promise<DocsSearchResult[]> {
|
|
59
|
+
const q = query.toLowerCase()
|
|
60
|
+
return this.pages.filter(p => !p.draft).map(page => {
|
|
61
|
+
const matches: DocsSearchResult['matches'] = []
|
|
62
|
+
if (page.title.toLowerCase().includes(q)) matches.push({ field: 'title', snippet: page.title })
|
|
63
|
+
if (page.description?.toLowerCase().includes(q)) matches.push({ field: 'description', snippet: page.description })
|
|
64
|
+
if (page.content.toLowerCase().includes(q)) {
|
|
65
|
+
const idx = page.content.toLowerCase().indexOf(q)
|
|
66
|
+
matches.push({ field: 'content', snippet: page.content.slice(Math.max(0, idx - 40), idx + q.length + 40) })
|
|
67
|
+
}
|
|
68
|
+
return matches.length > 0 ? { page, matches, score: matches.length } : null
|
|
69
|
+
}).filter(Boolean) as DocsSearchResult[]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getNavigation(slug: string): Promise<{ prev: DocsPage | null; next: DocsPage | null }> {
|
|
73
|
+
const page = this.pages.find(p => p.slug === slug)
|
|
74
|
+
if (!page) return { prev: null, next: null }
|
|
75
|
+
return {
|
|
76
|
+
prev: page.prev ? (this.pages.find(p => p.slug === page.prev!.slug) ?? null) : null,
|
|
77
|
+
next: page.next ? (this.pages.find(p => p.slug === page.next!.slug) ?? null) : null,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ─── Docs Types ──────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export type DocAccess = 'public' | 'team' | 'admin'
|
|
4
|
+
export type DocStatus = 'draft' | 'published' | 'archived'
|
|
5
|
+
|
|
6
|
+
export interface DocPage {
|
|
7
|
+
id: string
|
|
8
|
+
title: string
|
|
9
|
+
slug: string
|
|
10
|
+
content: string // MDX
|
|
11
|
+
excerpt?: string
|
|
12
|
+
sectionId: string
|
|
13
|
+
order: number
|
|
14
|
+
author: { name: string; avatar?: string }
|
|
15
|
+
lastEditedBy?: { name: string; editedAt: string }
|
|
16
|
+
version?: string // e.g. "2.1.0"
|
|
17
|
+
access: DocAccess
|
|
18
|
+
tags: string[]
|
|
19
|
+
status: DocStatus
|
|
20
|
+
createdAt: string
|
|
21
|
+
updatedAt: string
|
|
22
|
+
wordCount: number
|
|
23
|
+
readingTime: number
|
|
24
|
+
viewCount: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DocSection {
|
|
28
|
+
id: string
|
|
29
|
+
title: string
|
|
30
|
+
slug: string
|
|
31
|
+
parentId?: string // max 3 levels
|
|
32
|
+
order: number
|
|
33
|
+
icon?: string
|
|
34
|
+
description?: string
|
|
35
|
+
access: DocAccess
|
|
36
|
+
pageCount?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SearchResult {
|
|
40
|
+
pageId: string
|
|
41
|
+
pageTitle: string
|
|
42
|
+
sectionTitle: string
|
|
43
|
+
sectionSlug: string
|
|
44
|
+
slug: string
|
|
45
|
+
highlight: string
|
|
46
|
+
score: number
|
|
47
|
+
tags: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface TocItem {
|
|
51
|
+
id: string
|
|
52
|
+
text: string
|
|
53
|
+
level: 2 | 3 | 4
|
|
54
|
+
children: TocItem[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface BreadcrumbItem {
|
|
58
|
+
title: string
|
|
59
|
+
href: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface DocsConfig {
|
|
63
|
+
siteName?: string
|
|
64
|
+
baseUrl?: string
|
|
65
|
+
defaultAccess?: DocAccess
|
|
66
|
+
versionsEnabled?: boolean
|
|
67
|
+
cmdKEnabled?: boolean
|
|
68
|
+
editPageUrl?: string // e.g. 'https://github.com/org/repo/edit/main/docs'
|
|
69
|
+
showReadingTime?: boolean
|
|
70
|
+
showLastEdited?: boolean
|
|
71
|
+
showViewCount?: boolean
|
|
72
|
+
printModeEnabled?: boolean
|
|
73
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"target": "ES2022",
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "bundler"
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
"src"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# ✦ @geenius-docs/solidjs\n\n> A premium module for the Geenius Boilerplate Ecosystem.\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius-docs/solidjs\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius-docs/solidjs';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geenius-docs/solidjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"solid-js": ">=1.8.0"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@geenius-docs/shared": "workspace:*",
|
|
15
|
+
"lucide-solid": "^0.577.0",
|
|
16
|
+
"remark-gfm": "^4.0.1",
|
|
17
|
+
"solid-markdown": "^2.1.1"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"type-check": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@tanstack/solid-router": "^1.168.1"
|
|
24
|
+
},
|
|
25
|
+
"author": "Antigravity HQ",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// @geenius-docs/solidjs — src/DocsLayout.tsx
|
|
2
|
+
|
|
3
|
+
import { For, Show, type ParentComponent } from 'solid-js'
|
|
4
|
+
import { useDocs } from './DocsProvider'
|
|
5
|
+
|
|
6
|
+
export interface DocsLayoutProps {
|
|
7
|
+
currentPageId?: string
|
|
8
|
+
onSelectPage?: (id: string) => void
|
|
9
|
+
searchQuery?: string
|
|
10
|
+
onSearch?: (query: string) => void
|
|
11
|
+
searchResults?: unknown[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* DocsLayout — SolidJS sidebar + content layout for documentation.
|
|
16
|
+
* Uses data-* attributes and ga-docs-* classes for CSS styling.
|
|
17
|
+
*/
|
|
18
|
+
export const DocsLayout: ParentComponent<DocsLayoutProps> = (props) => {
|
|
19
|
+
const docs = useDocs()
|
|
20
|
+
|
|
21
|
+
const q = () => props.searchQuery ?? docs.searchQuery()
|
|
22
|
+
const results = () => (props.searchResults ?? docs.searchResults()) as Array<{ id: string; title: string; description?: string }>
|
|
23
|
+
const onSelect = (id: string) => (props.onSelectPage ?? docs.selectPage)(id)
|
|
24
|
+
const onSearch = (query: string) => (props.onSearch ?? docs.setSearchQuery)(query)
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div class="ga-docs-layout">
|
|
28
|
+
{/* Sidebar */}
|
|
29
|
+
<aside class="ga-docs-sidebar">
|
|
30
|
+
<div class="ga-docs-search">
|
|
31
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>
|
|
32
|
+
<input
|
|
33
|
+
type="text"
|
|
34
|
+
value={q()}
|
|
35
|
+
onInput={(e) => onSearch(e.currentTarget.value)}
|
|
36
|
+
placeholder="Search docs..."
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<nav>
|
|
41
|
+
<Show
|
|
42
|
+
when={!q() || results().length === 0}
|
|
43
|
+
fallback={
|
|
44
|
+
<div data-docs-search-results>
|
|
45
|
+
<p class="ga-docs-nav-group-title">Search Results ({results().length})</p>
|
|
46
|
+
<For each={results()}>
|
|
47
|
+
{(page) => (
|
|
48
|
+
<button
|
|
49
|
+
class="ga-docs-nav-item"
|
|
50
|
+
onClick={() => { onSelect(page.id); onSearch('') }}
|
|
51
|
+
>
|
|
52
|
+
{page.title}
|
|
53
|
+
</button>
|
|
54
|
+
)}
|
|
55
|
+
</For>
|
|
56
|
+
</div>
|
|
57
|
+
}
|
|
58
|
+
>
|
|
59
|
+
<For each={docs.tree}>
|
|
60
|
+
{(group) => (
|
|
61
|
+
<div class="ga-docs-nav-group">
|
|
62
|
+
<p class="ga-docs-nav-group-title">{group.title}</p>
|
|
63
|
+
<For each={group.children}>
|
|
64
|
+
{(page) => (
|
|
65
|
+
<button
|
|
66
|
+
class="ga-docs-nav-item"
|
|
67
|
+
data-active={page.id === props.currentPageId || undefined}
|
|
68
|
+
onClick={() => onSelect(page.id)}
|
|
69
|
+
>
|
|
70
|
+
{page.title}
|
|
71
|
+
</button>
|
|
72
|
+
)}
|
|
73
|
+
</For>
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
76
|
+
</For>
|
|
77
|
+
</Show>
|
|
78
|
+
</nav>
|
|
79
|
+
</aside>
|
|
80
|
+
|
|
81
|
+
{/* Content */}
|
|
82
|
+
<main class="ga-docs-content">
|
|
83
|
+
{props.children}
|
|
84
|
+
</main>
|
|
85
|
+
</div>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// @geenius-docs/solidjs — src/DocsProvider.tsx
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, type ParentComponent } from 'solid-js'
|
|
4
|
+
import { createSignal, createMemo } from 'solid-js'
|
|
5
|
+
|
|
6
|
+
export interface DocsPage {
|
|
7
|
+
id: string
|
|
8
|
+
title: string
|
|
9
|
+
description?: string
|
|
10
|
+
content: unknown
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DocsGroup {
|
|
14
|
+
id: string
|
|
15
|
+
title: string
|
|
16
|
+
children: DocsPage[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type DocsTree = DocsGroup[]
|
|
20
|
+
|
|
21
|
+
export interface DocsContextValue {
|
|
22
|
+
tree: DocsTree
|
|
23
|
+
currentPage: () => DocsPage | null
|
|
24
|
+
selectPage: (id: string) => void
|
|
25
|
+
searchQuery: () => string
|
|
26
|
+
setSearchQuery: (query: string) => void
|
|
27
|
+
searchResults: () => DocsPage[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DocsContext = createContext<DocsContextValue>()
|
|
31
|
+
|
|
32
|
+
export interface DocsProviderProps {
|
|
33
|
+
tree: DocsTree
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* DocsProvider — SolidJS context managing docs state:
|
|
38
|
+
* current page, search, and tree navigation.
|
|
39
|
+
*/
|
|
40
|
+
export const DocsProvider: ParentComponent<DocsProviderProps> = (props) => {
|
|
41
|
+
const firstPageId = () => props.tree[0]?.children[0]?.id || null
|
|
42
|
+
const [currentPageId, setCurrentPageId] = createSignal<string | null>(firstPageId())
|
|
43
|
+
const [searchQuery, setSearchQuery] = createSignal('')
|
|
44
|
+
|
|
45
|
+
const currentPage = createMemo(() => {
|
|
46
|
+
const id = currentPageId()
|
|
47
|
+
if (!id) return null
|
|
48
|
+
for (const group of props.tree) {
|
|
49
|
+
const page = group.children.find(p => p.id === id)
|
|
50
|
+
if (page) return page
|
|
51
|
+
}
|
|
52
|
+
return null
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const selectPage = (id: string) => setCurrentPageId(id)
|
|
56
|
+
|
|
57
|
+
const searchResults = createMemo(() => {
|
|
58
|
+
const q = searchQuery().toLowerCase()
|
|
59
|
+
if (!q) return []
|
|
60
|
+
const results: DocsPage[] = []
|
|
61
|
+
for (const group of props.tree) {
|
|
62
|
+
for (const page of group.children) {
|
|
63
|
+
if (
|
|
64
|
+
page.title.toLowerCase().includes(q) ||
|
|
65
|
+
page.description?.toLowerCase().includes(q) ||
|
|
66
|
+
(typeof page.content === 'string' && page.content.toLowerCase().includes(q))
|
|
67
|
+
) {
|
|
68
|
+
results.push(page)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return results
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const value: DocsContextValue = {
|
|
76
|
+
tree: props.tree,
|
|
77
|
+
currentPage,
|
|
78
|
+
selectPage,
|
|
79
|
+
searchQuery,
|
|
80
|
+
setSearchQuery,
|
|
81
|
+
searchResults,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<DocsContext.Provider value={value}>
|
|
86
|
+
{props.children}
|
|
87
|
+
</DocsContext.Provider>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function useDocs(): DocsContextValue {
|
|
92
|
+
const ctx = useContext(DocsContext)
|
|
93
|
+
if (!ctx) throw new Error('useDocs must be used within a DocsProvider')
|
|
94
|
+
return ctx
|
|
95
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// src/components/docs/DocsContent.tsx
|
|
2
|
+
|
|
3
|
+
import { SolidMarkdown as ReactMarkdown } from 'solid-markdown'
|
|
4
|
+
import remarkGfm from 'remark-gfm'
|
|
5
|
+
import { Link } from '@tanstack/solid-router'
|
|
6
|
+
|
|
7
|
+
interface DocsContentProps {
|
|
8
|
+
content: string
|
|
9
|
+
title: string
|
|
10
|
+
description: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const DocsContent: Component<DocsContentProps> = ({
|
|
14
|
+
content,
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
}) => {
|
|
18
|
+
return (
|
|
19
|
+
<article class="prose prose-lg dark:prose-invert max-w-none">
|
|
20
|
+
{/* Header */}
|
|
21
|
+
<header class="mb-8 pb-8 border-b border-border not-prose">
|
|
22
|
+
<h1 class="text-4xl font-extrabold text-text-main mb-3">{title}</h1>
|
|
23
|
+
<p class="text-lg text-text-muted">{description}</p>
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
{/* Markdown Content */}
|
|
27
|
+
<ReactMarkdown
|
|
28
|
+
remarkPlugins={[remarkGfm]}
|
|
29
|
+
components={{
|
|
30
|
+
// Custom heading styles
|
|
31
|
+
h1: ({ children }) => (
|
|
32
|
+
<h1 class="text-3xl font-bold text-text-main mt-12 mb-6">
|
|
33
|
+
{children}
|
|
34
|
+
</h1>
|
|
35
|
+
),
|
|
36
|
+
h2: ({ children }) => (
|
|
37
|
+
<h2 class="text-2xl font-bold text-text-main mt-10 mb-4 pb-2 border-b border-border">
|
|
38
|
+
{children}
|
|
39
|
+
</h2>
|
|
40
|
+
),
|
|
41
|
+
h3: ({ children }) => (
|
|
42
|
+
<h3 class="text-xl font-bold text-text-main mt-8 mb-3">
|
|
43
|
+
{children}
|
|
44
|
+
</h3>
|
|
45
|
+
),
|
|
46
|
+
h4: ({ children }) => (
|
|
47
|
+
<h4 class="text-lg font-semibold text-text-main mt-6 mb-2">
|
|
48
|
+
{children}
|
|
49
|
+
</h4>
|
|
50
|
+
),
|
|
51
|
+
// Paragraph
|
|
52
|
+
p: ({ children }) => (
|
|
53
|
+
<p class="text-text-muted leading-relaxed mb-4">{children}</p>
|
|
54
|
+
),
|
|
55
|
+
// Links
|
|
56
|
+
a: ({ href, children }) => {
|
|
57
|
+
const isInternal = href?.startsWith('/')
|
|
58
|
+
if (isInternal) {
|
|
59
|
+
return (
|
|
60
|
+
<Link
|
|
61
|
+
to={href!}
|
|
62
|
+
class="text-primary hover:underline font-medium"
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</Link>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
return (
|
|
69
|
+
<a
|
|
70
|
+
href={href}
|
|
71
|
+
target="_blank"
|
|
72
|
+
rel="noopener noreferrer"
|
|
73
|
+
class="text-primary hover:underline font-medium"
|
|
74
|
+
>
|
|
75
|
+
{children}
|
|
76
|
+
</a>
|
|
77
|
+
)
|
|
78
|
+
},
|
|
79
|
+
// Code blocks
|
|
80
|
+
code: ({ className, children, ...props }) => {
|
|
81
|
+
const isInline = !className
|
|
82
|
+
if (isInline) {
|
|
83
|
+
return (
|
|
84
|
+
<code class="bg-bg-muted px-1.5 py-0.5 rounded text-sm font-mono text-primary">
|
|
85
|
+
{children}
|
|
86
|
+
</code>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
return (
|
|
90
|
+
<code class={`${className} block`} {...props}>
|
|
91
|
+
{children}
|
|
92
|
+
</code>
|
|
93
|
+
)
|
|
94
|
+
},
|
|
95
|
+
pre: ({ children }) => (
|
|
96
|
+
<pre class="bg-[#1e1e2e] text-gray-100 p-4 rounded-xl overflow-x-auto text-sm my-6 border border-border">
|
|
97
|
+
{children}
|
|
98
|
+
</pre>
|
|
99
|
+
),
|
|
100
|
+
// Lists
|
|
101
|
+
ul: ({ children }) => (
|
|
102
|
+
<ul class="list-disc list-inside space-y-2 text-text-muted mb-4">
|
|
103
|
+
{children}
|
|
104
|
+
</ul>
|
|
105
|
+
),
|
|
106
|
+
ol: ({ children }) => (
|
|
107
|
+
<ol class="list-decimal list-inside space-y-2 text-text-muted mb-4">
|
|
108
|
+
{children}
|
|
109
|
+
</ol>
|
|
110
|
+
),
|
|
111
|
+
li: ({ children }) => <li class="text-text-muted">{children}</li>,
|
|
112
|
+
// Tables
|
|
113
|
+
table: ({ children }) => (
|
|
114
|
+
<div class="overflow-x-auto my-6">
|
|
115
|
+
<table class="min-w-full divide-y divide-border border border-border rounded-lg overflow-hidden">
|
|
116
|
+
{children}
|
|
117
|
+
</table>
|
|
118
|
+
</div>
|
|
119
|
+
),
|
|
120
|
+
thead: ({ children }) => (
|
|
121
|
+
<thead class="bg-bg-muted">{children}</thead>
|
|
122
|
+
),
|
|
123
|
+
th: ({ children }) => (
|
|
124
|
+
<th class="px-4 py-3 text-left text-sm font-bold text-text-main">
|
|
125
|
+
{children}
|
|
126
|
+
</th>
|
|
127
|
+
),
|
|
128
|
+
td: ({ children }) => (
|
|
129
|
+
<td class="px-4 py-3 text-sm text-text-muted border-t border-border">
|
|
130
|
+
{children}
|
|
131
|
+
</td>
|
|
132
|
+
),
|
|
133
|
+
// Blockquotes
|
|
134
|
+
blockquote: ({ children }) => (
|
|
135
|
+
<blockquote class="border-l-4 border-primary pl-4 py-2 my-6 bg-primary/5 rounded-r-lg">
|
|
136
|
+
{children}
|
|
137
|
+
</blockquote>
|
|
138
|
+
),
|
|
139
|
+
// Horizontal rules
|
|
140
|
+
hr: () => <hr class="border-border my-8" />,
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
{content}
|
|
144
|
+
</ReactMarkdown>
|
|
145
|
+
</article>
|
|
146
|
+
)
|
|
147
|
+
}
|