@raystack/chronicle 0.5.4 → 0.6.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/cli/index.js +258 -80
- package/package.json +8 -6
- package/src/cli/commands/build.ts +5 -8
- package/src/cli/commands/dev.ts +5 -6
- package/src/cli/commands/init.test.ts +77 -0
- package/src/cli/commands/init.ts +73 -40
- package/src/cli/commands/serve.ts +6 -9
- package/src/cli/commands/start.ts +5 -5
- package/src/cli/utils/config.ts +6 -12
- package/src/cli/utils/scaffold.test.ts +179 -0
- package/src/cli/utils/scaffold.ts +70 -9
- package/src/components/api/field-row.tsx +1 -1
- package/src/components/api/field-section.tsx +2 -2
- package/src/components/mdx/index.tsx +1 -1
- package/src/components/mdx/mermaid.tsx +24 -21
- package/src/components/ui/breadcrumbs.tsx +4 -2
- package/src/components/ui/client-theme-switcher.tsx +21 -4
- package/src/components/ui/search.module.css +16 -41
- package/src/components/ui/search.tsx +30 -41
- package/src/lib/config.test.ts +493 -0
- package/src/lib/config.ts +123 -22
- package/src/lib/head.tsx +23 -5
- package/src/lib/llms.test.ts +94 -0
- package/src/lib/llms.ts +41 -0
- package/src/lib/navigation.test.ts +94 -0
- package/src/lib/navigation.ts +51 -0
- package/src/lib/page-context.tsx +51 -32
- package/src/lib/route-resolver.test.ts +173 -0
- package/src/lib/route-resolver.ts +73 -0
- package/src/lib/source.ts +94 -1
- package/src/lib/version-source.test.ts +163 -0
- package/src/lib/version-source.ts +101 -0
- package/src/pages/ApiPage.tsx +1 -1
- package/src/pages/DocsLayout.tsx +24 -3
- package/src/pages/DocsPage.tsx +3 -6
- package/src/pages/LandingPage.module.css +56 -0
- package/src/pages/LandingPage.tsx +39 -0
- package/src/pages/NotFound.tsx +2 -0
- package/src/server/App.tsx +21 -23
- package/src/server/api/page.ts +5 -1
- package/src/server/api/search.ts +51 -24
- package/src/server/api/specs.ts +17 -5
- package/src/server/entry-client.tsx +42 -14
- package/src/server/entry-server.tsx +33 -11
- package/src/server/routes/[...slug].md.ts +0 -6
- package/src/server/routes/[version]/llms.txt.ts +26 -0
- package/src/server/routes/llms.txt.ts +10 -13
- package/src/server/routes/og.tsx +2 -2
- package/src/server/routes/sitemap.xml.ts +14 -6
- package/src/server/vite-config.ts +5 -5
- package/src/themes/default/ContentDirButtons.tsx +66 -0
- package/src/themes/default/Layout.module.css +187 -40
- package/src/themes/default/Layout.tsx +166 -65
- package/src/themes/default/OpenInAI.tsx +112 -0
- package/src/themes/default/Page.module.css +30 -0
- package/src/themes/default/Page.tsx +1 -3
- package/src/themes/default/SidebarLogo.tsx +26 -0
- package/src/themes/default/Toc.module.css +102 -25
- package/src/themes/default/Toc.tsx +56 -10
- package/src/themes/default/VersionSwitcher.tsx +59 -0
- package/src/themes/paper/ContentDirDropdown.tsx +47 -0
- package/src/themes/paper/Layout.module.css +7 -0
- package/src/themes/paper/Layout.tsx +20 -13
- package/src/themes/paper/VersionSwitcher.tsx +60 -0
- package/src/types/config.ts +145 -23
- package/src/types/content.ts +11 -1
- package/src/types/theme.ts +1 -0
- package/src/components/ui/footer.module.css +0 -27
- package/src/components/ui/footer.tsx +0 -30
|
@@ -1,79 +1,226 @@
|
|
|
1
1
|
.layout {
|
|
2
|
+
--navbar-height: 48px;
|
|
2
3
|
min-height: 100vh;
|
|
3
4
|
}
|
|
4
5
|
|
|
5
|
-
.header {
|
|
6
|
-
border-bottom: 1px solid var(--rs-color-border-base-primary);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.search {
|
|
10
|
-
margin-left: var(--rs-space-5);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
6
|
.body {
|
|
14
7
|
flex: 1;
|
|
15
8
|
}
|
|
16
9
|
|
|
17
10
|
.sidebar {
|
|
18
|
-
width:
|
|
11
|
+
width: 262px;
|
|
12
|
+
flex: 0 0 262px;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
19
15
|
position: sticky;
|
|
20
16
|
top: 0;
|
|
21
17
|
height: 100vh;
|
|
18
|
+
background: var(--rs-color-background-base-secondary);
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
.sidebarLogo {
|
|
22
|
+
width: 28px;
|
|
23
|
+
height: 28px;
|
|
24
|
+
object-fit: contain;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
.
|
|
30
|
-
|
|
27
|
+
.configIcon {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
width: 16px;
|
|
32
|
+
height: 16px;
|
|
33
|
+
color: currentColor;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.configIcon svg {
|
|
37
|
+
width: 100%;
|
|
38
|
+
height: 100%;
|
|
39
|
+
display: block;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sidebar[data-position='left'] {
|
|
43
|
+
border-right: none;
|
|
31
44
|
padding: 0;
|
|
32
|
-
margin: 0;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
.sidebarNavbar {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
gap: var(--rs-space-3);
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: var(--navbar-height);
|
|
54
|
+
padding: 0 var(--rs-space-5);
|
|
55
|
+
flex-shrink: 0;
|
|
56
|
+
backdrop-filter: blur(1px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.sidebarNavLogo {
|
|
60
|
+
color: var(--rs-color-foreground-base-primary);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.sidebarNavActions {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: var(--rs-space-3);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.sidebarMain {
|
|
70
|
+
padding: var(--rs-space-7) var(--rs-space-5);
|
|
71
|
+
gap: 0;
|
|
72
|
+
min-height: 0;
|
|
73
|
+
overflow-y: auto;
|
|
74
|
+
scrollbar-width: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.topLinks {
|
|
78
|
+
width: 100%;
|
|
79
|
+
margin-bottom: var(--rs-space-7);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.topLinkItem {
|
|
83
|
+
color: var(--rs-color-foreground-base-tertiary);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.topLinkText {
|
|
87
|
+
color: var(--rs-color-foreground-base-tertiary);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.topLinkItem[data-active='true'] {
|
|
91
|
+
background: transparent;
|
|
92
|
+
color: var(--rs-color-foreground-base-primary);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.topLinkItem[data-active='true'] .topLinkText {
|
|
96
|
+
color: var(--rs-color-foreground-base-primary);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.sidebarFooter {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
gap: var(--rs-space-3);
|
|
103
|
+
height: var(--navbar-height);
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
padding: 0 var(--rs-space-5);
|
|
106
|
+
border-top: 0.5px solid var(--rs-color-border-base-primary);
|
|
107
|
+
background: var(--rs-color-background-base-secondary);
|
|
108
|
+
backdrop-filter: blur(7.5px);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.sidebarMain::-webkit-scrollbar {
|
|
112
|
+
display: none;
|
|
39
113
|
}
|
|
40
114
|
|
|
41
|
-
.
|
|
42
|
-
|
|
115
|
+
.sidebarHeader {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: space-between;
|
|
119
|
+
gap: var(--rs-space-3);
|
|
120
|
+
height: var(--navbar-height);
|
|
121
|
+
box-sizing: border-box;
|
|
122
|
+
margin-bottom: 0;
|
|
123
|
+
padding: 0 var(--rs-space-5);
|
|
124
|
+
background: var(--rs-color-background-base-secondary);
|
|
125
|
+
border-bottom: 0.5px solid var(--rs-color-border-base-primary);
|
|
126
|
+
border-radius: 0;
|
|
127
|
+
backdrop-filter: blur(1px);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.mainArea {
|
|
131
|
+
flex: 1;
|
|
132
|
+
min-width: 0;
|
|
43
133
|
}
|
|
44
134
|
|
|
45
|
-
.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
135
|
+
.cardWrapper {
|
|
136
|
+
flex: 1;
|
|
137
|
+
display: flex;
|
|
138
|
+
padding: 0 0 var(--rs-space-2) 0;
|
|
139
|
+
min-height: 0;
|
|
140
|
+
background: var(--rs-color-background-base-secondary);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.card {
|
|
144
|
+
flex: 1;
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
border-left: 0.5px solid var(--rs-color-border-base-primary);
|
|
148
|
+
box-shadow: var(--rs-shadow-soft);
|
|
149
|
+
overflow: visible;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.subNav {
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: space-between;
|
|
156
|
+
height: var(--navbar-height);
|
|
157
|
+
padding: var(--rs-space-4) var(--rs-space-7);
|
|
158
|
+
background: var(--rs-color-background-base-primary);
|
|
159
|
+
border-bottom: 0.5px solid var(--rs-color-border-base-primary);
|
|
160
|
+
backdrop-filter: blur(1px);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.subNavLeft {
|
|
164
|
+
min-width: 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.content {
|
|
168
|
+
flex: 1;
|
|
169
|
+
padding: var(--rs-space-9) var(--rs-space-7);
|
|
170
|
+
background: var(--rs-color-background-base-primary);
|
|
51
171
|
}
|
|
52
172
|
|
|
53
|
-
.
|
|
54
|
-
margin-top: var(--rs-space-2);
|
|
173
|
+
.groupItems {
|
|
55
174
|
padding-left: var(--rs-space-4);
|
|
175
|
+
padding-bottom: var(--rs-space-3);
|
|
176
|
+
gap: 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.navGroup {
|
|
180
|
+
margin-top: 0;
|
|
56
181
|
}
|
|
57
182
|
|
|
58
|
-
.
|
|
183
|
+
.navGroup[data-depth='0'] {
|
|
184
|
+
margin-top: var(--rs-space-7);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.navGroup .navGroupHeader {
|
|
188
|
+
margin: 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.navGroup[data-depth='1'] .navGroupHeader {
|
|
192
|
+
height: auto;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.navGroup[data-depth='1'] .navGroupLabel {
|
|
196
|
+
color: var(--rs-color-foreground-base-primary);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.navGroupTrigger {
|
|
59
200
|
display: flex;
|
|
201
|
+
padding: var(--rs-space-3);
|
|
60
202
|
align-items: center;
|
|
203
|
+
gap: var(--rs-space-3);
|
|
204
|
+
align-self: stretch;
|
|
205
|
+
width: 100%;
|
|
61
206
|
height: 32px;
|
|
62
|
-
padding: 0 var(--rs-space-4);
|
|
63
|
-
border: 1px solid var(--rs-color-border-base-primary);
|
|
64
207
|
border-radius: var(--rs-radius-2);
|
|
65
|
-
|
|
66
|
-
font-weight: var(--rs-font-weight-medium);
|
|
67
|
-
color: var(--rs-color-foreground-base-primary);
|
|
68
|
-
text-decoration: none;
|
|
208
|
+
box-sizing: border-box;
|
|
69
209
|
}
|
|
70
210
|
|
|
71
|
-
.
|
|
72
|
-
|
|
211
|
+
.navGroupLabel {
|
|
212
|
+
flex: 1;
|
|
213
|
+
text-align: left;
|
|
214
|
+
color: var(--rs-color-foreground-base-secondary);
|
|
215
|
+
font-family: var(--rs-font-body);
|
|
216
|
+
font-size: var(--rs-font-size-small);
|
|
217
|
+
font-weight: var(--rs-font-weight-medium);
|
|
218
|
+
line-height: var(--rs-line-height-small);
|
|
219
|
+
letter-spacing: var(--rs-letter-spacing-small);
|
|
73
220
|
}
|
|
74
221
|
|
|
75
|
-
.
|
|
76
|
-
|
|
222
|
+
.navGroupChevron {
|
|
223
|
+
margin-left: auto;
|
|
77
224
|
}
|
|
78
225
|
|
|
79
226
|
.page {
|
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import { RectangleStackIcon } from '@heroicons/react/24/outline';
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from '@
|
|
2
|
+
ArrowLeftIcon,
|
|
3
|
+
ArrowRightIcon,
|
|
4
|
+
CodeBracketSquareIcon,
|
|
5
|
+
RectangleStackIcon,
|
|
6
|
+
DocumentTextIcon,
|
|
7
|
+
Squares2X2Icon
|
|
8
|
+
} from '@heroicons/react/24/outline';
|
|
9
|
+
import { Flex, IconButton, Sidebar } from '@raystack/apsara';
|
|
10
10
|
import { cx } from 'class-variance-authority';
|
|
11
|
-
import { useEffect, useRef } from 'react';
|
|
12
|
-
import { Link as RouterLink, useLocation } from 'react-router';
|
|
11
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
12
|
+
import { Link as RouterLink, useLocation, useNavigate } from 'react-router';
|
|
13
13
|
import { MethodBadge } from '@/components/api/method-badge';
|
|
14
14
|
import { ClientThemeSwitcher } from '@/components/ui/client-theme-switcher';
|
|
15
|
-
import { Footer } from '@/components/ui/footer';
|
|
16
15
|
import { Search } from '@/components/ui/search';
|
|
16
|
+
import { Breadcrumbs } from '@/components/ui/breadcrumbs';
|
|
17
|
+
import { getLandingEntries } from '@/lib/config';
|
|
18
|
+
import { getActiveContentDir } from '@/lib/navigation';
|
|
19
|
+
import { usePageContext } from '@/lib/page-context';
|
|
17
20
|
import type { Node } from 'fumadocs-core/page-tree';
|
|
18
21
|
import type { ThemeLayoutProps } from '@/types';
|
|
19
22
|
import styles from './Layout.module.css';
|
|
23
|
+
import { OpenInAI } from './OpenInAI';
|
|
24
|
+
import { SidebarLogo } from './SidebarLogo';
|
|
25
|
+
import { VersionSwitcher } from './VersionSwitcher';
|
|
20
26
|
|
|
21
27
|
const iconMap: Record<string, React.ReactNode> = {
|
|
22
28
|
'rectangle-stack': <RectangleStackIcon width={16} height={16} />,
|
|
@@ -27,16 +33,51 @@ const iconMap: Record<string, React.ReactNode> = {
|
|
|
27
33
|
'method-patch': <MethodBadge method='PATCH' size='micro' />
|
|
28
34
|
};
|
|
29
35
|
|
|
36
|
+
function renderConfigIcon(
|
|
37
|
+
icon: string | undefined,
|
|
38
|
+
alt: string,
|
|
39
|
+
fallback: React.ReactNode
|
|
40
|
+
): React.ReactNode {
|
|
41
|
+
if (!icon) return fallback;
|
|
42
|
+
if (icon.trim().startsWith('<svg')) {
|
|
43
|
+
return (
|
|
44
|
+
<span
|
|
45
|
+
aria-label={alt}
|
|
46
|
+
className={styles.configIcon}
|
|
47
|
+
dangerouslySetInnerHTML={{ __html: icon }}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return <img src={icon} alt={alt} className={styles.configIcon} />;
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
let savedScrollTop = 0;
|
|
31
55
|
|
|
32
56
|
export function Layout({
|
|
33
57
|
children,
|
|
34
58
|
config,
|
|
35
59
|
tree,
|
|
60
|
+
hideSidebar,
|
|
36
61
|
classNames
|
|
37
62
|
}: ThemeLayoutProps) {
|
|
38
63
|
const { pathname } = useLocation();
|
|
64
|
+
const navigate = useNavigate();
|
|
65
|
+
const { page, version } = usePageContext();
|
|
39
66
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
const isApiRoute = pathname === '/apis' || pathname.startsWith('/apis/');
|
|
68
|
+
const isApiBase = (basePath: string) =>
|
|
69
|
+
pathname === basePath || pathname.startsWith(`${basePath}/`);
|
|
70
|
+
const { prev, next } = page ?? { prev: null, next: null };
|
|
71
|
+
|
|
72
|
+
const contentEntries = getLandingEntries(config, version.dir);
|
|
73
|
+
const activeContentDir = getActiveContentDir(pathname, config);
|
|
74
|
+
const apiEntries = config.api ?? [];
|
|
75
|
+
const showTopLinks = contentEntries.length + apiEntries.length > 1;
|
|
76
|
+
|
|
77
|
+
const slug = useMemo(
|
|
78
|
+
() => (pathname === '/' ? [] : pathname.split('/').filter(Boolean)),
|
|
79
|
+
[pathname]
|
|
80
|
+
);
|
|
40
81
|
|
|
41
82
|
useEffect(() => {
|
|
42
83
|
const el = scrollRef.current;
|
|
@@ -58,87 +99,147 @@ export function Layout({
|
|
|
58
99
|
|
|
59
100
|
return (
|
|
60
101
|
<Flex direction='column' className={cx(styles.layout, classNames?.layout)}>
|
|
61
|
-
<Navbar className={styles.header}>
|
|
62
|
-
<Navbar.Start>
|
|
63
|
-
<RouterLink
|
|
64
|
-
to='/'
|
|
65
|
-
style={{ textDecoration: 'none', color: 'inherit' }}
|
|
66
|
-
>
|
|
67
|
-
<Headline size='small' weight='medium' as='h1'>
|
|
68
|
-
{config.title}
|
|
69
|
-
</Headline>
|
|
70
|
-
</RouterLink>
|
|
71
|
-
</Navbar.Start>
|
|
72
|
-
<Navbar.End>
|
|
73
|
-
<Flex gap='medium' align='center' className={styles.navActions}>
|
|
74
|
-
{config.api?.map(api => (
|
|
75
|
-
<RouterLink
|
|
76
|
-
key={api.basePath}
|
|
77
|
-
to={api.basePath}
|
|
78
|
-
className={styles.navButton}
|
|
79
|
-
>
|
|
80
|
-
{api.name} API
|
|
81
|
-
</RouterLink>
|
|
82
|
-
))}
|
|
83
|
-
{config.navigation?.links?.map(link => (
|
|
84
|
-
<Link key={link.href} href={link.href}>
|
|
85
|
-
{link.label}
|
|
86
|
-
</Link>
|
|
87
|
-
))}
|
|
88
|
-
{config.search?.enabled && <Search />}
|
|
89
|
-
</Flex>
|
|
90
|
-
<ClientThemeSwitcher size={16} />
|
|
91
|
-
</Navbar.End>
|
|
92
|
-
</Navbar>
|
|
93
102
|
<Flex className={cx(styles.body, classNames?.body)}>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
{hideSidebar ? null : (
|
|
104
|
+
<Sidebar
|
|
105
|
+
defaultOpen
|
|
106
|
+
collapsible={false}
|
|
107
|
+
className={cx(styles.sidebar, classNames?.sidebar)}
|
|
108
|
+
>
|
|
109
|
+
<Sidebar.Header className={styles.sidebarHeader}>
|
|
110
|
+
<SidebarLogo config={config} />
|
|
111
|
+
<Flex gap='small' align='center'>
|
|
112
|
+
{config.search?.enabled && <Search />}
|
|
113
|
+
<ClientThemeSwitcher size={16} />
|
|
114
|
+
</Flex>
|
|
115
|
+
</Sidebar.Header>
|
|
116
|
+
<Sidebar.Main ref={scrollRef} className={styles.sidebarMain}>
|
|
117
|
+
{showTopLinks ? (
|
|
118
|
+
<div className={styles.topLinks}>
|
|
119
|
+
{contentEntries.map(entry => (
|
|
120
|
+
<Sidebar.Item
|
|
121
|
+
key={entry.href}
|
|
122
|
+
href={entry.href}
|
|
123
|
+
active={activeContentDir === entry.contentDir}
|
|
124
|
+
leadingIcon={renderConfigIcon(
|
|
125
|
+
entry.icon,
|
|
126
|
+
entry.label,
|
|
127
|
+
<DocumentTextIcon width={16} height={16} />
|
|
128
|
+
)}
|
|
129
|
+
classNames={{ root: styles.topLinkItem, text: styles.topLinkText }}
|
|
130
|
+
render={<RouterLink to={entry.href} />}
|
|
131
|
+
>
|
|
132
|
+
{entry.label}
|
|
133
|
+
</Sidebar.Item>
|
|
134
|
+
))}
|
|
135
|
+
{apiEntries.map(api => (
|
|
136
|
+
<Sidebar.Item
|
|
137
|
+
key={api.basePath}
|
|
138
|
+
href={api.basePath}
|
|
139
|
+
active={isApiBase(api.basePath)}
|
|
140
|
+
leadingIcon={renderConfigIcon(
|
|
141
|
+
api.icon,
|
|
142
|
+
api.name,
|
|
143
|
+
<CodeBracketSquareIcon width={16} height={16} />
|
|
144
|
+
)}
|
|
145
|
+
classNames={{ root: styles.topLinkItem, text: styles.topLinkText }}
|
|
146
|
+
render={<RouterLink to={api.basePath} />}
|
|
147
|
+
>
|
|
148
|
+
{api.name} API
|
|
149
|
+
</Sidebar.Item>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
) : null}
|
|
153
|
+
{tree.children.map((item, i) => (
|
|
154
|
+
<SidebarNode
|
|
155
|
+
key={item.type === 'page' ? item.url : (item.name?.toString() ?? i)}
|
|
156
|
+
item={item}
|
|
157
|
+
pathname={pathname}
|
|
158
|
+
/>
|
|
159
|
+
))}
|
|
160
|
+
</Sidebar.Main>
|
|
161
|
+
{config.versions?.length ? (
|
|
162
|
+
<Sidebar.Footer className={styles.sidebarFooter}>
|
|
163
|
+
<VersionSwitcher />
|
|
164
|
+
</Sidebar.Footer>
|
|
165
|
+
) : null}
|
|
166
|
+
</Sidebar>
|
|
167
|
+
)}
|
|
168
|
+
<Flex direction='column' className={styles.mainArea}>
|
|
169
|
+
<div className={styles.cardWrapper}>
|
|
170
|
+
<div className={styles.card}>
|
|
171
|
+
<nav className={styles.subNav}>
|
|
172
|
+
<Flex align='center' gap='small' className={styles.subNavLeft}>
|
|
173
|
+
<Flex align='center' gap='extra-small'>
|
|
174
|
+
<IconButton
|
|
175
|
+
size={2}
|
|
176
|
+
disabled={!prev}
|
|
177
|
+
onClick={() => prev && navigate(prev.url)}
|
|
178
|
+
aria-label='Previous page'
|
|
179
|
+
>
|
|
180
|
+
<ArrowLeftIcon width={14} height={14} />
|
|
181
|
+
</IconButton>
|
|
182
|
+
<IconButton
|
|
183
|
+
size={2}
|
|
184
|
+
disabled={!next}
|
|
185
|
+
onClick={() => next && navigate(next.url)}
|
|
186
|
+
aria-label='Next page'
|
|
187
|
+
>
|
|
188
|
+
<ArrowRightIcon width={14} height={14} />
|
|
189
|
+
</IconButton>
|
|
190
|
+
</Flex>
|
|
191
|
+
{!isApiRoute && <Breadcrumbs slug={slug} tree={tree} />}
|
|
192
|
+
</Flex>
|
|
193
|
+
<OpenInAI />
|
|
194
|
+
</nav>
|
|
195
|
+
<main className={cx(styles.content, classNames?.content)}>
|
|
196
|
+
{children}
|
|
197
|
+
</main>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</Flex>
|
|
112
201
|
</Flex>
|
|
113
|
-
<Footer config={config.footer} />
|
|
114
202
|
</Flex>
|
|
115
203
|
);
|
|
116
204
|
}
|
|
117
205
|
|
|
118
206
|
function SidebarNode({
|
|
119
207
|
item,
|
|
120
|
-
pathname
|
|
208
|
+
pathname,
|
|
209
|
+
depth = 0
|
|
121
210
|
}: {
|
|
122
211
|
item: Node;
|
|
123
212
|
pathname: string;
|
|
213
|
+
depth?: number;
|
|
124
214
|
}) {
|
|
125
215
|
if (item.type === 'separator') {
|
|
126
216
|
return null;
|
|
127
217
|
}
|
|
128
218
|
|
|
129
219
|
if (item.type === 'folder') {
|
|
220
|
+
if (depth > 1) return null;
|
|
130
221
|
const icon = typeof item.icon === 'string' ? iconMap[item.icon] : item.icon;
|
|
131
222
|
return (
|
|
132
223
|
<Sidebar.Group
|
|
224
|
+
className={styles.navGroup}
|
|
225
|
+
data-depth={depth}
|
|
133
226
|
label={item.name?.toString() ?? ''}
|
|
134
227
|
leadingIcon={icon ?? undefined}
|
|
135
|
-
|
|
228
|
+
collapsible={depth === 1}
|
|
229
|
+
classNames={{
|
|
230
|
+
items: styles.groupItems,
|
|
231
|
+
header: styles.navGroupHeader,
|
|
232
|
+
trigger: styles.navGroupTrigger,
|
|
233
|
+
label: styles.navGroupLabel,
|
|
234
|
+
chevron: styles.navGroupChevron,
|
|
235
|
+
}}
|
|
136
236
|
>
|
|
137
237
|
{item.children.map((child, i) => (
|
|
138
238
|
<SidebarNode
|
|
139
239
|
key={child.type === 'page' ? child.url : (child.name?.toString() ?? i)}
|
|
140
240
|
item={child}
|
|
141
241
|
pathname={pathname}
|
|
242
|
+
depth={depth + 1}
|
|
142
243
|
/>
|
|
143
244
|
))}
|
|
144
245
|
</Sidebar.Group>
|
|
@@ -155,7 +256,7 @@ function SidebarNode({
|
|
|
155
256
|
href={href}
|
|
156
257
|
active={isActive}
|
|
157
258
|
leadingIcon={icon ?? undefined}
|
|
158
|
-
|
|
259
|
+
render={link}
|
|
159
260
|
>
|
|
160
261
|
{item.name}
|
|
161
262
|
</Sidebar.Item>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ChevronDownIcon,
|
|
5
|
+
ClipboardDocumentIcon,
|
|
6
|
+
DocumentTextIcon,
|
|
7
|
+
SparklesIcon
|
|
8
|
+
} from '@heroicons/react/24/outline';
|
|
9
|
+
import { Button, Menu } from '@raystack/apsara';
|
|
10
|
+
import { useCallback } from 'react';
|
|
11
|
+
|
|
12
|
+
function ClaudeIcon() {
|
|
13
|
+
return (
|
|
14
|
+
<svg
|
|
15
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
16
|
+
width='14'
|
|
17
|
+
height='14'
|
|
18
|
+
viewBox='0 0 24 24'
|
|
19
|
+
fill='currentColor'
|
|
20
|
+
fillRule='evenodd'
|
|
21
|
+
aria-hidden='true'
|
|
22
|
+
>
|
|
23
|
+
<title>Claude</title>
|
|
24
|
+
<path d='M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z' />
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ChatGPTIcon() {
|
|
30
|
+
return (
|
|
31
|
+
<svg
|
|
32
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
33
|
+
width='14'
|
|
34
|
+
height='14'
|
|
35
|
+
viewBox='0 0 12 12'
|
|
36
|
+
fill='none'
|
|
37
|
+
aria-hidden='true'
|
|
38
|
+
>
|
|
39
|
+
<path
|
|
40
|
+
d='M4.60254 4.37898V3.24915C4.60254 3.154 4.63825 3.08261 4.72146 3.0351L6.99307 1.72688C7.30228 1.54849 7.67098 1.46528 8.0515 1.46528C9.47862 1.46528 10.3825 2.57135 10.3825 3.74869C10.3825 3.83193 10.3825 3.92708 10.3706 4.02224L8.01581 2.64263C7.87311 2.55942 7.73034 2.55942 7.58765 2.64263L4.60254 4.37898ZM9.90677 8.77939V6.07964C9.90677 5.91311 9.83537 5.79418 9.6927 5.71095L6.70759 3.9746L7.6828 3.41559C7.76603 3.36808 7.83742 3.36808 7.92065 3.41559L10.1922 4.72381C10.8464 5.10443 11.2864 5.91311 11.2864 6.69799C11.2864 7.60182 10.7512 8.43436 9.90677 8.77929V8.77939ZM3.90086 6.40083L2.92565 5.83C2.84244 5.78248 2.80672 5.71107 2.80672 5.61592V2.9995C2.80672 1.727 3.78194 0.763609 5.10208 0.763609C5.60165 0.763609 6.06537 0.930148 6.45794 1.22746L4.11504 2.58329C3.97237 2.6665 3.90099 2.78543 3.90099 2.95199V6.40092L3.90086 6.40083ZM5.99999 7.61387L4.60254 6.82896V5.16401L5.99999 4.37911L7.39734 5.16401V6.82896L5.99999 7.61387ZM6.89789 11.2294C6.39835 11.2294 5.93463 11.0628 5.54206 10.7655L7.88493 9.40968C8.02763 9.32647 8.09901 9.20755 8.09901 9.04098V5.59205L9.08618 6.16288C9.16938 6.21039 9.2051 6.28178 9.2051 6.37696V8.99337C9.2051 10.2659 8.21794 11.2293 6.89789 11.2293V11.2294ZM4.07925 8.57726L1.80764 7.26906C1.15348 6.88842 0.713498 6.07977 0.713498 5.29486C0.713498 4.37911 1.26058 3.55851 2.10492 3.21358V5.92515C2.10492 6.09169 2.17633 6.21062 2.319 6.29385L5.29229 8.01825L4.31707 8.57726C4.23387 8.62477 4.16246 8.62477 4.07925 8.57726ZM3.9485 10.5277C2.60459 10.5277 1.61745 9.51678 1.61745 8.26802C1.61745 8.17287 1.62938 8.07772 1.6412 7.98256L3.9841 9.33839C4.12677 9.42163 4.26956 9.42163 4.41223 9.33839L7.39734 7.61399V8.74382C7.39734 8.83898 7.36165 8.91036 7.27841 8.95788L5.00683 10.2661C4.69759 10.4445 4.3289 10.5277 3.94838 10.5277H3.9485ZM6.89789 11.9429C8.33696 11.9429 9.53808 10.9201 9.81172 9.5643C11.1437 9.21937 12 7.97061 12 6.69811C12 5.86557 11.6433 5.05691 11.001 4.47414C11.0605 4.22437 11.0962 3.9746 11.0962 3.72495C11.0962 2.02429 9.71656 0.751662 8.12288 0.751662C7.80185 0.751662 7.49262 0.799178 7.18338 0.906279C6.64812 0.382967 5.91076 0.0499878 5.10208 0.0499878C3.66304 0.0499878 2.46192 1.07272 2.18828 2.42855C0.856291 2.77348 0 4.02224 0 5.29474C0 6.12728 0.356749 6.93594 0.998986 7.51871C0.939523 7.76848 0.903831 8.01825 0.903831 8.26793C0.903831 9.96859 2.28344 11.2412 3.87709 11.2412C4.19815 11.2412 4.50738 11.1937 4.81662 11.0866C5.35175 11.6099 6.08912 11.9429 6.89789 11.9429Z'
|
|
41
|
+
fill='currentColor'
|
|
42
|
+
/>
|
|
43
|
+
</svg>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function mdUrl() {
|
|
48
|
+
return `${window.location.origin}${window.location.pathname}.md`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function copyMd() {
|
|
52
|
+
try {
|
|
53
|
+
const res = await fetch(mdUrl());
|
|
54
|
+
const text = await res.text();
|
|
55
|
+
await navigator.clipboard.writeText(text);
|
|
56
|
+
} catch {
|
|
57
|
+
// ignore
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function OpenInAI() {
|
|
62
|
+
const onCopy = useCallback(() => {
|
|
63
|
+
void copyMd();
|
|
64
|
+
}, []);
|
|
65
|
+
const onView = useCallback(() => {
|
|
66
|
+
window.open(mdUrl(), '_blank', 'noopener,noreferrer');
|
|
67
|
+
}, []);
|
|
68
|
+
const onChatGPT = useCallback(() => {
|
|
69
|
+
const q = encodeURIComponent(`Read ${mdUrl()}`);
|
|
70
|
+
window.open(`https://chatgpt.com/?q=${q}`, '_blank', 'noopener,noreferrer');
|
|
71
|
+
}, []);
|
|
72
|
+
const onClaude = useCallback(() => {
|
|
73
|
+
const q = encodeURIComponent(`Read ${mdUrl()}`);
|
|
74
|
+
window.open(`https://claude.ai/new?q=${q}`, '_blank', 'noopener,noreferrer');
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Menu>
|
|
79
|
+
<Menu.Trigger
|
|
80
|
+
render={
|
|
81
|
+
<Button
|
|
82
|
+
size='small'
|
|
83
|
+
variant='outline'
|
|
84
|
+
color='neutral'
|
|
85
|
+
leadingIcon={<SparklesIcon width={12} height={12} />}
|
|
86
|
+
trailingIcon={<ChevronDownIcon width={12} height={12} />}
|
|
87
|
+
/>
|
|
88
|
+
}
|
|
89
|
+
>
|
|
90
|
+
Open in AI
|
|
91
|
+
</Menu.Trigger>
|
|
92
|
+
<Menu.Content>
|
|
93
|
+
<Menu.Item onClick={onCopy}>
|
|
94
|
+
<ClipboardDocumentIcon width={14} height={14} />
|
|
95
|
+
Copy as MD
|
|
96
|
+
</Menu.Item>
|
|
97
|
+
<Menu.Item onClick={onView}>
|
|
98
|
+
<DocumentTextIcon width={14} height={14} />
|
|
99
|
+
View MD
|
|
100
|
+
</Menu.Item>
|
|
101
|
+
<Menu.Item onClick={onChatGPT}>
|
|
102
|
+
<ChatGPTIcon />
|
|
103
|
+
Open in ChatGPT
|
|
104
|
+
</Menu.Item>
|
|
105
|
+
<Menu.Item onClick={onClaude}>
|
|
106
|
+
<ClaudeIcon />
|
|
107
|
+
Open in Claude
|
|
108
|
+
</Menu.Item>
|
|
109
|
+
</Menu.Content>
|
|
110
|
+
</Menu>
|
|
111
|
+
);
|
|
112
|
+
}
|