@vllnt/ui 0.1.4 → 0.1.7-canary.2c4792f

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 (225) hide show
  1. package/dist/components/accordion/accordion.js +172 -0
  2. package/dist/components/accordion/index.js +12 -0
  3. package/dist/components/alert/alert.js +53 -0
  4. package/dist/components/alert/index.js +7 -0
  5. package/dist/components/alert-dialog/alert-dialog.js +117 -0
  6. package/dist/components/alert-dialog/index.js +26 -0
  7. package/dist/components/aspect-ratio/aspect-ratio.js +6 -0
  8. package/dist/components/aspect-ratio/index.js +4 -0
  9. package/dist/components/avatar/avatar.js +43 -0
  10. package/dist/components/avatar/index.js +6 -0
  11. package/dist/components/badge/badge.js +26 -0
  12. package/dist/components/badge/index.js +5 -0
  13. package/dist/components/blog-card/blog-card.js +50 -0
  14. package/dist/components/blog-card/index.js +5 -0
  15. package/dist/components/breadcrumb/breadcrumb.js +61 -0
  16. package/dist/components/breadcrumb/index.js +4 -0
  17. package/dist/components/button/button.js +48 -0
  18. package/dist/components/button/index.js +5 -0
  19. package/dist/components/calendar/calendar.js +71 -0
  20. package/dist/components/calendar/index.js +4 -0
  21. package/dist/components/callout/callout.js +59 -0
  22. package/dist/components/callout/index.js +4 -0
  23. package/dist/components/card/card.js +64 -0
  24. package/dist/components/card/index.js +16 -0
  25. package/dist/components/carousel/carousel.js +239 -0
  26. package/dist/components/carousel/index.js +14 -0
  27. package/dist/components/category-filter/category-filter.js +34 -0
  28. package/dist/components/category-filter/index.js +4 -0
  29. package/dist/components/chart/area-chart.js +99 -0
  30. package/dist/components/chart/bar-chart.js +80 -0
  31. package/dist/components/chart/index.js +3 -0
  32. package/dist/components/chart/line-chart.js +97 -0
  33. package/dist/components/checkbox/checkbox.js +28 -0
  34. package/dist/components/checkbox/index.js +4 -0
  35. package/dist/components/checklist/checklist.js +181 -0
  36. package/dist/components/checklist/index.js +6 -0
  37. package/dist/components/code-block/code-block.js +126 -0
  38. package/dist/components/code-block/index.js +4 -0
  39. package/dist/components/code-playground/code-playground.js +86 -0
  40. package/dist/components/code-playground/index.js +8 -0
  41. package/dist/components/collapsible/collapsible.js +10 -0
  42. package/dist/components/collapsible/index.js +10 -0
  43. package/dist/components/command/command.js +123 -0
  44. package/dist/components/command/index.js +22 -0
  45. package/dist/components/comparison/comparison.js +121 -0
  46. package/dist/components/comparison/index.js +8 -0
  47. package/dist/components/completion-dialog/completion-dialog.js +173 -0
  48. package/dist/components/completion-dialog/index.js +6 -0
  49. package/dist/components/content-intro/content-intro.js +144 -0
  50. package/dist/components/content-intro/index.js +6 -0
  51. package/dist/components/context-menu/context-menu.js +154 -0
  52. package/dist/components/context-menu/index.js +34 -0
  53. package/dist/components/cookie-consent/cookie-consent.js +175 -0
  54. package/dist/components/cookie-consent/index.js +8 -0
  55. package/dist/components/dialog/dialog.js +105 -0
  56. package/dist/components/dialog/index.js +24 -0
  57. package/dist/components/drawer/drawer.js +102 -0
  58. package/dist/components/drawer/index.js +24 -0
  59. package/dist/components/dropdown-menu/dropdown-menu.js +151 -0
  60. package/dist/components/dropdown-menu/index.js +34 -0
  61. package/dist/components/exercise/exercise.js +112 -0
  62. package/dist/components/exercise/index.js +4 -0
  63. package/dist/components/faq/faq.js +56 -0
  64. package/dist/components/faq/index.js +5 -0
  65. package/dist/components/filter-bar/filter-bar.js +244 -0
  66. package/dist/components/filter-bar/index.js +6 -0
  67. package/dist/components/floating-action-button/floating-action-button.js +35 -0
  68. package/dist/components/floating-action-button/index.js +6 -0
  69. package/dist/components/flow-diagram/flow-canvas.js +109 -0
  70. package/dist/components/flow-diagram/flow-controls.js +140 -0
  71. package/dist/components/flow-diagram/flow-diagram.js +114 -0
  72. package/dist/components/flow-diagram/flow-error-boundary.js +63 -0
  73. package/dist/components/flow-diagram/flow-fullscreen.js +58 -0
  74. package/dist/components/flow-diagram/index.js +12 -0
  75. package/dist/components/flow-diagram/types.js +0 -0
  76. package/dist/components/flow-diagram/use-flow-diagram.js +146 -0
  77. package/dist/components/horizontal-scroll-row/horizontal-scroll-row.js +66 -0
  78. package/dist/components/horizontal-scroll-row/index.js +6 -0
  79. package/dist/components/hover-card/hover-card.js +26 -0
  80. package/dist/components/hover-card/index.js +6 -0
  81. package/dist/components/index.js +641 -0
  82. package/dist/components/inline-input/index.js +4 -0
  83. package/dist/components/inline-input/inline-input.js +42 -0
  84. package/dist/components/input/index.js +4 -0
  85. package/dist/components/input/input.js +23 -0
  86. package/dist/components/input-otp/index.js +12 -0
  87. package/dist/components/input-otp/input-otp.js +54 -0
  88. package/dist/components/key-concept/index.js +8 -0
  89. package/dist/components/key-concept/key-concept.js +79 -0
  90. package/dist/components/keyboard-shortcuts-help/index.js +6 -0
  91. package/dist/components/keyboard-shortcuts-help/keyboard-shortcuts-help.js +121 -0
  92. package/dist/components/label/index.js +4 -0
  93. package/dist/components/label/label.js +21 -0
  94. package/dist/components/lang-provider/index.js +4 -0
  95. package/dist/components/lang-provider/lang-provider.js +18 -0
  96. package/dist/components/learning-objectives/index.js +10 -0
  97. package/dist/components/learning-objectives/learning-objectives.js +76 -0
  98. package/dist/components/mdx-content/index.js +4 -0
  99. package/dist/components/mdx-content/mdx-content.js +151 -0
  100. package/dist/components/menubar/index.js +36 -0
  101. package/dist/components/menubar/menubar.js +183 -0
  102. package/dist/components/model-selector/index.js +6 -0
  103. package/dist/components/model-selector/model-selector.js +374 -0
  104. package/dist/components/navbar-saas/index.js +6 -0
  105. package/dist/components/navbar-saas/navbar-saas.js +68 -0
  106. package/dist/components/navbar-saas/use-mobile.js +19 -0
  107. package/dist/components/navigation-menu/index.js +22 -0
  108. package/dist/components/navigation-menu/navigation-menu.js +108 -0
  109. package/dist/components/pagination/index.js +4 -0
  110. package/dist/components/pagination/pagination.js +44 -0
  111. package/dist/components/popover/index.js +12 -0
  112. package/dist/components/popover/popover.js +28 -0
  113. package/dist/components/pro-tip/index.js +8 -0
  114. package/dist/components/pro-tip/pro-tip.js +139 -0
  115. package/dist/components/profile-section/index.js +4 -0
  116. package/dist/components/profile-section/profile-section.js +45 -0
  117. package/dist/components/progress-bar/index.js +4 -0
  118. package/dist/components/progress-bar/progress-bar.js +56 -0
  119. package/dist/components/progress-card/index.js +6 -0
  120. package/dist/components/progress-card/progress-card.js +71 -0
  121. package/dist/components/quiz/index.js +4 -0
  122. package/dist/components/quiz/quiz.js +210 -0
  123. package/dist/components/radio-group/index.js +5 -0
  124. package/dist/components/radio-group/radio-group.js +36 -0
  125. package/dist/components/resizable/index.js +10 -0
  126. package/dist/components/resizable/resizable.js +39 -0
  127. package/dist/components/scroll-area/index.js +5 -0
  128. package/dist/components/scroll-area/scroll-area.js +39 -0
  129. package/dist/components/search-bar/index.js +4 -0
  130. package/dist/components/search-bar/search-bar.js +122 -0
  131. package/dist/components/search-dialog/index.js +4 -0
  132. package/dist/components/search-dialog/search-dialog.js +102 -0
  133. package/dist/components/select/index.js +24 -0
  134. package/dist/components/select/select.js +125 -0
  135. package/dist/components/separator/index.js +4 -0
  136. package/dist/components/separator/separator.js +25 -0
  137. package/dist/components/share-dialog/index.js +6 -0
  138. package/dist/components/share-dialog/share-dialog.js +121 -0
  139. package/dist/components/share-section/index.js +6 -0
  140. package/dist/components/share-section/share-section.js +57 -0
  141. package/dist/components/sheet/index.js +24 -0
  142. package/dist/components/sheet/sheet.js +116 -0
  143. package/dist/components/sidebar/index.js +4 -0
  144. package/dist/components/sidebar/sidebar.js +188 -0
  145. package/dist/components/sidebar-provider/index.js +5 -0
  146. package/dist/components/sidebar-provider/sidebar-provider.js +25 -0
  147. package/dist/components/sidebar-toggle/index.js +4 -0
  148. package/dist/components/sidebar-toggle/sidebar-toggle.js +36 -0
  149. package/dist/components/skeleton/index.js +4 -0
  150. package/dist/components/skeleton/skeleton.js +17 -0
  151. package/dist/components/slider/index.js +4 -0
  152. package/dist/components/slider/slider.js +24 -0
  153. package/dist/components/slideshow/index.js +6 -0
  154. package/dist/components/slideshow/slideshow.js +440 -0
  155. package/dist/components/social-fab/index.js +6 -0
  156. package/dist/components/social-fab/social-fab.js +211 -0
  157. package/dist/components/social-fab/use-social-fab.js +111 -0
  158. package/dist/components/spinner/index.js +4 -0
  159. package/dist/components/spinner/spinner.js +23 -0
  160. package/dist/components/step-by-step/index.js +8 -0
  161. package/dist/components/step-by-step/step-by-step.js +194 -0
  162. package/dist/components/step-navigation/index.js +4 -0
  163. package/dist/components/step-navigation/step-navigation.js +119 -0
  164. package/dist/components/switch/index.js +4 -0
  165. package/dist/components/switch/switch.js +28 -0
  166. package/dist/components/table/index.js +20 -0
  167. package/dist/components/table/table.js +87 -0
  168. package/dist/components/table-of-contents/index.js +4 -0
  169. package/dist/components/table-of-contents/table-of-contents.js +71 -0
  170. package/dist/components/table-of-contents-panel/index.js +6 -0
  171. package/dist/components/table-of-contents-panel/table-of-contents-panel.js +202 -0
  172. package/dist/components/tabs/index.js +12 -0
  173. package/dist/components/tabs/tabs.js +84 -0
  174. package/dist/components/terminal/index.js +8 -0
  175. package/dist/components/terminal/terminal.js +119 -0
  176. package/dist/components/textarea/index.js +4 -0
  177. package/dist/components/textarea/textarea.js +22 -0
  178. package/dist/components/theme-provider/index.js +4 -0
  179. package/dist/components/theme-provider/theme-provider.js +11 -0
  180. package/dist/components/theme-toggle/index.js +4 -0
  181. package/dist/components/theme-toggle/theme-toggle.js +170 -0
  182. package/dist/components/thinking-block/index.js +4 -0
  183. package/dist/components/thinking-block/thinking-block.js +56 -0
  184. package/dist/components/tldr-section/index.js +4 -0
  185. package/dist/components/tldr-section/tldr-section.js +101 -0
  186. package/dist/components/toast/index.js +18 -0
  187. package/dist/components/toast/toast.js +84 -0
  188. package/dist/components/toast/toaster.js +38 -0
  189. package/dist/components/toggle/index.js +5 -0
  190. package/dist/components/toggle/toggle.js +39 -0
  191. package/dist/components/toggle-group/index.js +5 -0
  192. package/dist/components/toggle-group/toggle-group.js +46 -0
  193. package/dist/components/tooltip/index.js +12 -0
  194. package/dist/components/tooltip/tooltip.js +27 -0
  195. package/dist/components/truncated-text/index.js +4 -0
  196. package/dist/components/truncated-text/truncated-text.js +25 -0
  197. package/dist/components/tutorial-card/index.js +6 -0
  198. package/dist/components/tutorial-card/tutorial-card.js +78 -0
  199. package/dist/components/tutorial-complete/index.js +6 -0
  200. package/dist/components/tutorial-complete/tutorial-complete.js +134 -0
  201. package/dist/components/tutorial-filters/index.js +6 -0
  202. package/dist/components/tutorial-filters/tutorial-filters.js +205 -0
  203. package/dist/components/tutorial-intro-content/index.js +6 -0
  204. package/dist/components/tutorial-intro-content/tutorial-intro-content.js +141 -0
  205. package/dist/components/tutorial-mdx/index.js +8 -0
  206. package/dist/components/tutorial-mdx/tutorial-mdx.js +219 -0
  207. package/dist/components/video-embed/index.js +4 -0
  208. package/dist/components/video-embed/video-embed.js +77 -0
  209. package/dist/components/view-switcher/index.js +6 -0
  210. package/dist/components/view-switcher/view-switcher.js +92 -0
  211. package/dist/index.d.ts +44 -2
  212. package/dist/index.js +14 -8556
  213. package/dist/lib/types.js +11 -0
  214. package/dist/lib/use-debounce.js +17 -0
  215. package/dist/lib/use-horizontal-scroll.js +60 -0
  216. package/dist/lib/use-mounted.js +17 -0
  217. package/dist/lib/utils.js +8 -0
  218. package/dist/tailwind-preset.d.ts +5 -0
  219. package/dist/tailwind-preset.js +9 -10
  220. package/dist/types/content.js +0 -0
  221. package/dist/types/index.js +0 -0
  222. package/package.json +42 -23
  223. package/LICENSE +0 -21
  224. package/dist/chunk-XRV5RSYH.js +0 -569
  225. package/dist/flow-diagram-N3EHM6VB.js +0 -2
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as SwitchPrimitives from "@radix-ui/react-switch";
5
+ import { cn } from "../../lib/utils";
6
+ const Switch = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7
+ SwitchPrimitives.Root,
8
+ {
9
+ className: cn(
10
+ "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
11
+ className
12
+ ),
13
+ ref,
14
+ ...props,
15
+ children: /* @__PURE__ */ jsx(
16
+ SwitchPrimitives.Thumb,
17
+ {
18
+ className: cn(
19
+ "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
20
+ )
21
+ }
22
+ )
23
+ }
24
+ ));
25
+ Switch.displayName = SwitchPrimitives.Root.displayName;
26
+ export {
27
+ Switch
28
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ Table,
3
+ TableBody,
4
+ TableCaption,
5
+ TableCell,
6
+ TableFooter,
7
+ TableHead,
8
+ TableHeader,
9
+ TableRow
10
+ } from "./table";
11
+ export {
12
+ Table,
13
+ TableBody,
14
+ TableCaption,
15
+ TableCell,
16
+ TableFooter,
17
+ TableHead,
18
+ TableHeader,
19
+ TableRow
20
+ };
@@ -0,0 +1,87 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "../../lib/utils";
4
+ const Table = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
5
+ "table",
6
+ {
7
+ className: cn("w-full caption-bottom text-sm", className),
8
+ ref,
9
+ ...props
10
+ }
11
+ ) }));
12
+ Table.displayName = "Table";
13
+ const TableHeader = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { className: cn("[&_tr]:border-b", className), ref, ...props }));
14
+ TableHeader.displayName = "TableHeader";
15
+ const TableBody = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
16
+ "tbody",
17
+ {
18
+ className: cn("[&_tr:last-child]:border-0", className),
19
+ ref,
20
+ ...props
21
+ }
22
+ ));
23
+ TableBody.displayName = "TableBody";
24
+ const TableFooter = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
25
+ "tfoot",
26
+ {
27
+ className: cn(
28
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
29
+ className
30
+ ),
31
+ ref,
32
+ ...props
33
+ }
34
+ ));
35
+ TableFooter.displayName = "TableFooter";
36
+ const TableRow = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
37
+ "tr",
38
+ {
39
+ className: cn(
40
+ "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
41
+ className
42
+ ),
43
+ ref,
44
+ ...props
45
+ }
46
+ ));
47
+ TableRow.displayName = "TableRow";
48
+ const TableHead = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
49
+ "th",
50
+ {
51
+ className: cn(
52
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
53
+ className
54
+ ),
55
+ ref,
56
+ ...props
57
+ }
58
+ ));
59
+ TableHead.displayName = "TableHead";
60
+ const TableCell = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
61
+ "td",
62
+ {
63
+ className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
64
+ ref,
65
+ ...props
66
+ }
67
+ ));
68
+ TableCell.displayName = "TableCell";
69
+ const TableCaption = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
70
+ "caption",
71
+ {
72
+ className: cn("mt-4 text-sm text-muted-foreground", className),
73
+ ref,
74
+ ...props
75
+ }
76
+ ));
77
+ TableCaption.displayName = "TableCaption";
78
+ export {
79
+ Table,
80
+ TableBody,
81
+ TableCaption,
82
+ TableCell,
83
+ TableFooter,
84
+ TableHead,
85
+ TableHeader,
86
+ TableRow
87
+ };
@@ -0,0 +1,4 @@
1
+ import { TableOfContents } from "./table-of-contents";
2
+ export {
3
+ TableOfContents
4
+ };
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { cn } from "../../lib/utils";
5
+ function handleClick(id) {
6
+ const element = document.querySelector(`#${id}`);
7
+ if (element) {
8
+ element.scrollIntoView({ behavior: "smooth", block: "start" });
9
+ }
10
+ }
11
+ function useActiveSection(sections) {
12
+ const [activeSection, setActiveSection] = useState(null);
13
+ useEffect(() => {
14
+ const observer = new IntersectionObserver(
15
+ (entries) => {
16
+ entries.forEach((entry) => {
17
+ if (entry.isIntersecting) {
18
+ setActiveSection(entry.target.id);
19
+ }
20
+ });
21
+ },
22
+ {
23
+ rootMargin: "-100px 0px -66% 0px",
24
+ threshold: 0
25
+ }
26
+ );
27
+ sections.forEach((section) => {
28
+ const element = document.querySelector(`#${section.id}`);
29
+ if (element) {
30
+ observer.observe(element);
31
+ }
32
+ });
33
+ return () => {
34
+ sections.forEach((section) => {
35
+ const element = document.querySelector(`#${section.id}`);
36
+ if (element) {
37
+ observer.unobserve(element);
38
+ }
39
+ });
40
+ };
41
+ }, [sections]);
42
+ return activeSection;
43
+ }
44
+ function TableOfContents({ sections }) {
45
+ const activeSection = useActiveSection(sections);
46
+ if (sections.length === 0) {
47
+ return null;
48
+ }
49
+ return /* @__PURE__ */ jsx("aside", { className: "hidden xl:block", children: /* @__PURE__ */ jsx("div", { className: "sticky top-8", children: /* @__PURE__ */ jsxs("div", { className: "border-l-2 border-border pl-4", children: [
50
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold mb-4 text-muted-foreground uppercase tracking-wider", children: "On This Page" }),
51
+ /* @__PURE__ */ jsx("nav", { className: "space-y-2", children: sections.map((section) => /* @__PURE__ */ jsx(
52
+ "button",
53
+ {
54
+ className: cn(
55
+ "block text-left text-sm transition-colors",
56
+ "hover:text-foreground",
57
+ activeSection === section.id ? "text-foreground font-medium" : "text-muted-foreground"
58
+ ),
59
+ onClick: () => {
60
+ handleClick(section.id);
61
+ },
62
+ type: "button",
63
+ children: section.title
64
+ },
65
+ section.id
66
+ )) })
67
+ ] }) }) });
68
+ }
69
+ export {
70
+ TableOfContents
71
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ TableOfContentsPanel
3
+ } from "./table-of-contents-panel";
4
+ export {
5
+ TableOfContentsPanel
6
+ };
@@ -0,0 +1,202 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { memo, useEffect, useRef } from "react";
4
+ import { cn } from "../../lib/utils";
5
+ function TableOfContentsPanelImpl({
6
+ className,
7
+ closeIcon,
8
+ completedSections,
9
+ completionCount,
10
+ currentSectionIndex,
11
+ isOpen,
12
+ onClose,
13
+ onReset,
14
+ onSelectSection,
15
+ progressLabel = "Progress",
16
+ resetLabel = "Reset Progress",
17
+ sections,
18
+ title = "Table of Contents",
19
+ totalSections
20
+ }) {
21
+ const panelRef = useRef(null);
22
+ const closeButtonRef = useRef(null);
23
+ useEffect(() => {
24
+ if (!isOpen) return;
25
+ closeButtonRef.current?.focus();
26
+ const handleKeyDown = (event) => {
27
+ if (event.key === "Escape") {
28
+ event.preventDefault();
29
+ onClose();
30
+ }
31
+ };
32
+ window.addEventListener("keydown", handleKeyDown);
33
+ return () => {
34
+ window.removeEventListener("keydown", handleKeyDown);
35
+ };
36
+ }, [isOpen, onClose]);
37
+ useEffect(() => {
38
+ document.body.style.overflow = isOpen ? "hidden" : "";
39
+ return () => {
40
+ document.body.style.overflow = "";
41
+ };
42
+ }, [isOpen]);
43
+ if (!isOpen) return null;
44
+ const completionPercent = totalSections > 0 ? Math.round(completionCount / totalSections * 100) : 0;
45
+ return /* @__PURE__ */ jsxs(
46
+ "div",
47
+ {
48
+ "aria-labelledby": "toc-title",
49
+ "aria-modal": "true",
50
+ className: "fixed inset-0 z-50",
51
+ role: "dialog",
52
+ children: [
53
+ /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ "aria-hidden": "true",
57
+ className: "absolute inset-0 bg-black/50 backdrop-blur-sm",
58
+ onClick: onClose
59
+ }
60
+ ),
61
+ /* @__PURE__ */ jsx(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "absolute right-0 top-0 h-full w-full max-w-md bg-background shadow-xl",
66
+ className
67
+ ),
68
+ ref: panelRef,
69
+ children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
70
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
71
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", id: "toc-title", children: title }),
72
+ /* @__PURE__ */ jsx(
73
+ "button",
74
+ {
75
+ "aria-label": "Close table of contents",
76
+ className: "flex h-8 w-8 items-center justify-center rounded-md hover:bg-muted",
77
+ onClick: onClose,
78
+ ref: closeButtonRef,
79
+ type: "button",
80
+ children: closeIcon ?? /* @__PURE__ */ jsx(
81
+ "svg",
82
+ {
83
+ className: "h-5 w-5",
84
+ fill: "none",
85
+ stroke: "currentColor",
86
+ viewBox: "0 0 24 24",
87
+ children: /* @__PURE__ */ jsx(
88
+ "path",
89
+ {
90
+ d: "M6 18L18 6M6 6l12 12",
91
+ strokeLinecap: "round",
92
+ strokeLinejoin: "round",
93
+ strokeWidth: 2
94
+ }
95
+ )
96
+ }
97
+ )
98
+ }
99
+ )
100
+ ] }),
101
+ /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-4 py-3", children: [
102
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
103
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: progressLabel }),
104
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
105
+ completionCount,
106
+ " / ",
107
+ totalSections,
108
+ " (",
109
+ completionPercent,
110
+ "%)"
111
+ ] })
112
+ ] }),
113
+ /* @__PURE__ */ jsx("div", { className: "mt-2 h-2 rounded-full bg-muted", children: /* @__PURE__ */ jsx(
114
+ "div",
115
+ {
116
+ className: "h-full rounded-full bg-primary transition-all duration-300",
117
+ style: { width: `${completionPercent}%` }
118
+ }
119
+ ) })
120
+ ] }),
121
+ /* @__PURE__ */ jsx(
122
+ "nav",
123
+ {
124
+ "aria-label": "Sections",
125
+ className: "flex-1 overflow-y-auto px-4 py-3",
126
+ children: /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: sections.map((section, index) => {
127
+ const isCompleted = completedSections.has(section.id);
128
+ const isCurrent = index === currentSectionIndex;
129
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
130
+ "button",
131
+ {
132
+ className: cn(
133
+ "flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm transition-colors",
134
+ isCurrent ? "bg-primary/10 text-primary font-medium" : "hover:bg-muted text-foreground"
135
+ ),
136
+ onClick: () => {
137
+ onSelectSection(index);
138
+ onClose();
139
+ },
140
+ type: "button",
141
+ children: [
142
+ /* @__PURE__ */ jsx(
143
+ "span",
144
+ {
145
+ className: cn(
146
+ "flex h-5 w-5 shrink-0 items-center justify-center rounded-full border",
147
+ isCompleted ? "border-primary bg-primary text-primary-foreground" : "border-muted-foreground"
148
+ ),
149
+ children: isCompleted ? /* @__PURE__ */ jsx(
150
+ "svg",
151
+ {
152
+ className: "h-3 w-3",
153
+ fill: "none",
154
+ stroke: "currentColor",
155
+ viewBox: "0 0 24 24",
156
+ children: /* @__PURE__ */ jsx(
157
+ "path",
158
+ {
159
+ d: "M5 13l4 4L19 7",
160
+ strokeLinecap: "round",
161
+ strokeLinejoin: "round",
162
+ strokeWidth: 2
163
+ }
164
+ )
165
+ }
166
+ ) : /* @__PURE__ */ jsx("span", { className: "text-xs", children: index + 1 })
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsx(
170
+ "span",
171
+ {
172
+ className: isCompleted ? "line-through opacity-60" : "",
173
+ children: section.title
174
+ }
175
+ )
176
+ ]
177
+ }
178
+ ) }, `${section.id}-${index}`);
179
+ }) })
180
+ }
181
+ ),
182
+ completionCount > 0 && onReset ? /* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children: /* @__PURE__ */ jsx(
183
+ "button",
184
+ {
185
+ className: "w-full rounded-md border border-border px-3 py-2 text-sm text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
186
+ onClick: onReset,
187
+ type: "button",
188
+ children: resetLabel
189
+ }
190
+ ) }) : null
191
+ ] })
192
+ }
193
+ )
194
+ ]
195
+ }
196
+ );
197
+ }
198
+ const TableOfContentsPanel = memo(TableOfContentsPanelImpl);
199
+ TableOfContentsPanel.displayName = "TableOfContentsPanel";
200
+ export {
201
+ TableOfContentsPanel
202
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ Tabs,
3
+ TabsContent,
4
+ TabsList,
5
+ TabsTrigger
6
+ } from "./tabs";
7
+ export {
8
+ Tabs,
9
+ TabsContent,
10
+ TabsList,
11
+ TabsTrigger
12
+ };
@@ -0,0 +1,84 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo, useState } from "react";
4
+ import { cn } from "../../lib/utils";
5
+ const TabsContext = createContext(null);
6
+ function useTabsContext() {
7
+ const context = useContext(TabsContext);
8
+ if (!context) {
9
+ throw new Error("Tab components must be used within a Tabs component");
10
+ }
11
+ return context;
12
+ }
13
+ function Tabs({
14
+ children,
15
+ className,
16
+ defaultValue,
17
+ onValueChange
18
+ }) {
19
+ const [activeTab, setActiveTab] = useState(defaultValue);
20
+ const handleSetActiveTab = (value) => {
21
+ setActiveTab(value);
22
+ onValueChange?.(value);
23
+ };
24
+ const contextValue = useMemo(
25
+ () => ({ activeTab, setActiveTab: handleSetActiveTab }),
26
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27
+ [activeTab]
28
+ );
29
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { className: cn("my-6", className), children }) });
30
+ }
31
+ function TabsList({ children, className }) {
32
+ return /* @__PURE__ */ jsx(
33
+ "div",
34
+ {
35
+ className: cn("flex border-b border-border overflow-x-auto", className),
36
+ role: "tablist",
37
+ children
38
+ }
39
+ );
40
+ }
41
+ function TabsTrigger({
42
+ children,
43
+ className,
44
+ value
45
+ }) {
46
+ const { activeTab, setActiveTab } = useTabsContext();
47
+ const isActive = activeTab === value;
48
+ return /* @__PURE__ */ jsx(
49
+ "button",
50
+ {
51
+ "aria-selected": isActive,
52
+ className: cn(
53
+ "px-4 py-2 text-sm font-medium whitespace-nowrap transition-colors",
54
+ "border-b-2 -mb-px",
55
+ isActive ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground hover:border-muted-foreground/50",
56
+ className
57
+ ),
58
+ onClick: () => {
59
+ setActiveTab(value);
60
+ },
61
+ role: "tab",
62
+ type: "button",
63
+ children
64
+ }
65
+ );
66
+ }
67
+ function TabsContent({
68
+ children,
69
+ className,
70
+ value
71
+ }) {
72
+ const { activeTab } = useTabsContext();
73
+ if (activeTab !== value) return null;
74
+ return /* @__PURE__ */ jsx("div", { className: cn("pt-4", className), role: "tabpanel", children });
75
+ }
76
+ Tabs.List = TabsList;
77
+ Tabs.Trigger = TabsTrigger;
78
+ Tabs.Content = TabsContent;
79
+ export {
80
+ Tabs,
81
+ TabsContent,
82
+ TabsList,
83
+ TabsTrigger
84
+ };
@@ -0,0 +1,8 @@
1
+ import {
2
+ SimpleTerminal,
3
+ Terminal
4
+ } from "./terminal";
5
+ export {
6
+ SimpleTerminal,
7
+ Terminal
8
+ };
@@ -0,0 +1,119 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { Check, Copy, Terminal as TerminalIcon } from "lucide-react";
5
+ import { Button } from "../button";
6
+ function Terminal({
7
+ copyable = true,
8
+ lines,
9
+ title = "Terminal"
10
+ }) {
11
+ const [copied, setCopied] = useState(false);
12
+ const commands = lines.filter((l) => l.type === "command").map((l) => l.content);
13
+ const handleCopy = async () => {
14
+ await navigator.clipboard.writeText(commands.join("\n"));
15
+ setCopied(true);
16
+ setTimeout(() => {
17
+ setCopied(false);
18
+ }, 2e3);
19
+ };
20
+ return /* @__PURE__ */ jsxs("div", { className: "my-6 rounded-lg border bg-zinc-950 dark:bg-zinc-900 overflow-hidden", children: [
21
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 bg-zinc-900 dark:bg-zinc-800 border-b border-zinc-800", children: [
22
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
23
+ /* @__PURE__ */ jsx(TerminalIcon, { className: "h-4 w-4 text-zinc-400" }),
24
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-300", children: title })
25
+ ] }),
26
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
27
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-red-500" }),
28
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-yellow-500" }),
29
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-green-500" })
30
+ ] })
31
+ ] }),
32
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
33
+ /* @__PURE__ */ jsx("div", { className: "p-4 font-mono text-sm space-y-1 overflow-x-auto", children: lines.map((line, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-start", children: [
34
+ line.type === "command" && /* @__PURE__ */ jsxs(Fragment, { children: [
35
+ /* @__PURE__ */ jsx("span", { className: "text-green-400 mr-2 select-none", children: "$" }),
36
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-100", children: line.content })
37
+ ] }),
38
+ line.type === "output" && /* @__PURE__ */ jsx("span", { className: "text-zinc-400", children: line.content }),
39
+ line.type === "comment" && /* @__PURE__ */ jsxs("span", { className: "text-zinc-600 italic", children: [
40
+ "# ",
41
+ line.content
42
+ ] })
43
+ ] }, index)) }),
44
+ copyable && commands.length > 0 ? /* @__PURE__ */ jsx(
45
+ Button,
46
+ {
47
+ className: "absolute top-2 right-2 h-8 w-8 bg-zinc-800 hover:bg-zinc-700 text-zinc-300",
48
+ onClick: handleCopy,
49
+ size: "icon",
50
+ variant: "ghost",
51
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
52
+ }
53
+ ) : null
54
+ ] })
55
+ ] });
56
+ }
57
+ function SimpleTerminal({
58
+ children,
59
+ title = "Terminal"
60
+ }) {
61
+ const [copied, setCopied] = useState(false);
62
+ const lines = children.trim().split("\n").map((line) => {
63
+ if (line.startsWith("$ ")) {
64
+ return { content: line.slice(2), type: "command" };
65
+ }
66
+ if (line.startsWith("# ")) {
67
+ return { content: line.slice(2), type: "comment" };
68
+ }
69
+ return { content: line, type: "output" };
70
+ });
71
+ const commands = lines.filter((l) => l.type === "command").map((l) => l.content);
72
+ const handleCopy = async () => {
73
+ await navigator.clipboard.writeText(commands.join("\n"));
74
+ setCopied(true);
75
+ setTimeout(() => {
76
+ setCopied(false);
77
+ }, 2e3);
78
+ };
79
+ return /* @__PURE__ */ jsxs("div", { className: "my-6 rounded-lg border bg-zinc-950 dark:bg-zinc-900 overflow-hidden", children: [
80
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 bg-zinc-900 dark:bg-zinc-800 border-b border-zinc-800", children: [
81
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
82
+ /* @__PURE__ */ jsx(TerminalIcon, { className: "h-4 w-4 text-zinc-400" }),
83
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-300", children: title })
84
+ ] }),
85
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
86
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-red-500" }),
87
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-yellow-500" }),
88
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full bg-green-500" })
89
+ ] })
90
+ ] }),
91
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
92
+ /* @__PURE__ */ jsx("div", { className: "p-4 font-mono text-sm space-y-1 overflow-x-auto", children: lines.map((line, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-start", children: [
93
+ line.type === "command" && /* @__PURE__ */ jsxs(Fragment, { children: [
94
+ /* @__PURE__ */ jsx("span", { className: "text-green-400 mr-2 select-none", children: "$" }),
95
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-100", children: line.content })
96
+ ] }),
97
+ line.type === "output" && /* @__PURE__ */ jsx("span", { className: "text-zinc-400", children: line.content }),
98
+ line.type === "comment" && /* @__PURE__ */ jsxs("span", { className: "text-zinc-600 italic", children: [
99
+ "# ",
100
+ line.content
101
+ ] })
102
+ ] }, index)) }),
103
+ commands.length > 0 && /* @__PURE__ */ jsx(
104
+ Button,
105
+ {
106
+ className: "absolute top-2 right-2 h-8 w-8 bg-zinc-800 hover:bg-zinc-700 text-zinc-300",
107
+ onClick: handleCopy,
108
+ size: "icon",
109
+ variant: "ghost",
110
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
111
+ }
112
+ )
113
+ ] })
114
+ ] });
115
+ }
116
+ export {
117
+ SimpleTerminal,
118
+ Terminal
119
+ };
@@ -0,0 +1,4 @@
1
+ import { Textarea } from "./textarea";
2
+ export {
3
+ Textarea
4
+ };
@@ -0,0 +1,22 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "../../lib/utils";
4
+ const Textarea = forwardRef(
5
+ ({ className, ...props }, ref) => {
6
+ return /* @__PURE__ */ jsx(
7
+ "textarea",
8
+ {
9
+ className: cn(
10
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
11
+ className
12
+ ),
13
+ ref,
14
+ ...props
15
+ }
16
+ );
17
+ }
18
+ );
19
+ Textarea.displayName = "Textarea";
20
+ export {
21
+ Textarea
22
+ };