@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 @@
|
|
|
1
|
+
# ✦ @geenius-docs/solidjs-css\n\n> Geenius Docs — SolidJS components (vanilla CSS variant)\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-css\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius-docs/solidjs-css';\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,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geenius-docs/solidjs-css",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Geenius Docs \u2014 SolidJS components (vanilla CSS variant)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.ts"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"type-check": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"solid-js": ">=1.6.0",
|
|
16
|
+
"@tanstack/solid-router": ">=1.0.0"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@geenius-docs/shared": "workspace:*",
|
|
20
|
+
"lucide-solid": "^0.475.0",
|
|
21
|
+
"solid-markdown": "^1.2.0",
|
|
22
|
+
"remark-gfm": "^4.0.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"solid-js": "^1.9.5",
|
|
26
|
+
"typescript": "~6.0.2"
|
|
27
|
+
},
|
|
28
|
+
"author": "Antigravity HQ",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20.0.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Component, For, Show } from 'solid-js'
|
|
2
|
+
import { useDocs } from './DocsProvider'
|
|
3
|
+
|
|
4
|
+
export interface DocsLayoutProps {
|
|
5
|
+
children?: any
|
|
6
|
+
currentPageId?: string
|
|
7
|
+
onSelectPage?: (id: string) => void
|
|
8
|
+
searchQuery?: string
|
|
9
|
+
onSearch?: (query: string) => void
|
|
10
|
+
searchResults?: any[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A professional, high-quality layout for Geenius Documentation.
|
|
15
|
+
* SolidJS vanilla CSS variant.
|
|
16
|
+
*/
|
|
17
|
+
export const DocsLayout: Component<DocsLayoutProps> = (props) => {
|
|
18
|
+
const ctx = useDocs()
|
|
19
|
+
|
|
20
|
+
const q = () => props.searchQuery ?? ctx.searchQuery()
|
|
21
|
+
const results = () => props.searchResults ?? ctx.searchResults()
|
|
22
|
+
const onSelect = (id: string) => props.onSelectPage ? props.onSelectPage(id) : ctx.selectPage(id)
|
|
23
|
+
const onSearch = (val: string) => props.onSearch ? props.onSearch(val) : ctx.setSearchQuery(val)
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div data-docs-container="">
|
|
27
|
+
<aside data-docs-sidebar="">
|
|
28
|
+
<div data-docs-search-wrap="">
|
|
29
|
+
<div data-docs-search-input-wrap="">
|
|
30
|
+
<span data-docs-search-icon="">
|
|
31
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
|
32
|
+
</span>
|
|
33
|
+
<input
|
|
34
|
+
value={q()}
|
|
35
|
+
onInput={(e) => onSearch(e.currentTarget.value)}
|
|
36
|
+
placeholder="Search knowledge base..."
|
|
37
|
+
data-docs-search-input=""
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<nav data-docs-nav="">
|
|
43
|
+
<Show
|
|
44
|
+
when={q() && results().length > 0}
|
|
45
|
+
fallback={
|
|
46
|
+
<For each={ctx.tree()}>
|
|
47
|
+
{group => (
|
|
48
|
+
<div data-docs-nav-group="">
|
|
49
|
+
<h4 data-docs-nav-group-title="">{group.title}</h4>
|
|
50
|
+
<div data-docs-nav-group-list="">
|
|
51
|
+
<For each={group.children}>
|
|
52
|
+
{page => {
|
|
53
|
+
const isActive = page.id === props.currentPageId
|
|
54
|
+
return (
|
|
55
|
+
<button
|
|
56
|
+
onClick={() => onSelect(page.id)}
|
|
57
|
+
data-docs-nav-item=""
|
|
58
|
+
data-active={isActive}
|
|
59
|
+
>
|
|
60
|
+
<span data-docs-nav-indicator="" data-active={isActive} />
|
|
61
|
+
{page.title}
|
|
62
|
+
</button>
|
|
63
|
+
)
|
|
64
|
+
}}
|
|
65
|
+
</For>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</For>
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
<div data-docs-search-results="">
|
|
73
|
+
<p data-docs-search-results-label="">
|
|
74
|
+
Search Results ({results().length})
|
|
75
|
+
</p>
|
|
76
|
+
<For each={results()}>
|
|
77
|
+
{page => (
|
|
78
|
+
<button
|
|
79
|
+
onClick={() => { onSelect(page.id); onSearch('') }}
|
|
80
|
+
data-docs-search-result-btn=""
|
|
81
|
+
>
|
|
82
|
+
<h5 data-docs-search-result-title="">{page.title}</h5>
|
|
83
|
+
<Show when={page.description}><p data-docs-search-result-desc="">{page.description}</p></Show>
|
|
84
|
+
</button>
|
|
85
|
+
)}
|
|
86
|
+
</For>
|
|
87
|
+
</div>
|
|
88
|
+
</Show>
|
|
89
|
+
</nav>
|
|
90
|
+
</aside>
|
|
91
|
+
|
|
92
|
+
<main data-docs-main="">
|
|
93
|
+
<div data-docs-content="">
|
|
94
|
+
{props.children}
|
|
95
|
+
<div data-docs-footer="">
|
|
96
|
+
<p data-docs-footer-copy="">© 2024 Geenius. Premium Documentation.</p>
|
|
97
|
+
<div data-docs-footer-links="">
|
|
98
|
+
<button data-docs-footer-link="">Edit on GitHub</button>
|
|
99
|
+
<button data-docs-footer-link="">Community Help</button>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</main>
|
|
104
|
+
</div>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
@@ -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,54 @@
|
|
|
1
|
+
import { Component } from 'solid-js'
|
|
2
|
+
import { SolidMarkdown as ReactMarkdown } from 'solid-markdown'
|
|
3
|
+
import remarkGfm from 'remark-gfm'
|
|
4
|
+
import { Link } from '@tanstack/solid-router'
|
|
5
|
+
|
|
6
|
+
interface RouterDocsContentProps {
|
|
7
|
+
content: string
|
|
8
|
+
title: string
|
|
9
|
+
description: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const RouterDocsContent: Component<RouterDocsContentProps> = (props) => {
|
|
13
|
+
return (
|
|
14
|
+
<article data-rdocs-article="">
|
|
15
|
+
<header data-rdocs-header="">
|
|
16
|
+
<h1 data-rdocs-title="">{props.title}</h1>
|
|
17
|
+
<p data-rdocs-description="">{props.description}</p>
|
|
18
|
+
</header>
|
|
19
|
+
|
|
20
|
+
<ReactMarkdown
|
|
21
|
+
remarkPlugins={[remarkGfm]}
|
|
22
|
+
components={{
|
|
23
|
+
h1: ({ children }) => <h1 data-rdocs-h1="">{children}</h1>,
|
|
24
|
+
h2: ({ children }) => <h2 data-rdocs-h2="">{children}</h2>,
|
|
25
|
+
h3: ({ children }) => <h3 data-rdocs-h3="">{children}</h3>,
|
|
26
|
+
h4: ({ children }) => <h4 data-rdocs-h4="">{children}</h4>,
|
|
27
|
+
p: ({ children }) => <p data-rdocs-p="">{children}</p>,
|
|
28
|
+
a: ({ href, children }) => {
|
|
29
|
+
if (href?.startsWith('/')) {
|
|
30
|
+
return <Link to={href} data-rdocs-a="">{children}</Link>
|
|
31
|
+
}
|
|
32
|
+
return <a href={href} target="_blank" rel="noopener noreferrer" data-rdocs-a="">{children}</a>
|
|
33
|
+
},
|
|
34
|
+
code: ({ className, children, ...rest }) => {
|
|
35
|
+
if (!className) return <code data-rdocs-code-inline="">{children}</code>
|
|
36
|
+
return <code class={className} data-rdocs-code-block="" {...rest}>{children}</code>
|
|
37
|
+
},
|
|
38
|
+
pre: ({ children }) => <pre data-rdocs-pre="">{children}</pre>,
|
|
39
|
+
ul: ({ children }) => <ul data-rdocs-ul="">{children}</ul>,
|
|
40
|
+
ol: ({ children }) => <ol data-rdocs-ol="">{children}</ol>,
|
|
41
|
+
li: ({ children }) => <li data-rdocs-li="">{children}</li>,
|
|
42
|
+
table: ({ children }) => <div data-rdocs-table-wrap=""><table data-rdocs-table="">{children}</table></div>,
|
|
43
|
+
thead: ({ children }) => <thead data-rdocs-thead="">{children}</thead>,
|
|
44
|
+
th: ({ children }) => <th data-rdocs-th="">{children}</th>,
|
|
45
|
+
td: ({ children }) => <td data-rdocs-td="">{children}</td>,
|
|
46
|
+
blockquote: ({ children }) => <blockquote data-rdocs-blockquote="">{children}</blockquote>,
|
|
47
|
+
hr: () => <hr data-rdocs-hr="" />,
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{props.content}
|
|
51
|
+
</ReactMarkdown>
|
|
52
|
+
</article>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createSignal, Component, For, Show } from 'solid-js'
|
|
2
|
+
import { Link, useLocation } from '@tanstack/solid-router'
|
|
3
|
+
import { Book, Menu, X, Search, ChevronRight } from 'lucide-solid'
|
|
4
|
+
|
|
5
|
+
export interface DocItem {
|
|
6
|
+
slug: string
|
|
7
|
+
title: string
|
|
8
|
+
description: string
|
|
9
|
+
category: string
|
|
10
|
+
order: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface RouterDocsLayoutProps {
|
|
14
|
+
children?: any
|
|
15
|
+
docs: DocItem[]
|
|
16
|
+
currentSlug?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const RouterDocsLayout: Component<RouterDocsLayoutProps> = (props) => {
|
|
20
|
+
const [isSidebarOpen, setIsSidebarOpen] = createSignal(false)
|
|
21
|
+
|
|
22
|
+
const groupedDocs = () => props.docs.reduce((acc, doc) => {
|
|
23
|
+
if (!acc[doc.category]) { acc[doc.category] = [] }
|
|
24
|
+
acc[doc.category].push(doc)
|
|
25
|
+
return acc
|
|
26
|
+
}, {} as Record<string, DocItem[]>)
|
|
27
|
+
|
|
28
|
+
const sortedCategories = () => Object.entries(groupedDocs()).sort(([a], [b]) => {
|
|
29
|
+
const categoryOrder = ['Introduction', 'Getting Started', 'Guides', 'API', 'Advanced']
|
|
30
|
+
return categoryOrder.indexOf(a) - categoryOrder.indexOf(b)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div data-rdocs-layout="">
|
|
35
|
+
{/* Mobile Header */}
|
|
36
|
+
<div data-rdocs-mobile-header="">
|
|
37
|
+
<Link to="/" data-rdocs-logo="">
|
|
38
|
+
<Book />
|
|
39
|
+
<span>Documentation</span>
|
|
40
|
+
</Link>
|
|
41
|
+
<button onClick={() => setIsSidebarOpen(!isSidebarOpen())} data-rdocs-mobile-btn="">
|
|
42
|
+
{isSidebarOpen() ? <X /> : <Menu />}
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div data-rdocs-body="">
|
|
47
|
+
{/* Sidebar */}
|
|
48
|
+
<aside data-rdocs-sidebar="" data-open={isSidebarOpen()}>
|
|
49
|
+
<div data-rdocs-sidebar-content="">
|
|
50
|
+
<Link to="/" data-rdocs-logo="" data-desktop="">
|
|
51
|
+
<Book />
|
|
52
|
+
<span>Documentation</span>
|
|
53
|
+
</Link>
|
|
54
|
+
|
|
55
|
+
<div data-rdocs-search="">
|
|
56
|
+
<Search data-rdocs-search-icon="" />
|
|
57
|
+
<input type="text" placeholder="Search docs..." data-rdocs-search-input="" />
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<nav data-rdocs-nav="">
|
|
61
|
+
<For each={sortedCategories()}>
|
|
62
|
+
{([category, categoryDocs]) => (
|
|
63
|
+
<div data-rdocs-category-group="">
|
|
64
|
+
<h3 data-rdocs-category-title="">{category}</h3>
|
|
65
|
+
<ul data-rdocs-category-list="">
|
|
66
|
+
<For each={categoryDocs.sort((a, b) => a.order - b.order)}>
|
|
67
|
+
{(doc) => {
|
|
68
|
+
const isActive = props.currentSlug === doc.slug
|
|
69
|
+
return (
|
|
70
|
+
<li>
|
|
71
|
+
<Link
|
|
72
|
+
to="/docs/$slug"
|
|
73
|
+
params={{ slug: doc.slug }}
|
|
74
|
+
activeOptions={{ exact: true }}
|
|
75
|
+
onClick={() => setIsSidebarOpen(false)}
|
|
76
|
+
data-rdocs-nav-link=""
|
|
77
|
+
data-active={isActive}
|
|
78
|
+
>
|
|
79
|
+
<ChevronRight data-rdocs-chevron="" data-active={isActive} />
|
|
80
|
+
{doc.title}
|
|
81
|
+
</Link>
|
|
82
|
+
</li>
|
|
83
|
+
)
|
|
84
|
+
}}
|
|
85
|
+
</For>
|
|
86
|
+
</ul>
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</For>
|
|
90
|
+
</nav>
|
|
91
|
+
</div>
|
|
92
|
+
</aside>
|
|
93
|
+
|
|
94
|
+
<Show when={isSidebarOpen()}>
|
|
95
|
+
<div data-rdocs-overlay="" onClick={() => setIsSidebarOpen(false)} />
|
|
96
|
+
</Show>
|
|
97
|
+
|
|
98
|
+
<main data-rdocs-main="">
|
|
99
|
+
<div data-rdocs-content="">{props.children}</div>
|
|
100
|
+
</main>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// @geenius-docs/solidjs — src/createDocs.ts
|
|
2
|
+
|
|
3
|
+
import { createSignal, createMemo, onMount } from 'solid-js'
|
|
4
|
+
import type { DocsPage, DocsSidebar, DocsSearchResult, DocsProvider } from '@geenius-docs/shared'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* createDocs — SolidJS primitive wrapping a DocsProvider for docs rendering.
|
|
8
|
+
* SolidJS equivalent of useDocs hook.
|
|
9
|
+
*/
|
|
10
|
+
export function createDocs(provider: DocsProvider) {
|
|
11
|
+
const [sidebar, setSidebar] = createSignal<DocsSidebar | null>(null)
|
|
12
|
+
const [currentPage, setCurrentPage] = createSignal<DocsPage | null>(null)
|
|
13
|
+
const [searchResults, setSearchResults] = createSignal<DocsSearchResult[]>([])
|
|
14
|
+
const [isLoading, setIsLoading] = createSignal(false)
|
|
15
|
+
const [searchQuery, setSearchQuery] = createSignal('')
|
|
16
|
+
|
|
17
|
+
// Load sidebar on mount
|
|
18
|
+
onMount(async () => {
|
|
19
|
+
const sb = await provider.getSidebar()
|
|
20
|
+
setSidebar(sb)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const loadPage = async (slug: string) => {
|
|
24
|
+
setIsLoading(true)
|
|
25
|
+
try {
|
|
26
|
+
const page = await provider.getPage(slug)
|
|
27
|
+
setCurrentPage(page)
|
|
28
|
+
} finally {
|
|
29
|
+
setIsLoading(false)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const search = async (query: string) => {
|
|
34
|
+
setSearchQuery(query)
|
|
35
|
+
if (!query.trim()) {
|
|
36
|
+
setSearchResults([])
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
const results = await provider.search(query)
|
|
40
|
+
setSearchResults(results)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const navigation = createMemo(() => {
|
|
44
|
+
const page = currentPage()
|
|
45
|
+
if (!page) return { prev: null, next: null }
|
|
46
|
+
return {
|
|
47
|
+
prev: page.prev ?? null,
|
|
48
|
+
next: page.next ?? null,
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
sidebar,
|
|
54
|
+
currentPage,
|
|
55
|
+
navigation,
|
|
56
|
+
isLoading,
|
|
57
|
+
searchResults,
|
|
58
|
+
searchQuery,
|
|
59
|
+
loadPage,
|
|
60
|
+
search,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DocsProvider, useDocs } from './DocsProvider'
|
|
2
|
+
export type { DocsProviderProps } from './DocsProvider'
|
|
3
|
+
export { createDocs, type CreateDocsOptions, type CreateDocsReturn } from './createDocs'
|
|
4
|
+
|
|
5
|
+
export { DocsLayout } from './DocsLayout'
|
|
6
|
+
export { RouterDocsLayout, type DocItem } from './RouterDocsLayout'
|
|
7
|
+
export { RouterDocsContent } from './RouterDocsContent'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Primitives (re-exported from base SolidJS package)
|
|
2
|
+
export { createDocs, createDocSearch, createDocsAdmin, createTableOfContents } from '@geenius-docs/solidjs'
|
|
3
|
+
|
|
4
|
+
// Components — re-export from SolidJS base (BEM classes come from imported CSS)
|
|
5
|
+
export { DocSidebar, DocPage, TableOfContents, Breadcrumbs, PageNavigation, DocSearch, VersionSelector, EditButton, DocsLayout } from '@geenius-docs/solidjs'
|
|
6
|
+
|
|
7
|
+
// Pages — re-export from SolidJS base
|
|
8
|
+
export { DocsIndexPage, DocViewPage, DocSearchPage, DocsAdminPage } from '@geenius-docs/solidjs'
|
|
9
|
+
|
|
10
|
+
// Styles
|
|
11
|
+
import './styles.css'
|
|
12
|
+
|
|
13
|
+
// Re-export shared types
|
|
14
|
+
export type {
|
|
15
|
+
DocPageType, DocSection, SearchResult, TocItem,
|
|
16
|
+
BreadcrumbItem, DocsConfig, DocAccess, DocStatus,
|
|
17
|
+
} from '@geenius-docs/shared'
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createEffect, createMemo, Show } from 'solid-js'
|
|
2
|
+
import type { DocPage as DocPageType, DocSection } from '@geenius-docs/shared'
|
|
3
|
+
import { buildBreadcrumbs } from '@geenius-docs/shared'
|
|
4
|
+
import { useDocs, useTableOfContents } from '../hooks'
|
|
5
|
+
import { DocsLayout } from '../components/DocsLayout'
|
|
6
|
+
import { DocPage } from '../components/DocPage'
|
|
7
|
+
import { EditButton, PageNavigation } from '../components/common'
|
|
8
|
+
import '../styles.css'
|
|
9
|
+
|
|
10
|
+
interface DocViewPageProps {
|
|
11
|
+
tree: (DocSection & { pages: DocPageType[]; pageCount: number })[] | undefined
|
|
12
|
+
page: DocPageType | null | undefined
|
|
13
|
+
editPageUrl?: string
|
|
14
|
+
onNavigate: (page: DocPageType, section: DocSection) => void
|
|
15
|
+
onIncrementView?: (pageId: string) => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function DocViewPage(props: DocViewPageProps) {
|
|
19
|
+
const docs = useDocs(() => props.tree)
|
|
20
|
+
const { toc, activeId } = useTableOfContents(() => props.page?.content)
|
|
21
|
+
|
|
22
|
+
createEffect(() => {
|
|
23
|
+
if (props.page?.id && props.onIncrementView) {
|
|
24
|
+
props.onIncrementView(props.page.id)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const breadcrumbs = createMemo(() =>
|
|
29
|
+
props.page ? buildBreadcrumbs(docs().sections, props.page.sectionId, props.page.slug) : []
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const navigation = createMemo(() => {
|
|
33
|
+
if (!props.page) return { prev: undefined, next: undefined }
|
|
34
|
+
const all = docs().flatPages
|
|
35
|
+
const idx = all.findIndex(p => p.id === props.page.id)
|
|
36
|
+
const sec = docs().sections.find(s => s.id === props.page.sectionId)
|
|
37
|
+
return {
|
|
38
|
+
prev: idx > 0 ? { title: all[idx - 1].title, href: `/docs/${sec?.slug ?? ''}/${all[idx - 1].slug}` } : undefined,
|
|
39
|
+
next: idx < all.length - 1 ? { title: all[idx + 1].title, href: `/docs/${sec?.slug ?? ''}/${all[idx + 1].slug}` } : undefined,
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Show
|
|
45
|
+
when={!docs().isLoading && props.page !== undefined}
|
|
46
|
+
fallback={
|
|
47
|
+
<div class="docs__layout">
|
|
48
|
+
<div class="docs__sidebar" style={{ padding: '1rem' }}>
|
|
49
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
50
|
+
<div key={i} class="docs__skeleton" style={{ height: '32px', 'margin-bottom': '8px' }} />
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
<div class="docs__content" style={{ padding: '2rem' }}>
|
|
54
|
+
<div class="docs__skeleton" style={{ width: '384px', height: '40px', 'margin-bottom': '16px' }} />
|
|
55
|
+
{Array.from({ length: 10 }).map((_, i) => (
|
|
56
|
+
<div key={i} class="docs__skeleton" style={{ height: '16px', 'margin-bottom': '12px', width: `${60 + Math.random() * 40}%` }} />
|
|
57
|
+
))}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
<Show
|
|
63
|
+
when={props.page}
|
|
64
|
+
fallback={
|
|
65
|
+
<div class="docs__empty" style={{ 'min-height': '100vh', background: 'var(--docs-bg)' }}>
|
|
66
|
+
<div class="docs__empty-icon">🔍</div>
|
|
67
|
+
<h2 class="docs__empty-title">Page not found</h2>
|
|
68
|
+
</div>
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
<DocsLayout
|
|
72
|
+
sections={docs().sections}
|
|
73
|
+
toc={toc()}
|
|
74
|
+
activeHeadingId={activeId()}
|
|
75
|
+
breadcrumbs={breadcrumbs()}
|
|
76
|
+
currentPageId={props.page!.id}
|
|
77
|
+
onNavigate={props.onNavigate}
|
|
78
|
+
>
|
|
79
|
+
<div class="docs__page-header">
|
|
80
|
+
<h1 class="docs__page-title">{props.page!.title}</h1>
|
|
81
|
+
<div class="docs__reading-meta">
|
|
82
|
+
<span class="docs__reading-meta-author">
|
|
83
|
+
{props.page!.author.avatar ? (
|
|
84
|
+
<img src={props.page!.author.avatar} alt="" class="docs__reading-meta-avatar" />
|
|
85
|
+
) : (
|
|
86
|
+
<span class="docs__reading-meta-avatar-placeholder">{props.page!.author.name[0]}</span>
|
|
87
|
+
)}
|
|
88
|
+
{props.page!.author.name}
|
|
89
|
+
</span>
|
|
90
|
+
{props.page!.readingTime > 0 && <span>{props.page!.readingTime} min read</span>}
|
|
91
|
+
{props.page!.viewCount > 0 && <span>{props.page!.viewCount.toLocaleString()} views</span>}
|
|
92
|
+
</div>
|
|
93
|
+
{props.page!.tags.length > 0 && (
|
|
94
|
+
<div class="docs__tags">
|
|
95
|
+
{props.page!.tags.map(t => (
|
|
96
|
+
<span key={t} class="docs__tag">{t}</span>
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
<DocPage page={props.page!} />
|
|
102
|
+
<div style={{ 'margin-top': '2.5rem', 'padding-top': '1.5rem', 'border-top': '1px solid var(--docs-border)', display: 'flex', 'justify-content': 'space-between', 'align-items': 'center' }}>
|
|
103
|
+
<EditButton pageSlug={props.page!.slug} editUrl={props.editPageUrl} />
|
|
104
|
+
{props.page!.version && <span style={{ 'font-size': '0.6875rem', color: 'oklch(1 0 0/0.25)' }}>v{props.page!.version}</span>}
|
|
105
|
+
</div>
|
|
106
|
+
<PageNavigation prev={navigation().prev} next={navigation().next} />
|
|
107
|
+
</DocsLayout>
|
|
108
|
+
</Show>
|
|
109
|
+
</Show>
|
|
110
|
+
)
|
|
111
|
+
}
|