@raystack/chronicle 0.1.0-canary.e11f924
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/bin/chronicle.js +2 -0
- package/dist/cli/index.js +9788 -0
- package/next.config.mjs +10 -0
- package/package.json +62 -0
- package/source.config.ts +50 -0
- package/src/app/[[...slug]]/layout.tsx +15 -0
- package/src/app/[[...slug]]/page.tsx +57 -0
- package/src/app/api/apis-proxy/route.ts +59 -0
- package/src/app/api/health/route.ts +3 -0
- package/src/app/api/search/route.ts +90 -0
- package/src/app/apis/[[...slug]]/layout.module.css +22 -0
- package/src/app/apis/[[...slug]]/layout.tsx +26 -0
- package/src/app/apis/[[...slug]]/page.tsx +57 -0
- package/src/app/layout.tsx +26 -0
- package/src/app/llms-full.txt/route.ts +18 -0
- package/src/app/llms.txt/route.ts +15 -0
- package/src/app/providers.tsx +8 -0
- package/src/cli/commands/build.ts +33 -0
- package/src/cli/commands/dev.ts +34 -0
- package/src/cli/commands/init.ts +58 -0
- package/src/cli/commands/serve.ts +54 -0
- package/src/cli/commands/start.ts +34 -0
- package/src/cli/index.ts +21 -0
- package/src/cli/utils/config.ts +43 -0
- package/src/cli/utils/index.ts +2 -0
- package/src/cli/utils/process.ts +7 -0
- package/src/components/api/code-snippets.module.css +7 -0
- package/src/components/api/code-snippets.tsx +76 -0
- package/src/components/api/endpoint-page.module.css +58 -0
- package/src/components/api/endpoint-page.tsx +283 -0
- package/src/components/api/field-row.module.css +126 -0
- package/src/components/api/field-row.tsx +204 -0
- package/src/components/api/field-section.module.css +24 -0
- package/src/components/api/field-section.tsx +100 -0
- package/src/components/api/index.ts +8 -0
- package/src/components/api/json-editor.module.css +9 -0
- package/src/components/api/json-editor.tsx +61 -0
- package/src/components/api/key-value-editor.module.css +13 -0
- package/src/components/api/key-value-editor.tsx +62 -0
- package/src/components/api/method-badge.module.css +4 -0
- package/src/components/api/method-badge.tsx +29 -0
- package/src/components/api/response-panel.module.css +8 -0
- package/src/components/api/response-panel.tsx +44 -0
- package/src/components/common/breadcrumb.tsx +3 -0
- package/src/components/common/button.tsx +3 -0
- package/src/components/common/callout.module.css +7 -0
- package/src/components/common/callout.tsx +27 -0
- package/src/components/common/code-block.tsx +3 -0
- package/src/components/common/dialog.tsx +3 -0
- package/src/components/common/index.ts +10 -0
- package/src/components/common/input-field.tsx +3 -0
- package/src/components/common/sidebar.tsx +3 -0
- package/src/components/common/switch.tsx +3 -0
- package/src/components/common/table.tsx +3 -0
- package/src/components/common/tabs.tsx +3 -0
- package/src/components/mdx/code.module.css +42 -0
- package/src/components/mdx/code.tsx +27 -0
- package/src/components/mdx/details.module.css +37 -0
- package/src/components/mdx/details.tsx +18 -0
- package/src/components/mdx/image.tsx +38 -0
- package/src/components/mdx/index.tsx +35 -0
- package/src/components/mdx/link.tsx +38 -0
- package/src/components/mdx/mermaid.module.css +9 -0
- package/src/components/mdx/mermaid.tsx +37 -0
- package/src/components/mdx/paragraph.module.css +8 -0
- package/src/components/mdx/paragraph.tsx +19 -0
- package/src/components/mdx/table.tsx +40 -0
- package/src/components/ui/breadcrumbs.tsx +72 -0
- package/src/components/ui/client-theme-switcher.tsx +18 -0
- package/src/components/ui/footer.module.css +27 -0
- package/src/components/ui/footer.tsx +30 -0
- package/src/components/ui/search.module.css +104 -0
- package/src/components/ui/search.tsx +202 -0
- package/src/lib/api-routes.ts +120 -0
- package/src/lib/config.ts +47 -0
- package/src/lib/get-llm-text.ts +10 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/openapi.ts +188 -0
- package/src/lib/remark-unused-directives.ts +30 -0
- package/src/lib/schema.ts +99 -0
- package/src/lib/snippet-generators.ts +87 -0
- package/src/lib/source.ts +67 -0
- package/src/themes/default/Layout.module.css +81 -0
- package/src/themes/default/Layout.tsx +133 -0
- package/src/themes/default/Page.module.css +46 -0
- package/src/themes/default/Page.tsx +21 -0
- package/src/themes/default/Toc.module.css +48 -0
- package/src/themes/default/Toc.tsx +66 -0
- package/src/themes/default/font.ts +6 -0
- package/src/themes/default/index.ts +13 -0
- package/src/themes/paper/ChapterNav.module.css +71 -0
- package/src/themes/paper/ChapterNav.tsx +96 -0
- package/src/themes/paper/Layout.module.css +33 -0
- package/src/themes/paper/Layout.tsx +25 -0
- package/src/themes/paper/Page.module.css +174 -0
- package/src/themes/paper/Page.tsx +107 -0
- package/src/themes/paper/ReadingProgress.module.css +132 -0
- package/src/themes/paper/ReadingProgress.tsx +294 -0
- package/src/themes/paper/index.ts +8 -0
- package/src/themes/registry.ts +14 -0
- package/src/types/config.ts +69 -0
- package/src/types/content.ts +35 -0
- package/src/types/index.ts +3 -0
- package/src/types/theme.ts +22 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { CodeBlock } from '@raystack/apsara'
|
|
4
|
+
import styles from './response-panel.module.css'
|
|
5
|
+
|
|
6
|
+
interface ResponsePanelProps {
|
|
7
|
+
responses: {
|
|
8
|
+
status: string
|
|
9
|
+
description?: string
|
|
10
|
+
jsonExample?: string
|
|
11
|
+
}[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ResponsePanel({ responses }: ResponsePanelProps) {
|
|
15
|
+
const withExamples = responses.filter((r) => r.jsonExample)
|
|
16
|
+
if (withExamples.length === 0) return null
|
|
17
|
+
|
|
18
|
+
const defaultValue = withExamples[0].status
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<CodeBlock defaultValue={defaultValue} className={styles.panel}>
|
|
22
|
+
<CodeBlock.Header>
|
|
23
|
+
<CodeBlock.LanguageSelect>
|
|
24
|
+
<CodeBlock.LanguageSelectTrigger />
|
|
25
|
+
<CodeBlock.LanguageSelectContent>
|
|
26
|
+
{withExamples.map((resp) => (
|
|
27
|
+
<CodeBlock.LanguageSelectItem key={resp.status} value={resp.status}>
|
|
28
|
+
{resp.status} {resp.description ?? resp.status}
|
|
29
|
+
</CodeBlock.LanguageSelectItem>
|
|
30
|
+
))}
|
|
31
|
+
</CodeBlock.LanguageSelectContent>
|
|
32
|
+
</CodeBlock.LanguageSelect>
|
|
33
|
+
<CodeBlock.CopyButton />
|
|
34
|
+
</CodeBlock.Header>
|
|
35
|
+
<CodeBlock.Content>
|
|
36
|
+
{withExamples.map((resp) => (
|
|
37
|
+
<CodeBlock.Code key={resp.status} value={resp.status} language="json">
|
|
38
|
+
{resp.jsonExample!}
|
|
39
|
+
</CodeBlock.Code>
|
|
40
|
+
))}
|
|
41
|
+
</CodeBlock.Content>
|
|
42
|
+
</CodeBlock>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Callout } from '@raystack/apsara'
|
|
5
|
+
import styles from './callout.module.css'
|
|
6
|
+
|
|
7
|
+
function CalloutContainer(props: React.ComponentProps<typeof Callout>) {
|
|
8
|
+
return <Callout outline width="100%" className={styles.callout} {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function CalloutTitle({ children }: { children: React.ReactNode }) {
|
|
12
|
+
return <strong>{children}</strong>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function CalloutDescription({ children }: { children: React.ReactNode }) {
|
|
16
|
+
return <>{children}</>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function MdxBlockquote(props: React.ComponentProps<'blockquote'>) {
|
|
20
|
+
return (
|
|
21
|
+
<Callout type="grey" outline width="100%" className={styles.callout}>
|
|
22
|
+
{props.children}
|
|
23
|
+
</Callout>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Callout, CalloutContainer, CalloutTitle, CalloutDescription, MdxBlockquote }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Sidebar } from './sidebar'
|
|
2
|
+
export { Table } from './table'
|
|
3
|
+
export { Dialog } from './dialog'
|
|
4
|
+
export { InputField } from './input-field'
|
|
5
|
+
export { Tabs } from './tabs'
|
|
6
|
+
export { Breadcrumb } from './breadcrumb'
|
|
7
|
+
export { Button } from './button'
|
|
8
|
+
export { CodeBlock } from './code-block'
|
|
9
|
+
export { Callout } from './callout'
|
|
10
|
+
export { Switch } from './switch'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.codeBlock {
|
|
2
|
+
border-radius: var(--rs-radius-2);
|
|
3
|
+
overflow: hidden;
|
|
4
|
+
margin: var(--rs-space-5) 0;
|
|
5
|
+
border: 1px solid var(--rs-color-border-base-primary);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.codeHeader {
|
|
9
|
+
padding: var(--rs-space-3) var(--rs-space-4);
|
|
10
|
+
background: var(--rs-color-background-base-secondary);
|
|
11
|
+
border-bottom: 1px solid var(--rs-color-border-base-primary);
|
|
12
|
+
font-size: var(--rs-font-size-mini);
|
|
13
|
+
color: var(--rs-color-text-base-secondary);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.pre {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: var(--rs-space-4);
|
|
19
|
+
overflow-x: auto;
|
|
20
|
+
background: var(--rs-color-background-base-primary);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.pre code {
|
|
24
|
+
font-family: var(--rs-font-mono);
|
|
25
|
+
font-size: var(--rs-font-size-small);
|
|
26
|
+
line-height: 1.6;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.pre code span {
|
|
30
|
+
color: var(--shiki-light);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:global([data-theme=dark]) .pre code span {
|
|
34
|
+
color: var(--shiki-dark);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.inlineCode {
|
|
38
|
+
background: var(--rs-color-background-neutral-secondary);
|
|
39
|
+
padding: var(--rs-space-1) var(--rs-space-2);
|
|
40
|
+
border-radius: var(--rs-radius-1);
|
|
41
|
+
font-size: inherit;
|
|
42
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { ComponentProps } from 'react'
|
|
4
|
+
import styles from './code.module.css'
|
|
5
|
+
|
|
6
|
+
type PreProps = ComponentProps<'pre'> & {
|
|
7
|
+
'data-language'?: string
|
|
8
|
+
title?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function MdxCode({ children, className, ...props }: ComponentProps<'code'>) {
|
|
12
|
+
if (className || (typeof children === 'object')) {
|
|
13
|
+
return <code className={className} {...props}>{children}</code>
|
|
14
|
+
}
|
|
15
|
+
return <code className={styles.inlineCode} {...props}>{children}</code>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function MdxPre({ children, title, className, ...props }: PreProps) {
|
|
19
|
+
return (
|
|
20
|
+
<div className={styles.codeBlock}>
|
|
21
|
+
{title && <div className={styles.codeHeader}>{title}</div>}
|
|
22
|
+
<pre className={`${styles.pre} ${className ?? ''}`} {...props}>
|
|
23
|
+
{children}
|
|
24
|
+
</pre>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.details {
|
|
2
|
+
border: 1px solid var(--rs-color-border-base-primary);
|
|
3
|
+
border-radius: var(--rs-radius-2);
|
|
4
|
+
margin: var(--rs-space-5) 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.summary {
|
|
8
|
+
padding: var(--rs-space-4) var(--rs-space-5);
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
font-weight: 500;
|
|
11
|
+
font-size: var(--rs-font-size-small);
|
|
12
|
+
color: var(--rs-color-text-base-primary);
|
|
13
|
+
background: var(--rs-color-background-base-secondary);
|
|
14
|
+
list-style: none;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: var(--rs-space-3);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.summary::-webkit-details-marker {
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.summary::before {
|
|
25
|
+
content: '▶';
|
|
26
|
+
font-size: 10px;
|
|
27
|
+
transition: transform 0.2s ease;
|
|
28
|
+
color: var(--rs-color-text-base-secondary);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.details[open] > .summary::before {
|
|
32
|
+
transform: rotate(90deg);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.content {
|
|
36
|
+
padding: var(--rs-space-4) var(--rs-space-5);
|
|
37
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react'
|
|
2
|
+
import styles from './details.module.css'
|
|
3
|
+
|
|
4
|
+
export function MdxDetails({ children, className, ...props }: ComponentProps<'details'>) {
|
|
5
|
+
return (
|
|
6
|
+
<details className={`${styles.details} ${className ?? ''}`} {...props}>
|
|
7
|
+
{children}
|
|
8
|
+
</details>
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function MdxSummary({ children, className, ...props }: ComponentProps<'summary'>) {
|
|
13
|
+
return (
|
|
14
|
+
<summary className={`${styles.summary} ${className ?? ''}`} {...props}>
|
|
15
|
+
{children}
|
|
16
|
+
</summary>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import NextImage from 'next/image'
|
|
4
|
+
import type { ComponentProps } from 'react'
|
|
5
|
+
|
|
6
|
+
type ImageProps = Omit<ComponentProps<'img'>, 'src'> & {
|
|
7
|
+
src?: string
|
|
8
|
+
width?: number | string
|
|
9
|
+
height?: number | string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Image({ src, alt, width, height, ...props }: ImageProps) {
|
|
13
|
+
if (!src || typeof src !== 'string') return null
|
|
14
|
+
|
|
15
|
+
const isExternal = src.startsWith('http://') || src.startsWith('https://')
|
|
16
|
+
|
|
17
|
+
if (isExternal) {
|
|
18
|
+
return (
|
|
19
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
20
|
+
<img
|
|
21
|
+
src={src}
|
|
22
|
+
alt={alt ?? ''}
|
|
23
|
+
width={width}
|
|
24
|
+
height={height}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<NextImage
|
|
32
|
+
src={src}
|
|
33
|
+
alt={alt ?? ''}
|
|
34
|
+
width={typeof width === 'string' ? parseInt(width, 10) : (width ?? 800)}
|
|
35
|
+
height={typeof height === 'string' ? parseInt(height, 10) : (height ?? 400)}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MDXComponents } from 'mdx/types'
|
|
2
|
+
import { Image } from './image'
|
|
3
|
+
import { Link } from './link'
|
|
4
|
+
import { MdxTable, MdxThead, MdxTbody, MdxTr, MdxTh, MdxTd } from './table'
|
|
5
|
+
import { MdxPre, MdxCode } from './code'
|
|
6
|
+
import { MdxDetails, MdxSummary } from './details'
|
|
7
|
+
import { Mermaid } from './mermaid'
|
|
8
|
+
import { MdxParagraph } from './paragraph'
|
|
9
|
+
import { CalloutContainer, CalloutTitle, CalloutDescription, MdxBlockquote } from '@/components/common/callout'
|
|
10
|
+
import { Tabs } from '@raystack/apsara'
|
|
11
|
+
|
|
12
|
+
export const mdxComponents: MDXComponents = {
|
|
13
|
+
p: MdxParagraph,
|
|
14
|
+
img: Image,
|
|
15
|
+
a: Link,
|
|
16
|
+
table: MdxTable,
|
|
17
|
+
thead: MdxThead,
|
|
18
|
+
tbody: MdxTbody,
|
|
19
|
+
tr: MdxTr,
|
|
20
|
+
th: MdxTh,
|
|
21
|
+
td: MdxTd,
|
|
22
|
+
code: MdxCode,
|
|
23
|
+
pre: MdxPre,
|
|
24
|
+
details: MdxDetails,
|
|
25
|
+
summary: MdxSummary,
|
|
26
|
+
blockquote: MdxBlockquote,
|
|
27
|
+
Callout: CalloutContainer,
|
|
28
|
+
CalloutTitle,
|
|
29
|
+
CalloutDescription,
|
|
30
|
+
Tabs,
|
|
31
|
+
Mermaid,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { Image } from './image'
|
|
35
|
+
export { Link } from './link'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import NextLink from 'next/link'
|
|
4
|
+
import { Link as ApsaraLink } from '@raystack/apsara'
|
|
5
|
+
import type { ComponentProps } from 'react'
|
|
6
|
+
|
|
7
|
+
type LinkProps = ComponentProps<'a'>
|
|
8
|
+
|
|
9
|
+
export function Link({ href, children, ...props }: LinkProps) {
|
|
10
|
+
if (!href) {
|
|
11
|
+
return <span {...props}>{children}</span>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const isExternal = href.startsWith('http://') || href.startsWith('https://')
|
|
15
|
+
const isAnchor = href.startsWith('#')
|
|
16
|
+
|
|
17
|
+
if (isAnchor) {
|
|
18
|
+
return (
|
|
19
|
+
<ApsaraLink href={href} {...props}>
|
|
20
|
+
{children}
|
|
21
|
+
</ApsaraLink>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (isExternal) {
|
|
26
|
+
return (
|
|
27
|
+
<ApsaraLink href={href} target="_blank" rel="noopener noreferrer" {...props}>
|
|
28
|
+
{children}
|
|
29
|
+
</ApsaraLink>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<NextLink href={href} className={props.className}>
|
|
35
|
+
{children}
|
|
36
|
+
</NextLink>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useId, useState } from 'react'
|
|
4
|
+
import styles from './mermaid.module.css'
|
|
5
|
+
|
|
6
|
+
interface MermaidProps {
|
|
7
|
+
chart: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Mermaid({ chart }: MermaidProps) {
|
|
11
|
+
const mermaidId = useId().replace(/:/g, '-')
|
|
12
|
+
const [svg, setSvg] = useState<string>('')
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
let cancelled = false
|
|
16
|
+
|
|
17
|
+
async function render() {
|
|
18
|
+
const { default: mermaid } = await import('mermaid')
|
|
19
|
+
mermaid.initialize({ startOnLoad: false, theme: 'default' })
|
|
20
|
+
const { svg: rendered } = await mermaid.render(
|
|
21
|
+
mermaidId,
|
|
22
|
+
chart
|
|
23
|
+
)
|
|
24
|
+
if (!cancelled) setSvg(rendered)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render()
|
|
28
|
+
return () => { cancelled = true }
|
|
29
|
+
}, [chart])
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={styles.mermaid}
|
|
34
|
+
dangerouslySetInnerHTML={{ __html: svg }}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Children, isValidElement, type ComponentProps } from 'react'
|
|
2
|
+
import styles from './paragraph.module.css'
|
|
3
|
+
|
|
4
|
+
const BLOCK_ELEMENTS = new Set(['summary', 'details', 'div', 'table', 'ul', 'ol'])
|
|
5
|
+
|
|
6
|
+
function hasBlockChild(children: React.ReactNode): boolean {
|
|
7
|
+
return Children.toArray(children).some(
|
|
8
|
+
(child) => isValidElement(child) && typeof child.type === 'string' && BLOCK_ELEMENTS.has(child.type)
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function MdxParagraph({ children, className, ...props }: ComponentProps<'p'>) {
|
|
13
|
+
const Tag = hasBlockChild(children) ? 'div' : 'p'
|
|
14
|
+
return (
|
|
15
|
+
<Tag className={`${styles.paragraph} ${className ?? ''}`} {...props}>
|
|
16
|
+
{children}
|
|
17
|
+
</Tag>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Table } from '@raystack/apsara'
|
|
4
|
+
import type { ComponentProps, ReactNode } from 'react'
|
|
5
|
+
|
|
6
|
+
type TableProps = ComponentProps<'table'>
|
|
7
|
+
|
|
8
|
+
export function MdxTable({ children, ...props }: TableProps) {
|
|
9
|
+
return <Table {...props}>{children}</Table>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type TheadProps = ComponentProps<'thead'>
|
|
13
|
+
|
|
14
|
+
export function MdxThead({ children, ...props }: TheadProps) {
|
|
15
|
+
return <Table.Header {...props}>{children}</Table.Header>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type TbodyProps = ComponentProps<'tbody'>
|
|
19
|
+
|
|
20
|
+
export function MdxTbody({ children, ...props }: TbodyProps) {
|
|
21
|
+
return <Table.Body {...props}>{children}</Table.Body>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type TrProps = ComponentProps<'tr'>
|
|
25
|
+
|
|
26
|
+
export function MdxTr({ children, ...props }: TrProps) {
|
|
27
|
+
return <Table.Row {...props}>{children}</Table.Row>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ThProps = ComponentProps<'th'>
|
|
31
|
+
|
|
32
|
+
export function MdxTh({ children, ...props }: ThProps) {
|
|
33
|
+
return <Table.Head {...props}>{children}</Table.Head>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type TdProps = ComponentProps<'td'>
|
|
37
|
+
|
|
38
|
+
export function MdxTd({ children, ...props }: TdProps) {
|
|
39
|
+
return <Table.Cell {...props}>{children}</Table.Cell>
|
|
40
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Breadcrumb } from '@raystack/apsara'
|
|
4
|
+
import type { PageTree, PageTreeItem } from '@/types'
|
|
5
|
+
|
|
6
|
+
interface BreadcrumbsProps {
|
|
7
|
+
slug: string[]
|
|
8
|
+
tree: PageTree
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function findInTree(items: PageTreeItem[], targetPath: string): PageTreeItem | undefined {
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
const itemUrl = item.url || `/${item.name.toLowerCase().replace(/\s+/g, '-')}`
|
|
14
|
+
if (itemUrl === targetPath || itemUrl === `/${targetPath}`) {
|
|
15
|
+
return item
|
|
16
|
+
}
|
|
17
|
+
if (item.children) {
|
|
18
|
+
const found = findInTree(item.children, targetPath)
|
|
19
|
+
if (found) return found
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getFirstPageUrl(item: PageTreeItem): string | undefined {
|
|
26
|
+
if (item.type === 'page' && item.url) {
|
|
27
|
+
return item.url
|
|
28
|
+
}
|
|
29
|
+
if (item.children) {
|
|
30
|
+
for (const child of item.children) {
|
|
31
|
+
const url = getFirstPageUrl(child)
|
|
32
|
+
if (url) return url
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function Breadcrumbs({ slug, tree }: BreadcrumbsProps) {
|
|
39
|
+
const items: { label: string; href: string }[] = []
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < slug.length; i++) {
|
|
42
|
+
const currentPath = `/${slug.slice(0, i + 1).join('/')}`
|
|
43
|
+
const node = findInTree(tree.children, currentPath)
|
|
44
|
+
const href = node?.url || (node && getFirstPageUrl(node)) || currentPath
|
|
45
|
+
const label = node?.name ?? slug[i]
|
|
46
|
+
items.push({
|
|
47
|
+
label: label.charAt(0).toUpperCase() + label.slice(1),
|
|
48
|
+
href,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Breadcrumb size="small">
|
|
54
|
+
{items.flatMap((item, index) => {
|
|
55
|
+
const breadcrumbItem = (
|
|
56
|
+
<Breadcrumb.Item
|
|
57
|
+
key={`item-${index}`}
|
|
58
|
+
href={item.href}
|
|
59
|
+
current={index === items.length - 1}
|
|
60
|
+
>
|
|
61
|
+
{item.label}
|
|
62
|
+
</Breadcrumb.Item>
|
|
63
|
+
)
|
|
64
|
+
if (index === 0) return [breadcrumbItem]
|
|
65
|
+
return [
|
|
66
|
+
<Breadcrumb.Separator key={`sep-${index}`} style={{ display: 'flex' }} />,
|
|
67
|
+
breadcrumbItem,
|
|
68
|
+
]
|
|
69
|
+
})}
|
|
70
|
+
</Breadcrumb>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { ThemeSwitcher } from '@raystack/apsara'
|
|
4
|
+
import { useState, useEffect } from 'react'
|
|
5
|
+
|
|
6
|
+
interface ClientThemeSwitcherProps {
|
|
7
|
+
size?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ClientThemeSwitcher({ size }: ClientThemeSwitcherProps) {
|
|
11
|
+
const [isClient, setIsClient] = useState(false)
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setIsClient(true)
|
|
15
|
+
}, [])
|
|
16
|
+
|
|
17
|
+
return isClient ? <ThemeSwitcher size={size} /> : null
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.footer {
|
|
2
|
+
border-top: 1px solid var(--rs-color-border-base-primary);
|
|
3
|
+
padding: var(--rs-space-5) var(--rs-space-7);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.container {
|
|
7
|
+
max-width: 1200px;
|
|
8
|
+
margin: 0 auto;
|
|
9
|
+
width: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.copyright {
|
|
13
|
+
color: var(--rs-color-foreground-base-secondary);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.links {
|
|
17
|
+
flex-wrap: wrap;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.link {
|
|
21
|
+
color: var(--rs-color-foreground-base-secondary);
|
|
22
|
+
font-size: 14px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.link:hover {
|
|
26
|
+
color: var(--rs-color-foreground-base-primary);
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Flex, Link, Text } from "@raystack/apsara";
|
|
2
|
+
import type { FooterConfig } from "@/types";
|
|
3
|
+
import styles from "./footer.module.css";
|
|
4
|
+
|
|
5
|
+
interface FooterProps {
|
|
6
|
+
config?: FooterConfig;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function Footer({ config }: FooterProps) {
|
|
10
|
+
return (
|
|
11
|
+
<footer className={styles.footer}>
|
|
12
|
+
<Flex align="center" justify="between" className={styles.container}>
|
|
13
|
+
{config?.copyright && (
|
|
14
|
+
<Text size={2} className={styles.copyright}>
|
|
15
|
+
{config.copyright}
|
|
16
|
+
</Text>
|
|
17
|
+
)}
|
|
18
|
+
{config?.links && config.links.length > 0 && (
|
|
19
|
+
<Flex gap="medium" className={styles.links}>
|
|
20
|
+
{config.links.map((link) => (
|
|
21
|
+
<Link key={link.href} href={link.href} className={styles.link}>
|
|
22
|
+
{link.label}
|
|
23
|
+
</Link>
|
|
24
|
+
))}
|
|
25
|
+
</Flex>
|
|
26
|
+
)}
|
|
27
|
+
</Flex>
|
|
28
|
+
</footer>
|
|
29
|
+
);
|
|
30
|
+
}
|