@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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +68 -0
  3. package/src/components/CodeCopy.astro +173 -0
  4. package/src/components/DocHeader.tsx +166 -0
  5. package/src/components/DocsSidebar.tsx +84 -0
  6. package/src/components/Header.astro +32 -0
  7. package/src/components/LanguageSwitcher.astro +77 -0
  8. package/src/components/MobileNav.astro +61 -0
  9. package/src/components/MobileNavSheet.tsx +73 -0
  10. package/src/components/Search.tsx +210 -0
  11. package/src/components/SearchDialog.tsx +83 -0
  12. package/src/components/Sidebar.astro +56 -0
  13. package/src/components/SidebarWrapper.tsx +24 -0
  14. package/src/components/TableOfContents.astro +98 -0
  15. package/src/components/ThemeScript.astro +11 -0
  16. package/src/components/ThemeToggle.tsx +57 -0
  17. package/src/components/api/ApiEndpoint.astro +36 -0
  18. package/src/components/api/ApiParam.astro +26 -0
  19. package/src/components/api/ApiParams.astro +16 -0
  20. package/src/components/api/ApiResponse.astro +35 -0
  21. package/src/components/index.ts +30 -0
  22. package/src/components/mdx/Accordion.tsx +61 -0
  23. package/src/components/mdx/Badge.tsx +33 -0
  24. package/src/components/mdx/Callout.astro +79 -0
  25. package/src/components/mdx/Card.astro +66 -0
  26. package/src/components/mdx/CardGroup.astro +18 -0
  27. package/src/components/mdx/CodeGroup.astro +63 -0
  28. package/src/components/mdx/CodeGroup.tsx +51 -0
  29. package/src/components/mdx/Columns.tsx +31 -0
  30. package/src/components/mdx/DocAccordion.tsx +87 -0
  31. package/src/components/mdx/DocCallout.tsx +65 -0
  32. package/src/components/mdx/DocCard.tsx +70 -0
  33. package/src/components/mdx/DocTabs.tsx +48 -0
  34. package/src/components/mdx/Expandable.tsx +107 -0
  35. package/src/components/mdx/FileTree.tsx +72 -0
  36. package/src/components/mdx/Frame.tsx +23 -0
  37. package/src/components/mdx/Icon.tsx +59 -0
  38. package/src/components/mdx/Mermaid.tsx +94 -0
  39. package/src/components/mdx/ParamField.tsx +76 -0
  40. package/src/components/mdx/ResponseField.tsx +62 -0
  41. package/src/components/mdx/Step.astro +14 -0
  42. package/src/components/mdx/Steps.astro +37 -0
  43. package/src/components/mdx/Steps.tsx +49 -0
  44. package/src/components/mdx/Tabs.tsx +67 -0
  45. package/src/components/mdx/Tooltip.tsx +36 -0
  46. package/src/components/ui/accordion.tsx +54 -0
  47. package/src/components/ui/alert.tsx +60 -0
  48. package/src/components/ui/button.tsx +57 -0
  49. package/src/components/ui/card.tsx +75 -0
  50. package/src/components/ui/collapsible.tsx +9 -0
  51. package/src/components/ui/dialog.tsx +119 -0
  52. package/src/components/ui/index.ts +11 -0
  53. package/src/components/ui/scroll-area.tsx +45 -0
  54. package/src/components/ui/separator.tsx +28 -0
  55. package/src/components/ui/sheet.tsx +137 -0
  56. package/src/components/ui/tabs.tsx +52 -0
  57. package/src/components/ui/tooltip.tsx +29 -0
  58. package/src/index.ts +74 -0
  59. package/src/layouts/BaseLayout.astro +28 -0
  60. package/src/layouts/DocsLayout.astro +121 -0
  61. package/src/lib/utils.ts +6 -0
  62. package/src/pages/docs/[...slug].astro +116 -0
  63. package/src/pages/index.astro +217 -0
  64. package/src/styles/global.css +342 -0
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+ import { Card, CardHeader, CardTitle, CardDescription } from "../ui/card";
3
+ import { cn } from "../../lib/utils";
4
+ import { ChevronRight } from "lucide-react";
5
+
6
+ interface DocCardProps {
7
+ title: string;
8
+ icon?: string;
9
+ href?: string;
10
+ children?: React.ReactNode;
11
+ }
12
+
13
+ export function DocCard({ title, icon, href, children }: DocCardProps) {
14
+ const Comp = href ? "a" : "div";
15
+
16
+ return (
17
+ <Card
18
+ className={cn(
19
+ "group relative overflow-hidden transition-all duration-200",
20
+ href && "cursor-pointer hover:border-primary-300 dark:hover:border-primary-600 hover:shadow-lg hover:shadow-primary-500/5"
21
+ )}
22
+ >
23
+ <Comp href={href} className="block">
24
+ <div className="absolute inset-0 bg-gradient-to-br from-primary-50/50 to-transparent dark:from-primary-950/30 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" />
25
+ <CardHeader className="relative">
26
+ {icon && (
27
+ <div className="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 mb-3 transition-colors">
28
+ <span className="text-xl">{icon}</span>
29
+ </div>
30
+ )}
31
+ <div className="flex items-center gap-2">
32
+ <CardTitle className="group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
33
+ {title}
34
+ </CardTitle>
35
+ {href && (
36
+ <ChevronRight className="h-4 w-4 text-[var(--color-text-muted)] opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" />
37
+ )}
38
+ </div>
39
+ {children && (
40
+ <CardDescription className="mt-1.5 leading-relaxed">
41
+ {children}
42
+ </CardDescription>
43
+ )}
44
+ </CardHeader>
45
+ </Comp>
46
+ </Card>
47
+ );
48
+ }
49
+
50
+ interface DocCardGroupProps {
51
+ cols?: 1 | 2 | 3 | 4;
52
+ children: React.ReactNode;
53
+ }
54
+
55
+ export function DocCardGroup({ cols = 2, children }: DocCardGroupProps) {
56
+ const gridCols: Record<number, string> = {
57
+ 1: "grid-cols-1",
58
+ 2: "grid-cols-1 sm:grid-cols-2",
59
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
60
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
61
+ };
62
+
63
+ return (
64
+ <div className={cn("not-prose grid gap-4 my-6", gridCols[cols])}>
65
+ {children}
66
+ </div>
67
+ );
68
+ }
69
+
70
+ export default DocCard;
@@ -0,0 +1,48 @@
1
+ import * as React from "react";
2
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
3
+ import { cn } from "../../lib/utils";
4
+
5
+ interface TabItem {
6
+ label: string;
7
+ value: string;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ interface DocTabsProps {
12
+ items: TabItem[];
13
+ defaultValue?: string;
14
+ className?: string;
15
+ }
16
+
17
+ export function DocTabs({ items, defaultValue, className }: DocTabsProps) {
18
+ const defaultTab = defaultValue || items[0]?.value;
19
+
20
+ return (
21
+ <Tabs defaultValue={defaultTab} className={cn("not-prose my-6", className)}>
22
+ <TabsList className="w-full justify-start bg-[var(--color-bg-secondary)] rounded-lg p-1">
23
+ {items.map((item) => (
24
+ <TabsTrigger
25
+ key={item.value}
26
+ value={item.value}
27
+ className="data-[state=active]:bg-[var(--color-bg)] data-[state=active]:shadow-sm"
28
+ >
29
+ {item.label}
30
+ </TabsTrigger>
31
+ ))}
32
+ </TabsList>
33
+ {items.map((item) => (
34
+ <TabsContent
35
+ key={item.value}
36
+ value={item.value}
37
+ className="mt-4 rounded-lg border border-[var(--color-border)] bg-[var(--color-bg-secondary)] p-4"
38
+ >
39
+ <div className="text-sm">
40
+ {item.children}
41
+ </div>
42
+ </TabsContent>
43
+ ))}
44
+ </Tabs>
45
+ );
46
+ }
47
+
48
+ export default DocTabs;
@@ -0,0 +1,107 @@
1
+ import * as React from "react";
2
+ import { ChevronDown, Plus, Minus } from "lucide-react";
3
+ import { cn } from "../../lib/utils.js";
4
+
5
+ interface ExpandableProps {
6
+ title: string;
7
+ children: React.ReactNode;
8
+ defaultOpen?: boolean;
9
+ className?: string;
10
+ }
11
+
12
+ export function Expandable({
13
+ title,
14
+ children,
15
+ defaultOpen = false,
16
+ className,
17
+ }: ExpandableProps) {
18
+ const [isOpen, setIsOpen] = React.useState(defaultOpen);
19
+
20
+ return (
21
+ <div
22
+ className={cn(
23
+ "not-prose border border-[var(--color-border)] rounded-lg overflow-hidden my-4",
24
+ className
25
+ )}
26
+ >
27
+ <button
28
+ type="button"
29
+ onClick={() => setIsOpen(!isOpen)}
30
+ className="flex w-full items-center justify-between px-4 py-3 bg-[var(--color-bg-secondary)] hover:bg-[var(--color-bg-tertiary)] transition-colors text-left"
31
+ >
32
+ <span className="text-sm font-medium text-[var(--color-text)]">
33
+ {title}
34
+ </span>
35
+ <ChevronDown
36
+ className={cn(
37
+ "h-4 w-4 text-[var(--color-text-muted)] transition-transform",
38
+ isOpen && "rotate-180"
39
+ )}
40
+ />
41
+ </button>
42
+ {isOpen && (
43
+ <div className="px-4 py-3 bg-[var(--color-bg)] border-t border-[var(--color-border)] text-sm text-[var(--color-text-secondary)]">
44
+ {children}
45
+ </div>
46
+ )}
47
+ </div>
48
+ );
49
+ }
50
+
51
+ interface ExpandableListProps {
52
+ children: React.ReactNode;
53
+ className?: string;
54
+ }
55
+
56
+ export function ExpandableList({ children, className }: ExpandableListProps) {
57
+ return (
58
+ <div className={cn("space-y-2 my-4", className)}>
59
+ {children}
60
+ </div>
61
+ );
62
+ }
63
+
64
+ interface ExpandableItemProps {
65
+ title: string;
66
+ type?: string;
67
+ children: React.ReactNode;
68
+ defaultOpen?: boolean;
69
+ }
70
+
71
+ export function ExpandableItem({
72
+ title,
73
+ type,
74
+ children,
75
+ defaultOpen = false,
76
+ }: ExpandableItemProps) {
77
+ const [isOpen, setIsOpen] = React.useState(defaultOpen);
78
+
79
+ return (
80
+ <div className="not-prose border-l-2 border-[var(--color-border)] pl-4">
81
+ <button
82
+ type="button"
83
+ onClick={() => setIsOpen(!isOpen)}
84
+ className="flex items-center gap-2 text-left group"
85
+ >
86
+ {isOpen ? (
87
+ <Minus className="h-3 w-3 text-[var(--color-text-muted)]" />
88
+ ) : (
89
+ <Plus className="h-3 w-3 text-[var(--color-text-muted)]" />
90
+ )}
91
+ <code className="font-mono text-sm text-[var(--color-text)] group-hover:text-primary-600 dark:group-hover:text-primary-400">
92
+ {title}
93
+ </code>
94
+ {type && (
95
+ <span className="font-mono text-xs text-[var(--color-text-muted)]">
96
+ {type}
97
+ </span>
98
+ )}
99
+ </button>
100
+ {isOpen && (
101
+ <div className="mt-2 ml-5 text-sm text-[var(--color-text-secondary)]">
102
+ {children}
103
+ </div>
104
+ )}
105
+ </div>
106
+ );
107
+ }
@@ -0,0 +1,72 @@
1
+ import * as React from "react";
2
+ import { ChevronRight, File, Folder, FolderOpen } from "lucide-react";
3
+ import { cn } from "../../lib/utils.js";
4
+
5
+ interface FileTreeProps {
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ export function FileTree({ children, className }: FileTreeProps) {
11
+ return (
12
+ <div className={cn("not-prose my-4 rounded-lg border border-[var(--color-border)] bg-[var(--color-bg-secondary)] p-4 font-mono text-sm", className)}>
13
+ <ul className="space-y-1">{children}</ul>
14
+ </div>
15
+ );
16
+ }
17
+
18
+ interface FileProps {
19
+ name: string;
20
+ icon?: React.ReactNode;
21
+ }
22
+
23
+ export function TreeFile({ name, icon }: FileProps) {
24
+ return (
25
+ <li className="flex items-center gap-2 py-0.5 text-[var(--color-text-secondary)]">
26
+ {icon || <File className="h-4 w-4 text-[var(--color-text-muted)]" />}
27
+ <span>{name}</span>
28
+ </li>
29
+ );
30
+ }
31
+
32
+ interface FolderProps {
33
+ name: string;
34
+ children?: React.ReactNode;
35
+ defaultOpen?: boolean;
36
+ }
37
+
38
+ export function TreeFolder({ name, children, defaultOpen = false }: FolderProps) {
39
+ const [isOpen, setIsOpen] = React.useState(defaultOpen);
40
+ const hasChildren = React.Children.count(children) > 0;
41
+
42
+ return (
43
+ <li>
44
+ <button
45
+ type="button"
46
+ onClick={() => setIsOpen(!isOpen)}
47
+ className="flex w-full items-center gap-1 py-0.5 text-[var(--color-text)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
48
+ >
49
+ {hasChildren && (
50
+ <ChevronRight
51
+ className={cn(
52
+ "h-3 w-3 text-[var(--color-text-muted)] transition-transform",
53
+ isOpen && "rotate-90"
54
+ )}
55
+ />
56
+ )}
57
+ {!hasChildren && <span className="w-3" />}
58
+ {isOpen ? (
59
+ <FolderOpen className="h-4 w-4 text-primary-500" />
60
+ ) : (
61
+ <Folder className="h-4 w-4 text-primary-500" />
62
+ )}
63
+ <span className="font-medium">{name}</span>
64
+ </button>
65
+ {isOpen && hasChildren && (
66
+ <ul className="ml-4 border-l border-[var(--color-border)] pl-3 mt-1 space-y-1">
67
+ {children}
68
+ </ul>
69
+ )}
70
+ </li>
71
+ );
72
+ }
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils.js";
3
+
4
+ interface FrameProps {
5
+ children: React.ReactNode;
6
+ caption?: string;
7
+ className?: string;
8
+ }
9
+
10
+ export function Frame({ children, caption, className }: FrameProps) {
11
+ return (
12
+ <figure className={cn("not-prose my-6", className)}>
13
+ <div className="overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-bg-secondary)]">
14
+ {children}
15
+ </div>
16
+ {caption && (
17
+ <figcaption className="mt-2 text-center text-sm text-[var(--color-text-muted)]">
18
+ {caption}
19
+ </figcaption>
20
+ )}
21
+ </figure>
22
+ );
23
+ }
@@ -0,0 +1,59 @@
1
+ import * as React from "react";
2
+ import { icons, type LucideIcon as LucideIconType } from "lucide-react";
3
+ import { cn } from "../../lib/utils.js";
4
+
5
+ interface IconProps {
6
+ name: string;
7
+ size?: number | "sm" | "md" | "lg" | "xl";
8
+ className?: string;
9
+ color?: string;
10
+ }
11
+
12
+ const sizeMap = {
13
+ sm: 16,
14
+ md: 20,
15
+ lg: 24,
16
+ xl: 32,
17
+ };
18
+
19
+ export function Icon({ name, size = "md", className, color }: IconProps) {
20
+ // Convert name to PascalCase (e.g., "chevron-right" -> "ChevronRight")
21
+ const iconName = name
22
+ .split("-")
23
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
24
+ .join("");
25
+
26
+ const LucideIcon = icons[iconName as keyof typeof icons] as LucideIconType | undefined;
27
+
28
+ if (!LucideIcon) {
29
+ console.warn(`Icon "${name}" not found in lucide-react`);
30
+ return null;
31
+ }
32
+
33
+ const numericSize = typeof size === "number" ? size : sizeMap[size];
34
+
35
+ return (
36
+ <LucideIcon
37
+ size={numericSize}
38
+ className={cn("inline-block", className)}
39
+ style={color ? { color } : undefined}
40
+ />
41
+ );
42
+ }
43
+
44
+ // Pre-built icon components for common use cases
45
+ export function CheckIcon({ className }: { className?: string }) {
46
+ return <Icon name="check" className={cn("text-green-500", className)} />;
47
+ }
48
+
49
+ export function XIcon({ className }: { className?: string }) {
50
+ return <Icon name="x" className={cn("text-red-500", className)} />;
51
+ }
52
+
53
+ export function InfoIcon({ className }: { className?: string }) {
54
+ return <Icon name="info" className={cn("text-blue-500", className)} />;
55
+ }
56
+
57
+ export function WarningIcon({ className }: { className?: string }) {
58
+ return <Icon name="alert-triangle" className={cn("text-yellow-500", className)} />;
59
+ }
@@ -0,0 +1,94 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils.js";
3
+
4
+ interface MermaidProps {
5
+ chart: string;
6
+ className?: string;
7
+ }
8
+
9
+ export function Mermaid({ chart, className }: MermaidProps) {
10
+ const containerRef = React.useRef<HTMLDivElement>(null);
11
+ const [svg, setSvg] = React.useState<string>("");
12
+ const [error, setError] = React.useState<string | null>(null);
13
+
14
+ React.useEffect(() => {
15
+ let isMounted = true;
16
+
17
+ async function renderChart() {
18
+ try {
19
+ // Dynamically import mermaid
20
+ const mermaid = (await import("mermaid")).default;
21
+
22
+ mermaid.initialize({
23
+ startOnLoad: false,
24
+ theme: document.documentElement.classList.contains("dark") ? "dark" : "default",
25
+ securityLevel: "loose",
26
+ });
27
+
28
+ const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
29
+ const { svg } = await mermaid.render(id, chart);
30
+
31
+ if (isMounted) {
32
+ setSvg(svg);
33
+ setError(null);
34
+ }
35
+ } catch (err) {
36
+ if (isMounted) {
37
+ setError(err instanceof Error ? err.message : "Failed to render diagram");
38
+ }
39
+ }
40
+ }
41
+
42
+ renderChart();
43
+
44
+ return () => {
45
+ isMounted = false;
46
+ };
47
+ }, [chart]);
48
+
49
+ // Re-render on theme change
50
+ React.useEffect(() => {
51
+ const observer = new MutationObserver((mutations) => {
52
+ mutations.forEach((mutation) => {
53
+ if (mutation.attributeName === "class") {
54
+ // Theme changed, re-render
55
+ setSvg("");
56
+ }
57
+ });
58
+ });
59
+
60
+ observer.observe(document.documentElement, {
61
+ attributes: true,
62
+ attributeFilter: ["class"],
63
+ });
64
+
65
+ return () => observer.disconnect();
66
+ }, []);
67
+
68
+ if (error) {
69
+ return (
70
+ <div className="not-prose my-4 rounded-lg border border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30 p-4">
71
+ <p className="text-sm text-red-600 dark:text-red-400">
72
+ Mermaid diagram error: {error}
73
+ </p>
74
+ <pre className="mt-2 text-xs text-red-500 overflow-auto">{chart}</pre>
75
+ </div>
76
+ );
77
+ }
78
+
79
+ if (!svg) {
80
+ return (
81
+ <div className={cn("not-prose my-4 flex items-center justify-center p-8 bg-[var(--color-bg-secondary)] rounded-lg", className)}>
82
+ <div className="text-sm text-[var(--color-text-muted)]">Loading diagram...</div>
83
+ </div>
84
+ );
85
+ }
86
+
87
+ return (
88
+ <div
89
+ ref={containerRef}
90
+ className={cn("not-prose my-4 flex justify-center overflow-x-auto rounded-lg bg-[var(--color-bg)] p-4", className)}
91
+ dangerouslySetInnerHTML={{ __html: svg }}
92
+ />
93
+ );
94
+ }
@@ -0,0 +1,76 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils.js";
3
+
4
+ interface ParamFieldProps {
5
+ name: string;
6
+ type?: string;
7
+ required?: boolean;
8
+ default?: string;
9
+ children?: React.ReactNode;
10
+ className?: string;
11
+ }
12
+
13
+ export function ParamField({
14
+ name,
15
+ type,
16
+ required,
17
+ default: defaultValue,
18
+ children,
19
+ className,
20
+ }: ParamFieldProps) {
21
+ return (
22
+ <div
23
+ className={cn(
24
+ "not-prose border-b border-[var(--color-border)] py-4 last:border-b-0",
25
+ className
26
+ )}
27
+ >
28
+ <div className="flex flex-wrap items-baseline gap-2">
29
+ <code className="font-mono text-sm font-semibold text-[var(--color-text)]">
30
+ {name}
31
+ </code>
32
+ {type && (
33
+ <span className="font-mono text-xs text-[var(--color-text-muted)]">
34
+ {type}
35
+ </span>
36
+ )}
37
+ {required && (
38
+ <span className="rounded bg-red-100 px-1.5 py-0.5 text-xs font-medium text-red-700 dark:bg-red-900/30 dark:text-red-400">
39
+ required
40
+ </span>
41
+ )}
42
+ {defaultValue && (
43
+ <span className="text-xs text-[var(--color-text-muted)]">
44
+ default: <code className="font-mono">{defaultValue}</code>
45
+ </span>
46
+ )}
47
+ </div>
48
+ {children && (
49
+ <div className="mt-2 text-sm text-[var(--color-text-secondary)] prose prose-sm dark:prose-invert max-w-none">
50
+ {children}
51
+ </div>
52
+ )}
53
+ </div>
54
+ );
55
+ }
56
+
57
+ interface ParamFieldGroupProps {
58
+ children: React.ReactNode;
59
+ title?: string;
60
+ className?: string;
61
+ }
62
+
63
+ export function ParamFieldGroup({ children, title, className }: ParamFieldGroupProps) {
64
+ return (
65
+ <div className={cn("my-6", className)}>
66
+ {title && (
67
+ <h4 className="text-sm font-semibold text-[var(--color-text)] mb-4 uppercase tracking-wide">
68
+ {title}
69
+ </h4>
70
+ )}
71
+ <div className="rounded-lg border border-[var(--color-border)] bg-[var(--color-bg)] px-4">
72
+ {children}
73
+ </div>
74
+ </div>
75
+ );
76
+ }
@@ -0,0 +1,62 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils.js";
3
+
4
+ interface ResponseFieldProps {
5
+ name: string;
6
+ type?: string;
7
+ children?: React.ReactNode;
8
+ className?: string;
9
+ }
10
+
11
+ export function ResponseField({
12
+ name,
13
+ type,
14
+ children,
15
+ className,
16
+ }: ResponseFieldProps) {
17
+ return (
18
+ <div
19
+ className={cn(
20
+ "not-prose border-b border-[var(--color-border)] py-4 first:pt-0 last:border-b-0",
21
+ className
22
+ )}
23
+ >
24
+ <div className="flex flex-wrap items-baseline gap-2">
25
+ <code className="font-mono text-sm font-semibold text-[var(--color-text)]">
26
+ {name}
27
+ </code>
28
+ {type && (
29
+ <span className="font-mono text-xs text-[var(--color-text-muted)]">
30
+ {type}
31
+ </span>
32
+ )}
33
+ </div>
34
+ {children && (
35
+ <div className="mt-2 text-sm text-[var(--color-text-secondary)] prose prose-sm dark:prose-invert max-w-none">
36
+ {children}
37
+ </div>
38
+ )}
39
+ </div>
40
+ );
41
+ }
42
+
43
+ interface ResponseFieldGroupProps {
44
+ children: React.ReactNode;
45
+ title?: string;
46
+ className?: string;
47
+ }
48
+
49
+ export function ResponseFieldGroup({ children, title, className }: ResponseFieldGroupProps) {
50
+ return (
51
+ <div className={cn("my-6", className)}>
52
+ {title && (
53
+ <h4 className="text-sm font-semibold text-[var(--color-text)] mb-4 uppercase tracking-wide">
54
+ {title}
55
+ </h4>
56
+ )}
57
+ <div className="rounded-lg border border-[var(--color-border)] bg-[var(--color-bg)] px-4">
58
+ {children}
59
+ </div>
60
+ </div>
61
+ );
62
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ interface Props {
3
+ title: string;
4
+ }
5
+
6
+ const { title } = Astro.props;
7
+ ---
8
+
9
+ <div class="relative">
10
+ <h3 class="font-semibold text-[var(--color-text)] mb-2">{title}</h3>
11
+ <div class="text-sm text-[var(--color-text-secondary)]">
12
+ <slot />
13
+ </div>
14
+ </div>
@@ -0,0 +1,37 @@
1
+ ---
2
+ // Steps component for step-by-step guides
3
+ ---
4
+
5
+ <div class="not-prose my-6 space-y-4 border-l-2 border-[var(--color-border)] pl-6 ml-2">
6
+ <slot />
7
+ </div>
8
+
9
+ <style>
10
+ div :global(> *) {
11
+ position: relative;
12
+ }
13
+
14
+ div :global(> *::before) {
15
+ content: counter(step);
16
+ counter-increment: step;
17
+ position: absolute;
18
+ left: -2.25rem;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ width: 1.5rem;
23
+ height: 1.5rem;
24
+ font-size: 0.75rem;
25
+ font-weight: 600;
26
+ background-color: var(--color-bg);
27
+ border: 2px solid var(--color-border);
28
+ border-radius: 9999px;
29
+ }
30
+ </style>
31
+
32
+ <script>
33
+ // Initialize step counter
34
+ document.querySelectorAll('.not-prose.space-y-4').forEach(container => {
35
+ container.style.counterReset = 'step';
36
+ });
37
+ </script>