@barodoc/theme-docs 0.0.1
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/LICENSE +21 -0
- package/package.json +68 -0
- package/src/components/CodeCopy.astro +173 -0
- package/src/components/DocHeader.tsx +166 -0
- package/src/components/DocsSidebar.tsx +84 -0
- package/src/components/Header.astro +32 -0
- package/src/components/LanguageSwitcher.astro +77 -0
- package/src/components/MobileNav.astro +61 -0
- package/src/components/MobileNavSheet.tsx +73 -0
- package/src/components/Search.tsx +210 -0
- package/src/components/SearchDialog.tsx +83 -0
- package/src/components/Sidebar.astro +56 -0
- package/src/components/SidebarWrapper.tsx +24 -0
- package/src/components/TableOfContents.astro +98 -0
- package/src/components/ThemeScript.astro +11 -0
- package/src/components/ThemeToggle.tsx +57 -0
- package/src/components/api/ApiEndpoint.astro +36 -0
- package/src/components/api/ApiParam.astro +26 -0
- package/src/components/api/ApiParams.astro +16 -0
- package/src/components/api/ApiResponse.astro +35 -0
- package/src/components/index.ts +30 -0
- package/src/components/mdx/Accordion.tsx +61 -0
- package/src/components/mdx/Badge.tsx +33 -0
- package/src/components/mdx/Callout.astro +79 -0
- package/src/components/mdx/Card.astro +66 -0
- package/src/components/mdx/CardGroup.astro +18 -0
- package/src/components/mdx/CodeGroup.astro +63 -0
- package/src/components/mdx/CodeGroup.tsx +51 -0
- package/src/components/mdx/Columns.tsx +31 -0
- package/src/components/mdx/DocAccordion.tsx +87 -0
- package/src/components/mdx/DocCallout.tsx +65 -0
- package/src/components/mdx/DocCard.tsx +70 -0
- package/src/components/mdx/DocTabs.tsx +48 -0
- package/src/components/mdx/Expandable.tsx +107 -0
- package/src/components/mdx/FileTree.tsx +72 -0
- package/src/components/mdx/Frame.tsx +23 -0
- package/src/components/mdx/Icon.tsx +59 -0
- package/src/components/mdx/Mermaid.tsx +94 -0
- package/src/components/mdx/ParamField.tsx +76 -0
- package/src/components/mdx/ResponseField.tsx +62 -0
- package/src/components/mdx/Step.astro +14 -0
- package/src/components/mdx/Steps.astro +37 -0
- package/src/components/mdx/Steps.tsx +49 -0
- package/src/components/mdx/Tabs.tsx +67 -0
- package/src/components/mdx/Tooltip.tsx +36 -0
- package/src/components/ui/accordion.tsx +54 -0
- package/src/components/ui/alert.tsx +60 -0
- package/src/components/ui/button.tsx +57 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/dialog.tsx +119 -0
- package/src/components/ui/index.ts +11 -0
- package/src/components/ui/scroll-area.tsx +45 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +137 -0
- package/src/components/ui/tabs.tsx +52 -0
- package/src/components/ui/tooltip.tsx +29 -0
- package/src/index.ts +74 -0
- package/src/layouts/BaseLayout.astro +28 -0
- package/src/layouts/DocsLayout.astro +121 -0
- package/src/lib/utils.ts +6 -0
- package/src/pages/docs/[...slug].astro +116 -0
- package/src/pages/index.astro +217 -0
- package/src/styles/global.css +342 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
title?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { title = "Parameters" } = Astro.props;
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<div class="my-4 px-2">
|
|
10
|
+
<h4 class="text-sm font-semibold text-[var(--color-text)] mb-2">{title}</h4>
|
|
11
|
+
<div class="border border-[var(--color-border)] rounded-lg overflow-hidden">
|
|
12
|
+
<div class="divide-y divide-[var(--color-border)] px-4">
|
|
13
|
+
<slot />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
status: number;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { status, description } = Astro.props;
|
|
8
|
+
|
|
9
|
+
const statusColors: Record<number, string> = {
|
|
10
|
+
200: "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400",
|
|
11
|
+
201: "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400",
|
|
12
|
+
204: "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400",
|
|
13
|
+
400: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400",
|
|
14
|
+
401: "bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400",
|
|
15
|
+
403: "bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400",
|
|
16
|
+
404: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
|
|
17
|
+
500: "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const statusColor = statusColors[status] || "bg-gray-100 dark:bg-gray-900/30 text-gray-700 dark:text-gray-400";
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<div class="my-4 px-2">
|
|
24
|
+
<div class="flex items-center gap-2 mb-2">
|
|
25
|
+
<span class:list={["px-2 py-0.5 text-xs font-bold rounded", statusColor]}>
|
|
26
|
+
{status}
|
|
27
|
+
</span>
|
|
28
|
+
{description && (
|
|
29
|
+
<span class="text-sm text-[var(--color-text-secondary)]">{description}</span>
|
|
30
|
+
)}
|
|
31
|
+
</div>
|
|
32
|
+
<div class="border border-[var(--color-border)] rounded-lg overflow-hidden px-2">
|
|
33
|
+
<slot />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// UI Components - exported for custom overrides
|
|
2
|
+
export { ThemeToggle } from "./ThemeToggle.tsx";
|
|
3
|
+
export { Search } from "./Search.tsx";
|
|
4
|
+
|
|
5
|
+
// shadcn/ui components
|
|
6
|
+
export * from "./ui/index.ts";
|
|
7
|
+
|
|
8
|
+
// MDX Components (shadcn/ui based)
|
|
9
|
+
export { DocCard, DocCardGroup } from "./mdx/DocCard.tsx";
|
|
10
|
+
export { DocCallout } from "./mdx/DocCallout.tsx";
|
|
11
|
+
export { DocTabs } from "./mdx/DocTabs.tsx";
|
|
12
|
+
export { DocAccordion, SimpleAccordion } from "./mdx/DocAccordion.tsx";
|
|
13
|
+
|
|
14
|
+
// New MDX Components (Mintlify-style)
|
|
15
|
+
export { CodeGroup } from "./mdx/CodeGroup.tsx";
|
|
16
|
+
export { Badge } from "./mdx/Badge.tsx";
|
|
17
|
+
export { Frame } from "./mdx/Frame.tsx";
|
|
18
|
+
export { Columns, Column } from "./mdx/Columns.tsx";
|
|
19
|
+
export { Tooltip } from "./mdx/Tooltip.tsx";
|
|
20
|
+
export { FileTree, TreeFile, TreeFolder } from "./mdx/FileTree.tsx";
|
|
21
|
+
export { ParamField, ParamFieldGroup } from "./mdx/ParamField.tsx";
|
|
22
|
+
export { ResponseField, ResponseFieldGroup } from "./mdx/ResponseField.tsx";
|
|
23
|
+
export { Expandable, ExpandableList, ExpandableItem } from "./mdx/Expandable.tsx";
|
|
24
|
+
export { Icon, CheckIcon, XIcon, InfoIcon, WarningIcon } from "./mdx/Icon.tsx";
|
|
25
|
+
export { Steps, Step } from "./mdx/Steps.tsx";
|
|
26
|
+
export { Mermaid } from "./mdx/Mermaid.tsx";
|
|
27
|
+
|
|
28
|
+
// Legacy exports for backwards compatibility
|
|
29
|
+
export { Tabs, Tab } from "./mdx/Tabs.tsx";
|
|
30
|
+
export { Accordion, AccordionGroup } from "./mdx/Accordion.tsx";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
interface AccordionProps {
|
|
4
|
+
title: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Accordion({ title, icon, defaultOpen = false, children }: AccordionProps) {
|
|
11
|
+
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className="accordion-item border border-[var(--color-border)] rounded-xl overflow-hidden bg-[var(--color-bg)] my-3">
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
18
|
+
className="w-full flex items-center gap-3 px-5 py-4 text-left hover:bg-[var(--color-bg-secondary)] transition-colors"
|
|
19
|
+
aria-expanded={isOpen}
|
|
20
|
+
>
|
|
21
|
+
{icon && (
|
|
22
|
+
<span className="flex items-center justify-center w-8 h-8 rounded-lg bg-[var(--color-bg-secondary)] text-lg shrink-0">
|
|
23
|
+
{icon}
|
|
24
|
+
</span>
|
|
25
|
+
)}
|
|
26
|
+
<span className="flex-1 font-medium text-[var(--color-text)]">{title}</span>
|
|
27
|
+
<svg
|
|
28
|
+
className={`w-5 h-5 text-[var(--color-text-secondary)] transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`}
|
|
29
|
+
fill="none"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
viewBox="0 0 24 24"
|
|
32
|
+
>
|
|
33
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
34
|
+
</svg>
|
|
35
|
+
</button>
|
|
36
|
+
<div
|
|
37
|
+
className={`accordion-content overflow-hidden transition-all duration-200 ease-out ${
|
|
38
|
+
isOpen ? "max-h-[1000px] opacity-100" : "max-h-0 opacity-0"
|
|
39
|
+
}`}
|
|
40
|
+
>
|
|
41
|
+
<div className="px-5 pb-5 pt-1 text-sm text-[var(--color-text-secondary)] leading-relaxed">
|
|
42
|
+
{children}
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface AccordionGroupProps {
|
|
50
|
+
children: ReactNode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function AccordionGroup({ children }: AccordionGroupProps) {
|
|
54
|
+
return (
|
|
55
|
+
<div className="not-prose accordion-group space-y-2 my-6">
|
|
56
|
+
{children}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default Accordion;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
|
|
5
|
+
const badgeVariants = cva(
|
|
6
|
+
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-colors",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "bg-primary-100 text-primary-800 dark:bg-primary-900/30 dark:text-primary-300",
|
|
11
|
+
secondary: "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300",
|
|
12
|
+
success: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300",
|
|
13
|
+
warning: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300",
|
|
14
|
+
error: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300",
|
|
15
|
+
info: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300",
|
|
16
|
+
outline: "border border-[var(--color-border)] text-[var(--color-text-secondary)]",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: "default",
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export interface BadgeProps
|
|
26
|
+
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
27
|
+
VariantProps<typeof badgeVariants> {}
|
|
28
|
+
|
|
29
|
+
export function Badge({ className, variant, ...props }: BadgeProps) {
|
|
30
|
+
return (
|
|
31
|
+
<span className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
type?: "info" | "warning" | "tip" | "danger" | "note";
|
|
4
|
+
title?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { type = "info", title } = Astro.props;
|
|
8
|
+
|
|
9
|
+
const styles = {
|
|
10
|
+
info: {
|
|
11
|
+
container: "bg-blue-50/70 dark:bg-blue-950/30 border-l-blue-500",
|
|
12
|
+
iconBg: "bg-blue-100 dark:bg-blue-900/50",
|
|
13
|
+
icon: "text-blue-600 dark:text-blue-400",
|
|
14
|
+
title: "text-blue-900 dark:text-blue-100",
|
|
15
|
+
},
|
|
16
|
+
note: {
|
|
17
|
+
container: "bg-gray-50/70 dark:bg-gray-950/30 border-l-gray-400",
|
|
18
|
+
iconBg: "bg-gray-100 dark:bg-gray-900/50",
|
|
19
|
+
icon: "text-gray-600 dark:text-gray-400",
|
|
20
|
+
title: "text-gray-900 dark:text-gray-100",
|
|
21
|
+
},
|
|
22
|
+
warning: {
|
|
23
|
+
container: "bg-orange-50/70 dark:bg-orange-950/30 border-l-orange-500",
|
|
24
|
+
iconBg: "bg-orange-100 dark:bg-orange-900/50",
|
|
25
|
+
icon: "text-orange-600 dark:text-orange-400",
|
|
26
|
+
title: "text-orange-900 dark:text-orange-100",
|
|
27
|
+
},
|
|
28
|
+
tip: {
|
|
29
|
+
container: "bg-green-50/70 dark:bg-green-950/30 border-l-green-500",
|
|
30
|
+
iconBg: "bg-green-100 dark:bg-green-900/50",
|
|
31
|
+
icon: "text-green-600 dark:text-green-400",
|
|
32
|
+
title: "text-green-900 dark:text-green-100",
|
|
33
|
+
},
|
|
34
|
+
danger: {
|
|
35
|
+
container: "bg-red-50/70 dark:bg-red-950/30 border-l-red-500",
|
|
36
|
+
iconBg: "bg-red-100 dark:bg-red-900/50",
|
|
37
|
+
icon: "text-red-600 dark:text-red-400",
|
|
38
|
+
title: "text-red-900 dark:text-red-100",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const icons = {
|
|
43
|
+
info: `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>`,
|
|
44
|
+
note: `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>`,
|
|
45
|
+
warning: `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>`,
|
|
46
|
+
tip: `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path></svg>`,
|
|
47
|
+
danger: `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>`,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const defaultTitles = {
|
|
51
|
+
info: "Info",
|
|
52
|
+
note: "Note",
|
|
53
|
+
warning: "Warning",
|
|
54
|
+
tip: "Tip",
|
|
55
|
+
danger: "Danger",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const style = styles[type];
|
|
59
|
+
const icon = icons[type];
|
|
60
|
+
const displayTitle = title || defaultTitles[type];
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<div class:list={["not-prose my-4 rounded-md border-l-4 overflow-hidden", style.container]}>
|
|
64
|
+
<div class="p-3">
|
|
65
|
+
<div class="flex items-start gap-3">
|
|
66
|
+
<div class:list={["shrink-0 flex items-center justify-center w-6 h-6 rounded", style.iconBg]}>
|
|
67
|
+
<div class:list={[style.icon]} set:html={icon} />
|
|
68
|
+
</div>
|
|
69
|
+
<div class="flex-1 min-w-0">
|
|
70
|
+
{displayTitle && (
|
|
71
|
+
<p class:list={["font-semibold text-sm mb-1", style.title]}>{displayTitle}</p>
|
|
72
|
+
)}
|
|
73
|
+
<div class="text-sm text-[var(--color-text-secondary)] leading-relaxed [&>p]:m-0 [&>p+p]:mt-1">
|
|
74
|
+
<slot />
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
title: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
href?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { title, icon, href } = Astro.props;
|
|
9
|
+
|
|
10
|
+
const Tag = href ? "a" : "div";
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<Tag
|
|
14
|
+
href={href}
|
|
15
|
+
class:list={[
|
|
16
|
+
"card-component not-prose group block p-4 rounded-lg border border-[var(--color-border)] bg-[var(--color-bg)] no-underline",
|
|
17
|
+
href && "cursor-pointer hover:border-primary-300 dark:hover:border-primary-600 hover:shadow-md transition-all duration-200"
|
|
18
|
+
]}
|
|
19
|
+
style={href ? "cursor: pointer;" : ""}
|
|
20
|
+
>
|
|
21
|
+
<div class="flex flex-col gap-3">
|
|
22
|
+
{icon && (
|
|
23
|
+
<div class="flex items-center justify-center w-10 h-10 rounded-lg bg-[var(--color-bg-secondary)] group-hover:bg-primary-50 dark:group-hover:bg-primary-950/50 transition-colors">
|
|
24
|
+
<span class="text-xl">{icon}</span>
|
|
25
|
+
</div>
|
|
26
|
+
)}
|
|
27
|
+
<div class="flex-1 min-w-0">
|
|
28
|
+
<div class="flex items-center gap-2">
|
|
29
|
+
<h3 class="font-semibold text-[var(--color-text)] group-hover:text-primary-700 dark:group-hover:text-primary-300 transition-colors">{title}</h3>
|
|
30
|
+
{href && (
|
|
31
|
+
<svg class="w-4 h-4 text-[var(--color-text-muted)] opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
32
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
|
33
|
+
</svg>
|
|
34
|
+
)}
|
|
35
|
+
</div>
|
|
36
|
+
<div class="mt-1 text-sm text-[var(--color-text-secondary)] group-hover:text-[var(--color-text)] leading-relaxed transition-colors">
|
|
37
|
+
<slot />
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</Tag>
|
|
42
|
+
|
|
43
|
+
<style>
|
|
44
|
+
.card-component {
|
|
45
|
+
position: relative;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.card-component::before {
|
|
50
|
+
content: '';
|
|
51
|
+
position: absolute;
|
|
52
|
+
inset: 0;
|
|
53
|
+
background: linear-gradient(135deg, var(--color-primary-50) 0%, transparent 50%);
|
|
54
|
+
opacity: 0;
|
|
55
|
+
transition: opacity 200ms ease-out;
|
|
56
|
+
pointer-events: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:global(.dark) .card-component::before {
|
|
60
|
+
background: linear-gradient(135deg, var(--color-primary-950) 0%, transparent 50%);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.card-component:hover::before {
|
|
64
|
+
opacity: 0.5;
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
cols?: 1 | 2 | 3 | 4;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { cols = 2 } = Astro.props;
|
|
7
|
+
|
|
8
|
+
const gridCols: Record<number, string> = {
|
|
9
|
+
1: "grid-cols-1",
|
|
10
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
11
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
12
|
+
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
|
|
13
|
+
};
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<div class:list={["not-prose grid gap-5 my-6", gridCols[cols]]}>
|
|
17
|
+
<slot />
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
// CodeGroup component for tabbed code blocks
|
|
3
|
+
interface Props {
|
|
4
|
+
titles?: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { titles = [] } = Astro.props;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<div class="not-prose my-4 code-group" data-titles={JSON.stringify(titles)}>
|
|
11
|
+
<div class="code-group-tabs flex border-b border-[var(--color-border)] bg-[var(--color-bg-secondary)] rounded-t-lg"></div>
|
|
12
|
+
<div class="code-group-content">
|
|
13
|
+
<slot />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
function initCodeGroups() {
|
|
19
|
+
document.querySelectorAll('.code-group').forEach((group) => {
|
|
20
|
+
const tabsContainer = group.querySelector('.code-group-tabs');
|
|
21
|
+
const contentContainer = group.querySelector('.code-group-content');
|
|
22
|
+
const titles = JSON.parse(group.getAttribute('data-titles') || '[]');
|
|
23
|
+
const codeBlocks = contentContainer?.querySelectorAll('pre');
|
|
24
|
+
|
|
25
|
+
if (!tabsContainer || !contentContainer || !codeBlocks?.length) return;
|
|
26
|
+
|
|
27
|
+
// Create tabs
|
|
28
|
+
codeBlocks.forEach((block, index) => {
|
|
29
|
+
const tab = document.createElement('button');
|
|
30
|
+
tab.className = 'px-4 py-2 text-sm font-medium transition-colors text-[var(--color-text-secondary)] hover:text-[var(--color-text)]';
|
|
31
|
+
tab.textContent = titles[index] || `Tab ${index + 1}`;
|
|
32
|
+
tab.addEventListener('click', () => {
|
|
33
|
+
// Update tabs
|
|
34
|
+
tabsContainer.querySelectorAll('button').forEach((t, i) => {
|
|
35
|
+
if (i === index) {
|
|
36
|
+
t.classList.add('border-b-2', 'border-primary-600', 'text-primary-600');
|
|
37
|
+
t.classList.remove('text-[var(--color-text-secondary)]');
|
|
38
|
+
} else {
|
|
39
|
+
t.classList.remove('border-b-2', 'border-primary-600', 'text-primary-600');
|
|
40
|
+
t.classList.add('text-[var(--color-text-secondary)]');
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// Update content
|
|
44
|
+
codeBlocks.forEach((b, i) => {
|
|
45
|
+
(b as HTMLElement).style.display = i === index ? 'block' : 'none';
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
tabsContainer.appendChild(tab);
|
|
49
|
+
|
|
50
|
+
// Hide all but first
|
|
51
|
+
if (index === 0) {
|
|
52
|
+
tab.classList.add('border-b-2', 'border-primary-600', 'text-primary-600');
|
|
53
|
+
tab.classList.remove('text-[var(--color-text-secondary)]');
|
|
54
|
+
} else {
|
|
55
|
+
(block as HTMLElement).style.display = 'none';
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
initCodeGroups();
|
|
62
|
+
document.addEventListener('astro:page-load', initCodeGroups);
|
|
63
|
+
</script>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
interface CodeGroupProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
titles?: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function CodeGroup({ children, titles = [] }: CodeGroupProps) {
|
|
9
|
+
const [activeIndex, setActiveIndex] = React.useState(0);
|
|
10
|
+
|
|
11
|
+
// Extract code blocks from children
|
|
12
|
+
const codeBlocks = React.Children.toArray(children);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="not-prose my-4 rounded-lg border border-[var(--color-border)] overflow-hidden">
|
|
16
|
+
{/* Tabs */}
|
|
17
|
+
<div className="flex bg-[var(--color-bg-tertiary)] border-b border-[var(--color-border)]">
|
|
18
|
+
{codeBlocks.map((_, index) => {
|
|
19
|
+
const isActive = activeIndex === index;
|
|
20
|
+
const title = titles[index] || `Tab ${index + 1}`;
|
|
21
|
+
return (
|
|
22
|
+
<button
|
|
23
|
+
key={index}
|
|
24
|
+
type="button"
|
|
25
|
+
onClick={() => setActiveIndex(index)}
|
|
26
|
+
className={`px-4 py-2 text-sm font-medium transition-colors ${
|
|
27
|
+
isActive
|
|
28
|
+
? "bg-[var(--color-bg-secondary)] text-[var(--color-text)] border-b-2 border-primary-500 -mb-px"
|
|
29
|
+
: "text-[var(--color-text-muted)] hover:text-[var(--color-text)]"
|
|
30
|
+
}`}
|
|
31
|
+
>
|
|
32
|
+
{title}
|
|
33
|
+
</button>
|
|
34
|
+
);
|
|
35
|
+
})}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
{/* Content */}
|
|
39
|
+
<div className="bg-[var(--color-bg-secondary)]">
|
|
40
|
+
{codeBlocks.map((block, index) => (
|
|
41
|
+
<div
|
|
42
|
+
key={index}
|
|
43
|
+
style={{ display: activeIndex === index ? "block" : "none" }}
|
|
44
|
+
>
|
|
45
|
+
{block}
|
|
46
|
+
</div>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
|
|
4
|
+
interface ColumnsProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
columns?: 2 | 3 | 4;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Columns({ children, columns = 2, className }: ColumnsProps) {
|
|
11
|
+
const gridCols = {
|
|
12
|
+
2: "grid-cols-1 md:grid-cols-2",
|
|
13
|
+
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
14
|
+
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className={cn("not-prose grid gap-4 my-4", gridCols[columns], className)}>
|
|
19
|
+
{children}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ColumnProps {
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Column({ children, className }: ColumnProps) {
|
|
30
|
+
return <div className={cn("", className)}>{children}</div>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Accordion,
|
|
4
|
+
AccordionContent,
|
|
5
|
+
AccordionItem,
|
|
6
|
+
AccordionTrigger,
|
|
7
|
+
} from "../ui/accordion";
|
|
8
|
+
import { cn } from "../../lib/utils";
|
|
9
|
+
|
|
10
|
+
// Accordion item structure
|
|
11
|
+
interface AccordionItemData {
|
|
12
|
+
title: string;
|
|
13
|
+
content: React.ReactNode;
|
|
14
|
+
icon?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface DocAccordionProps {
|
|
18
|
+
items: AccordionItemData[];
|
|
19
|
+
type?: "single" | "multiple";
|
|
20
|
+
collapsible?: boolean;
|
|
21
|
+
defaultValue?: string | string[];
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function DocAccordion({
|
|
26
|
+
items,
|
|
27
|
+
type = "single",
|
|
28
|
+
collapsible = true,
|
|
29
|
+
defaultValue,
|
|
30
|
+
className
|
|
31
|
+
}: DocAccordionProps) {
|
|
32
|
+
const renderItems = () =>
|
|
33
|
+
items.map((item, index) => {
|
|
34
|
+
const value = `item-${index}`;
|
|
35
|
+
return (
|
|
36
|
+
<AccordionItem
|
|
37
|
+
key={value}
|
|
38
|
+
value={value}
|
|
39
|
+
className="border-b border-[var(--color-border)] last:border-b-0"
|
|
40
|
+
>
|
|
41
|
+
<div className="flex items-start gap-3 px-4">
|
|
42
|
+
{item.icon && (
|
|
43
|
+
<span className="flex items-center justify-center w-8 h-8 rounded-lg bg-[var(--color-bg-secondary)] text-lg shrink-0 mt-3">
|
|
44
|
+
{item.icon}
|
|
45
|
+
</span>
|
|
46
|
+
)}
|
|
47
|
+
<div className="flex-1">
|
|
48
|
+
<AccordionTrigger className="text-left">
|
|
49
|
+
{item.title}
|
|
50
|
+
</AccordionTrigger>
|
|
51
|
+
<AccordionContent className="text-[var(--color-text-secondary)]">
|
|
52
|
+
{item.content}
|
|
53
|
+
</AccordionContent>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</AccordionItem>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (type === "single") {
|
|
61
|
+
return (
|
|
62
|
+
<Accordion
|
|
63
|
+
type="single"
|
|
64
|
+
collapsible={collapsible}
|
|
65
|
+
defaultValue={defaultValue as string}
|
|
66
|
+
className={cn("not-prose my-6 rounded-xl border border-[var(--color-border)] overflow-hidden", className)}
|
|
67
|
+
>
|
|
68
|
+
{renderItems()}
|
|
69
|
+
</Accordion>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Accordion
|
|
75
|
+
type="multiple"
|
|
76
|
+
defaultValue={defaultValue as string[]}
|
|
77
|
+
className={cn("not-prose my-6 rounded-xl border border-[var(--color-border)] overflow-hidden", className)}
|
|
78
|
+
>
|
|
79
|
+
{renderItems()}
|
|
80
|
+
</Accordion>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Alias for backwards compatibility
|
|
85
|
+
export const SimpleAccordion = DocAccordion;
|
|
86
|
+
|
|
87
|
+
export default DocAccordion;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Alert, AlertTitle, AlertDescription } from "../ui/alert";
|
|
3
|
+
import { Info, AlertTriangle, Lightbulb, AlertCircle, FileText } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
|
|
6
|
+
type CalloutType = "info" | "warning" | "tip" | "danger" | "note";
|
|
7
|
+
|
|
8
|
+
interface DocCalloutProps {
|
|
9
|
+
type?: CalloutType;
|
|
10
|
+
title?: string;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const variantMap: Record<CalloutType, "info" | "warning" | "success" | "destructive" | "default"> = {
|
|
15
|
+
info: "info",
|
|
16
|
+
warning: "warning",
|
|
17
|
+
tip: "success",
|
|
18
|
+
danger: "destructive",
|
|
19
|
+
note: "default",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const iconMap: Record<CalloutType, React.ReactNode> = {
|
|
23
|
+
info: <Info className="h-4 w-4" />,
|
|
24
|
+
warning: <AlertTriangle className="h-4 w-4" />,
|
|
25
|
+
tip: <Lightbulb className="h-4 w-4" />,
|
|
26
|
+
danger: <AlertCircle className="h-4 w-4" />,
|
|
27
|
+
note: <FileText className="h-4 w-4" />,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const defaultTitles: Record<CalloutType, string> = {
|
|
31
|
+
info: "Info",
|
|
32
|
+
warning: "Warning",
|
|
33
|
+
tip: "Tip",
|
|
34
|
+
danger: "Danger",
|
|
35
|
+
note: "Note",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function DocCallout({ type = "info", title, children }: DocCalloutProps) {
|
|
39
|
+
const displayTitle = title || defaultTitles[type];
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Alert variant={variantMap[type]} className="not-prose my-6">
|
|
43
|
+
<div className="flex items-start gap-4">
|
|
44
|
+
<div className={cn(
|
|
45
|
+
"flex items-center justify-center w-8 h-8 rounded-lg shrink-0",
|
|
46
|
+
type === "info" && "bg-blue-100 dark:bg-blue-900/50 text-blue-600 dark:text-blue-400",
|
|
47
|
+
type === "warning" && "bg-orange-100 dark:bg-orange-900/50 text-orange-600 dark:text-orange-400",
|
|
48
|
+
type === "tip" && "bg-green-100 dark:bg-green-900/50 text-green-600 dark:text-green-400",
|
|
49
|
+
type === "danger" && "bg-red-100 dark:bg-red-900/50 text-red-600 dark:text-red-400",
|
|
50
|
+
type === "note" && "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400",
|
|
51
|
+
)}>
|
|
52
|
+
{iconMap[type]}
|
|
53
|
+
</div>
|
|
54
|
+
<div className="flex-1 pt-0.5">
|
|
55
|
+
<AlertTitle className="text-sm font-semibold mb-1">{displayTitle}</AlertTitle>
|
|
56
|
+
<AlertDescription className="text-sm leading-relaxed [&>p]:m-0 [&>p+p]:mt-2">
|
|
57
|
+
{children}
|
|
58
|
+
</AlertDescription>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</Alert>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default DocCallout;
|