@usecross/docs 0.10.2 → 0.12.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/dist/index.d.ts +164 -7
- package/dist/index.js +1304 -44
- package/dist/index.js.map +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/types-_anC1UJu.d.ts +320 -0
- package/package.json +1 -1
- package/src/components/DocsLayout.tsx +75 -59
- package/src/components/Sidebar.tsx +171 -28
- package/src/components/TableOfContents.tsx +6 -6
- package/src/components/api/APILayout.tsx +231 -0
- package/src/components/api/APIPage.tsx +216 -0
- package/src/components/api/Breadcrumb.tsx +98 -0
- package/src/components/api/ClassDoc.tsx +257 -0
- package/src/components/api/CodeSpan.tsx +53 -0
- package/src/components/api/Docstring.tsx +269 -0
- package/src/components/api/FunctionDoc.tsx +130 -0
- package/src/components/api/ModuleDoc.tsx +298 -0
- package/src/components/api/ParameterTable.tsx +183 -0
- package/src/components/api/Signature.tsx +317 -0
- package/src/components/api/TableOfContents.tsx +50 -0
- package/src/components/api/index.ts +17 -0
- package/src/components/index.ts +13 -1
- package/src/index.ts +32 -0
- package/src/types.ts +222 -1
- package/dist/types-DlTTA3Dc.d.ts +0 -128
|
@@ -1,13 +1,151 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
1
2
|
import { Link } from '@inertiajs/react'
|
|
2
3
|
import { cn } from '../lib/utils'
|
|
3
4
|
import { DocSetSelector } from './DocSetSelector'
|
|
4
|
-
import type { SidebarProps } from '../types'
|
|
5
|
+
import type { SidebarProps, NavSection } from '../types'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Chevron icon for collapsible sections
|
|
9
|
+
*/
|
|
10
|
+
function ChevronIcon({ expanded, className }: { expanded: boolean; className?: string }) {
|
|
11
|
+
return (
|
|
12
|
+
<svg
|
|
13
|
+
className={cn('w-4 h-4 transition-transform duration-200', expanded && 'rotate-90', className)}
|
|
14
|
+
fill="none"
|
|
15
|
+
viewBox="0 0 24 24"
|
|
16
|
+
stroke="currentColor"
|
|
17
|
+
>
|
|
18
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
19
|
+
</svg>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Collapsible navigation section
|
|
25
|
+
*/
|
|
26
|
+
function CollapsibleSection({
|
|
27
|
+
section,
|
|
28
|
+
currentPath,
|
|
29
|
+
defaultExpanded = true,
|
|
30
|
+
compact = false,
|
|
31
|
+
}: {
|
|
32
|
+
section: NavSection
|
|
33
|
+
currentPath: string
|
|
34
|
+
defaultExpanded?: boolean
|
|
35
|
+
compact?: boolean
|
|
36
|
+
}) {
|
|
37
|
+
// Check if current path is in this section
|
|
38
|
+
const isActive = section.items.some(
|
|
39
|
+
(item) => currentPath === item.href || currentPath + '/' === item.href
|
|
40
|
+
)
|
|
41
|
+
const [expanded, setExpanded] = useState(defaultExpanded || isActive)
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<button
|
|
46
|
+
onClick={() => setExpanded(!expanded)}
|
|
47
|
+
className="w-full flex items-center justify-between mb-2 group"
|
|
48
|
+
>
|
|
49
|
+
<h3 className={cn(
|
|
50
|
+
'text-sm font-mono uppercase tracking-widest text-gray-500 dark:text-gray-400',
|
|
51
|
+
'group-hover:text-gray-700 dark:group-hover:text-gray-300 transition-colors'
|
|
52
|
+
)}>
|
|
53
|
+
{section.title}
|
|
54
|
+
</h3>
|
|
55
|
+
<ChevronIcon expanded={expanded} className="text-gray-400 dark:text-gray-500" />
|
|
56
|
+
</button>
|
|
57
|
+
{expanded && (
|
|
58
|
+
<ul className={cn(
|
|
59
|
+
'border-l-2 border-gray-200 dark:border-gray-700',
|
|
60
|
+
compact ? 'space-y-0.5' : 'space-y-1.5'
|
|
61
|
+
)}>
|
|
62
|
+
{section.items.map((item) => (
|
|
63
|
+
<li key={item.href}>
|
|
64
|
+
<Link
|
|
65
|
+
href={item.href}
|
|
66
|
+
className={cn(
|
|
67
|
+
'block border-l-2 py-1 pl-4 leading-snug transition-colors -ml-0.5',
|
|
68
|
+
compact ? 'text-sm' : 'text-[15px]',
|
|
69
|
+
currentPath === item.href || currentPath + '/' === item.href
|
|
70
|
+
? 'border-primary-500 text-gray-900 dark:text-white font-semibold'
|
|
71
|
+
: 'border-transparent text-gray-600 dark:text-gray-400 hover:border-primary-300 dark:hover:border-primary-400 hover:text-gray-900 dark:hover:text-white'
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
74
|
+
{item.title}
|
|
75
|
+
</Link>
|
|
76
|
+
</li>
|
|
77
|
+
))}
|
|
78
|
+
</ul>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Static navigation section (non-collapsible)
|
|
86
|
+
*/
|
|
87
|
+
function StaticSection({
|
|
88
|
+
section,
|
|
89
|
+
currentPath,
|
|
90
|
+
compact = false,
|
|
91
|
+
}: {
|
|
92
|
+
section: NavSection
|
|
93
|
+
currentPath: string
|
|
94
|
+
compact?: boolean
|
|
95
|
+
}) {
|
|
96
|
+
return (
|
|
97
|
+
<div>
|
|
98
|
+
<h3 className="mb-3 text-sm font-mono uppercase tracking-widest text-gray-500 dark:text-gray-400">
|
|
99
|
+
{section.title}
|
|
100
|
+
</h3>
|
|
101
|
+
<ul className={cn(
|
|
102
|
+
'border-l-2 border-gray-200 dark:border-gray-700',
|
|
103
|
+
compact ? 'space-y-0.5' : 'space-y-1.5'
|
|
104
|
+
)}>
|
|
105
|
+
{section.items.map((item) => (
|
|
106
|
+
<li key={item.href}>
|
|
107
|
+
<Link
|
|
108
|
+
href={item.href}
|
|
109
|
+
className={cn(
|
|
110
|
+
'block border-l-2 py-1 pl-4 leading-snug transition-colors -ml-0.5',
|
|
111
|
+
compact ? 'text-sm' : 'text-[15px]',
|
|
112
|
+
currentPath === item.href || currentPath + '/' === item.href
|
|
113
|
+
? 'border-primary-500 text-gray-900 dark:text-white font-semibold'
|
|
114
|
+
: 'border-transparent text-gray-600 dark:text-gray-400 hover:border-primary-300 dark:hover:border-primary-400 hover:text-gray-900 dark:hover:text-white'
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
{item.title}
|
|
118
|
+
</Link>
|
|
119
|
+
</li>
|
|
120
|
+
))}
|
|
121
|
+
</ul>
|
|
122
|
+
</div>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface ExtendedSidebarProps extends SidebarProps {
|
|
127
|
+
/** Use compact styling (smaller text) */
|
|
128
|
+
compact?: boolean
|
|
129
|
+
/** Make sections collapsible */
|
|
130
|
+
collapsible?: boolean
|
|
131
|
+
/** Collapse sections with more than N items by default */
|
|
132
|
+
collapseThreshold?: number
|
|
133
|
+
}
|
|
5
134
|
|
|
6
135
|
/**
|
|
7
136
|
* Documentation sidebar with section-based navigation.
|
|
8
|
-
*
|
|
137
|
+
* Supports both docs and API navigation styles.
|
|
9
138
|
*/
|
|
10
|
-
export function Sidebar({
|
|
139
|
+
export function Sidebar({
|
|
140
|
+
nav,
|
|
141
|
+
currentPath,
|
|
142
|
+
className,
|
|
143
|
+
docSets,
|
|
144
|
+
currentDocSet,
|
|
145
|
+
compact = false,
|
|
146
|
+
collapsible = false,
|
|
147
|
+
collapseThreshold = 10,
|
|
148
|
+
}: ExtendedSidebarProps) {
|
|
11
149
|
return (
|
|
12
150
|
<nav className={cn('space-y-6', className)}>
|
|
13
151
|
{/* Doc Set Selector - only shown in multi-docs mode */}
|
|
@@ -16,31 +154,36 @@ export function Sidebar({ nav, currentPath, className, docSets, currentDocSet }:
|
|
|
16
154
|
)}
|
|
17
155
|
|
|
18
156
|
{/* Navigation Sections */}
|
|
19
|
-
<div className=
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
157
|
+
<div className={compact ? 'space-y-4' : 'space-y-6'}>
|
|
158
|
+
{nav.map((section) => {
|
|
159
|
+
// Determine if this section should be collapsible
|
|
160
|
+
const shouldCollapse = collapsible && section.items.length > collapseThreshold
|
|
161
|
+
// Check if current path is in this section
|
|
162
|
+
const isActive = section.items.some(
|
|
163
|
+
(item) => currentPath === item.href || currentPath + '/' === item.href
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if (shouldCollapse) {
|
|
167
|
+
return (
|
|
168
|
+
<CollapsibleSection
|
|
169
|
+
key={section.title}
|
|
170
|
+
section={section}
|
|
171
|
+
currentPath={currentPath}
|
|
172
|
+
defaultExpanded={isActive}
|
|
173
|
+
compact={compact}
|
|
174
|
+
/>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<StaticSection
|
|
180
|
+
key={section.title}
|
|
181
|
+
section={section}
|
|
182
|
+
currentPath={currentPath}
|
|
183
|
+
compact={compact}
|
|
184
|
+
/>
|
|
185
|
+
)
|
|
186
|
+
})}
|
|
44
187
|
</div>
|
|
45
188
|
</nav>
|
|
46
189
|
)
|
|
@@ -5,7 +5,7 @@ import type { TableOfContentsProps } from '../types'
|
|
|
5
5
|
* Table of contents component with scroll spy functionality.
|
|
6
6
|
* Displays "ON THIS PAGE" sidebar with heading links.
|
|
7
7
|
*/
|
|
8
|
-
export function TableOfContents({ items, className = '' }: TableOfContentsProps) {
|
|
8
|
+
export function TableOfContents({ items, className = '', ...props }: TableOfContentsProps) {
|
|
9
9
|
const [activeId, setActiveId] = useState<string>(() => {
|
|
10
10
|
// Initialize with hash from URL if present
|
|
11
11
|
if (typeof window !== 'undefined' && window.location.hash) {
|
|
@@ -149,11 +149,11 @@ export function TableOfContents({ items, className = '' }: TableOfContentsProps)
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
return (
|
|
152
|
-
<nav className={className}>
|
|
153
|
-
<h3 className="mb-3 text-
|
|
152
|
+
<nav className={className} {...props}>
|
|
153
|
+
<h3 className="mb-3 text-sm font-mono uppercase tracking-widest text-gray-500 dark:text-gray-400">
|
|
154
154
|
On this page
|
|
155
155
|
</h3>
|
|
156
|
-
<ul className="space-y-1 border-l-2 border-gray-200 dark:border-gray-700">
|
|
156
|
+
<ul className="space-y-1.5 border-l-2 border-gray-200 dark:border-gray-700">
|
|
157
157
|
{items.map((item) => {
|
|
158
158
|
const isActive = activeId === item.id
|
|
159
159
|
const indent = item.level === 3 ? 'pl-6' : 'pl-4'
|
|
@@ -163,13 +163,13 @@ export function TableOfContents({ items, className = '' }: TableOfContentsProps)
|
|
|
163
163
|
<a
|
|
164
164
|
href={`#${item.id}`}
|
|
165
165
|
onClick={(e) => handleClick(e, item.id)}
|
|
166
|
-
className={`block border-l-2 py-1
|
|
166
|
+
className={`block border-l-2 py-1 ${indent} -ml-0.5 text-base leading-snug transition-colors ${
|
|
167
167
|
isActive
|
|
168
168
|
? 'border-primary-500 text-gray-900 dark:text-white font-bold'
|
|
169
169
|
: 'border-transparent text-gray-600 dark:text-gray-300 hover:border-primary-300 dark:hover:border-primary-400 hover:text-gray-900 dark:hover:text-white'
|
|
170
170
|
}`}
|
|
171
171
|
>
|
|
172
|
-
{item.text}
|
|
172
|
+
{item.text || item.title}
|
|
173
173
|
</a>
|
|
174
174
|
</li>
|
|
175
175
|
)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { Head, Link, usePage } from '@inertiajs/react'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { ThemeToggle } from '../ThemeToggle'
|
|
4
|
+
import { useTheme } from '../ThemeProvider'
|
|
5
|
+
import { MobileMenuButton } from '../DocsLayout'
|
|
6
|
+
import { Sidebar } from '../Sidebar'
|
|
7
|
+
import type { NavSection, SharedProps } from '../../types'
|
|
8
|
+
|
|
9
|
+
interface APILayoutProps {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
title: string
|
|
12
|
+
apiNav: NavSection[]
|
|
13
|
+
currentPath: string
|
|
14
|
+
logoUrl?: string
|
|
15
|
+
logoInvertedUrl?: string
|
|
16
|
+
footerLogoUrl?: string
|
|
17
|
+
footerLogoInvertedUrl?: string
|
|
18
|
+
githubUrl?: string
|
|
19
|
+
navLinks?: Array<{ label: string; href: string }>
|
|
20
|
+
/** Right sidebar content (e.g., table of contents) */
|
|
21
|
+
rightSidebar?: React.ReactNode
|
|
22
|
+
/** Custom header component (replaces entire header). Can be a ReactNode or a function that receives mobile menu props. */
|
|
23
|
+
header?: React.ReactNode | ((props: { mobileMenuOpen: boolean; toggleMobileMenu: () => void }) => React.ReactNode)
|
|
24
|
+
/** Header height in pixels. Used to calculate content offset. Defaults to 64 (h-16). */
|
|
25
|
+
headerHeight?: number
|
|
26
|
+
/** Custom footer component */
|
|
27
|
+
footer?: React.ReactNode
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Shared props type for API pages */
|
|
31
|
+
interface APISharedProps extends SharedProps {
|
|
32
|
+
apiNav?: NavSection[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function GitHubIcon() {
|
|
36
|
+
return (
|
|
37
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
38
|
+
<path
|
|
39
|
+
fillRule="evenodd"
|
|
40
|
+
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
|
41
|
+
clipRule="evenodd"
|
|
42
|
+
/>
|
|
43
|
+
</svg>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Layout component for API documentation pages.
|
|
49
|
+
* Uses the shared Sidebar component with compact styling and collapsible sections.
|
|
50
|
+
*/
|
|
51
|
+
export function APILayout({
|
|
52
|
+
children,
|
|
53
|
+
title,
|
|
54
|
+
apiNav,
|
|
55
|
+
currentPath,
|
|
56
|
+
logoUrl: propLogoUrl,
|
|
57
|
+
logoInvertedUrl: propLogoInvertedUrl,
|
|
58
|
+
footerLogoUrl: propFooterLogoUrl,
|
|
59
|
+
footerLogoInvertedUrl: propFooterLogoInvertedUrl,
|
|
60
|
+
githubUrl: propGithubUrl,
|
|
61
|
+
navLinks: propNavLinks,
|
|
62
|
+
rightSidebar,
|
|
63
|
+
header,
|
|
64
|
+
headerHeight: propHeaderHeight = 64,
|
|
65
|
+
footer,
|
|
66
|
+
}: APILayoutProps) {
|
|
67
|
+
const sharedProps = usePage<{ props: APISharedProps }>().props as unknown as APISharedProps
|
|
68
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
|
69
|
+
const { resolvedTheme } = useTheme()
|
|
70
|
+
const headerHeight = propHeaderHeight
|
|
71
|
+
|
|
72
|
+
// Merge props - component props take precedence over shared props from Python
|
|
73
|
+
const logoUrl = propLogoUrl ?? sharedProps.logoUrl
|
|
74
|
+
const logoInvertedUrl = propLogoInvertedUrl ?? sharedProps.logoInvertedUrl
|
|
75
|
+
const githubUrl = propGithubUrl ?? sharedProps.githubUrl
|
|
76
|
+
const navLinks = propNavLinks ?? sharedProps.navLinks ?? []
|
|
77
|
+
|
|
78
|
+
const headerLogo = logoInvertedUrl ? (
|
|
79
|
+
<img src={logoInvertedUrl} alt="Logo" className="h-8" />
|
|
80
|
+
) : logoUrl ? (
|
|
81
|
+
<img src={logoUrl} alt="Logo" className="h-8" />
|
|
82
|
+
) : null
|
|
83
|
+
|
|
84
|
+
const footerLogoUrl = propFooterLogoUrl || sharedProps.footerLogoUrl || logoUrl
|
|
85
|
+
const footerLogoInvertedUrl = propFooterLogoInvertedUrl || sharedProps.footerLogoInvertedUrl || logoInvertedUrl
|
|
86
|
+
const currentFooterLogoUrl = resolvedTheme === 'dark' ? (footerLogoInvertedUrl || footerLogoUrl) : footerLogoUrl
|
|
87
|
+
const footerLogo = currentFooterLogoUrl ? (
|
|
88
|
+
<img src={currentFooterLogoUrl} alt="Logo" className="h-6" />
|
|
89
|
+
) : null
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className="min-h-screen bg-white dark:bg-[#0f0f0f] flex flex-col transition-colors duration-200">
|
|
93
|
+
<Head title={title} />
|
|
94
|
+
|
|
95
|
+
{/* Fixed navigation */}
|
|
96
|
+
{(typeof header === 'function'
|
|
97
|
+
? header({ mobileMenuOpen, toggleMobileMenu: () => setMobileMenuOpen(!mobileMenuOpen) })
|
|
98
|
+
: header) || (
|
|
99
|
+
<nav className="fixed w-full z-50 bg-white/95 dark:bg-[#0f0f0f]/95 backdrop-blur-sm border-b border-gray-200 dark:border-gray-800 transition-colors">
|
|
100
|
+
<div className="px-4 lg:px-10">
|
|
101
|
+
<div className="flex justify-between h-16 items-center">
|
|
102
|
+
<div className="flex items-center gap-2">
|
|
103
|
+
<MobileMenuButton onClick={() => setMobileMenuOpen(!mobileMenuOpen)} isOpen={mobileMenuOpen} />
|
|
104
|
+
{headerLogo ? (
|
|
105
|
+
<Link href="/" className="flex items-center">
|
|
106
|
+
{headerLogo}
|
|
107
|
+
</Link>
|
|
108
|
+
) : (
|
|
109
|
+
<Link href="/" className="font-bold text-lg text-gray-900 dark:text-white">
|
|
110
|
+
Docs
|
|
111
|
+
</Link>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
<div className="flex items-center gap-6">
|
|
115
|
+
<div className="-mr-2">
|
|
116
|
+
<ThemeToggle size="sm" />
|
|
117
|
+
</div>
|
|
118
|
+
{navLinks.map((link) => (
|
|
119
|
+
<Link
|
|
120
|
+
key={link.href}
|
|
121
|
+
href={link.href}
|
|
122
|
+
className="hidden sm:block text-gray-700 dark:text-gray-300 font-medium hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
123
|
+
>
|
|
124
|
+
{link.label}
|
|
125
|
+
</Link>
|
|
126
|
+
))}
|
|
127
|
+
{githubUrl && (
|
|
128
|
+
<a
|
|
129
|
+
href={githubUrl}
|
|
130
|
+
target="_blank"
|
|
131
|
+
rel="noopener noreferrer"
|
|
132
|
+
className="text-gray-700 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
133
|
+
>
|
|
134
|
+
<GitHubIcon />
|
|
135
|
+
</a>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</nav>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
{/* Mobile sidebar */}
|
|
144
|
+
{mobileMenuOpen && (
|
|
145
|
+
<div className="fixed inset-0 z-40 lg:hidden">
|
|
146
|
+
<div className="fixed inset-0 bg-black/50 dark:bg-black/70" onClick={() => setMobileMenuOpen(false)} />
|
|
147
|
+
<div
|
|
148
|
+
className="fixed inset-y-0 left-0 w-72 overflow-y-auto bg-white dark:bg-[#0f0f0f] px-4 py-6 border-r border-gray-200 dark:border-gray-800 transition-colors"
|
|
149
|
+
style={{ paddingTop: headerHeight + 16 }}
|
|
150
|
+
>
|
|
151
|
+
<Sidebar
|
|
152
|
+
nav={apiNav}
|
|
153
|
+
currentPath={currentPath}
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
)}
|
|
158
|
+
|
|
159
|
+
{/* Main content area */}
|
|
160
|
+
<div className="bg-white dark:bg-[#0f0f0f] w-full flex-1 transition-colors" style={{ paddingTop: headerHeight }}>
|
|
161
|
+
<div className="flex">
|
|
162
|
+
{/* Desktop sidebar */}
|
|
163
|
+
<aside
|
|
164
|
+
className="hidden lg:block w-64 shrink-0 border-r border-gray-200 dark:border-gray-800 transition-colors"
|
|
165
|
+
style={{ minHeight: `calc(100vh - ${headerHeight}px)` }}
|
|
166
|
+
>
|
|
167
|
+
<div
|
|
168
|
+
className="sticky px-6 py-6 overflow-y-auto"
|
|
169
|
+
style={{ top: headerHeight, maxHeight: `calc(100vh - ${headerHeight}px)` }}
|
|
170
|
+
>
|
|
171
|
+
<Sidebar
|
|
172
|
+
nav={apiNav}
|
|
173
|
+
currentPath={currentPath}
|
|
174
|
+
/>
|
|
175
|
+
</div>
|
|
176
|
+
</aside>
|
|
177
|
+
|
|
178
|
+
{/* Right section: content + TOC + footer */}
|
|
179
|
+
<div className="flex-1 min-w-0 flex flex-col">
|
|
180
|
+
<div className="flex-1 p-4 lg:px-10 lg:py-6">
|
|
181
|
+
<div className="flex gap-5">
|
|
182
|
+
{/* Main content */}
|
|
183
|
+
<main className="min-w-0 w-full max-w-4xl">
|
|
184
|
+
{children}
|
|
185
|
+
</main>
|
|
186
|
+
|
|
187
|
+
{/* Table of Contents - desktop only */}
|
|
188
|
+
{rightSidebar && (
|
|
189
|
+
<aside className="hidden xl:block w-56 shrink-0 transition-colors">
|
|
190
|
+
<div
|
|
191
|
+
className="sticky overflow-y-auto"
|
|
192
|
+
style={{ top: headerHeight + 24, maxHeight: `calc(100vh - ${headerHeight + 24}px)` }}
|
|
193
|
+
>
|
|
194
|
+
{rightSidebar}
|
|
195
|
+
</div>
|
|
196
|
+
</aside>
|
|
197
|
+
)}
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
{/* Footer */}
|
|
202
|
+
{footer || (
|
|
203
|
+
<footer className="border-t border-gray-200 dark:border-gray-800 py-8 px-4 lg:px-10 transition-colors">
|
|
204
|
+
<div className="flex flex-col md:flex-row justify-between items-center gap-6">
|
|
205
|
+
{footerLogo && <Link href="/">{footerLogo}</Link>}
|
|
206
|
+
<div className="flex gap-8 text-sm text-gray-600 dark:text-gray-400">
|
|
207
|
+
{navLinks.map((link) => (
|
|
208
|
+
<Link key={link.href} href={link.href} className="hover:text-black dark:hover:text-white transition-colors">
|
|
209
|
+
{link.label}
|
|
210
|
+
</Link>
|
|
211
|
+
))}
|
|
212
|
+
{githubUrl && (
|
|
213
|
+
<a
|
|
214
|
+
href={githubUrl}
|
|
215
|
+
target="_blank"
|
|
216
|
+
rel="noopener noreferrer"
|
|
217
|
+
className="hover:text-black dark:hover:text-white transition-colors"
|
|
218
|
+
>
|
|
219
|
+
GitHub
|
|
220
|
+
</a>
|
|
221
|
+
)}
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</footer>
|
|
225
|
+
)}
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
)
|
|
231
|
+
}
|