@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,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;