@terrafirmagreg-team/ui 0.0.0-stage → 1.2.0

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/package.json +93 -3
  2. package/src/components/blocks/button/icon-button.tsx +49 -0
  3. package/src/components/blocks/canvas/chevron-edge.tsx +242 -0
  4. package/src/components/blocks/canvas/flow-canvas.tsx +181 -0
  5. package/src/components/blocks/canvas/flow-toolbar.tsx +33 -0
  6. package/src/components/blocks/canvas/flow-viewport.tsx +244 -0
  7. package/src/components/blocks/fit-box.tsx +26 -0
  8. package/src/components/blocks/git/github-info.tsx +78 -0
  9. package/src/components/blocks/lang/content.tsx +52 -0
  10. package/src/components/blocks/lang/flag.tsx +25 -0
  11. package/src/components/blocks/lang/link.tsx +23 -0
  12. package/src/components/blocks/lang/redirect.tsx +48 -0
  13. package/src/components/blocks/lang/switcher.tsx +54 -0
  14. package/src/components/blocks/lang/untranslated-callout.tsx +29 -0
  15. package/src/components/blocks/lang/untranslated-chip.tsx +53 -0
  16. package/src/components/blocks/link/link-preview.tsx +257 -0
  17. package/src/components/blocks/list/row.tsx +92 -0
  18. package/src/components/blocks/media/glb/model.tsx +244 -0
  19. package/src/components/blocks/media/glb/scene.tsx +373 -0
  20. package/src/components/blocks/media/glb/viewer.tsx +52 -0
  21. package/src/components/blocks/media/image.tsx +136 -0
  22. package/src/components/blocks/media/slideshow.tsx +178 -0
  23. package/src/components/blocks/nav/breadcrumb.tsx +51 -0
  24. package/src/components/blocks/nav/copy-menu.tsx +37 -0
  25. package/src/components/blocks/nav/link.tsx +86 -0
  26. package/src/components/blocks/nav/site-menu.tsx +78 -0
  27. package/src/components/blocks/nav/site-title.tsx +61 -0
  28. package/src/components/blocks/nav/switcher.tsx +206 -0
  29. package/src/components/blocks/page/empty-state.tsx +32 -0
  30. package/src/components/blocks/page/heading.tsx +54 -0
  31. package/src/components/blocks/page/pager.tsx +220 -0
  32. package/src/components/blocks/readability/fields.tsx +250 -0
  33. package/src/components/blocks/readability/menu.tsx +247 -0
  34. package/src/components/blocks/readability/track.tsx +165 -0
  35. package/src/components/blocks/search/command.tsx +80 -0
  36. package/src/components/blocks/search/dialog.tsx +724 -0
  37. package/src/components/blocks/search/provider.tsx +118 -0
  38. package/src/components/blocks/sidebar.tsx +406 -0
  39. package/src/components/blocks/sprite.tsx +231 -0
  40. package/src/components/blocks/text/format-text.tsx +110 -0
  41. package/src/components/blocks/theme/toggle.tsx +75 -0
  42. package/src/components/blocks/tooltip/hint.tsx +28 -0
  43. package/src/components/blocks/tooltip/lazy.tsx +41 -0
  44. package/src/components/blocks/viewer/controls.tsx +284 -0
  45. package/src/components/blocks/viewer/float-bar.tsx +51 -0
  46. package/src/components/layouts/layout.tsx +94 -0
  47. package/src/components/layouts/left-sidebar/content.tsx +63 -0
  48. package/src/components/layouts/left-sidebar/context.tsx +55 -0
  49. package/src/components/layouts/left-sidebar/expand.tsx +23 -0
  50. package/src/components/layouts/left-sidebar/footer.tsx +111 -0
  51. package/src/components/layouts/left-sidebar/index.ts +29 -0
  52. package/src/components/layouts/left-sidebar/items.tsx +103 -0
  53. package/src/components/layouts/left-sidebar/search.tsx +75 -0
  54. package/src/components/layouts/left-sidebar/sidebar.tsx +189 -0
  55. package/src/components/layouts/left-sidebar/tree.tsx +157 -0
  56. package/src/components/layouts/right-sidebar.tsx +96 -0
  57. package/src/components/layouts/tree-context.tsx +42 -0
  58. package/src/components/mdx/accordion.tsx +185 -0
  59. package/src/components/mdx/banner.tsx +157 -0
  60. package/src/components/mdx/callout.tsx +97 -0
  61. package/src/components/mdx/card.tsx +56 -0
  62. package/src/components/mdx/codeblock.tsx +250 -0
  63. package/src/components/mdx/collapsible.tsx +33 -0
  64. package/src/components/mdx/files.tsx +63 -0
  65. package/src/components/mdx/glow-header.tsx +54 -0
  66. package/src/components/mdx/gradient-text.tsx +28 -0
  67. package/src/components/mdx/icon.tsx +35 -0
  68. package/src/components/mdx/image-zoom.tsx +315 -0
  69. package/src/components/mdx/math.tsx +30 -0
  70. package/src/components/mdx/mermaid.tsx +23 -0
  71. package/src/components/mdx/multiblock.tsx +19 -0
  72. package/src/components/mdx/preview.tsx +101 -0
  73. package/src/components/mdx/steps.tsx +10 -0
  74. package/src/components/mdx/table.tsx +14 -0
  75. package/src/components/mdx/tabs.tsx +354 -0
  76. package/src/components/mdx/type-table.tsx +171 -0
  77. package/src/components/provider.tsx +139 -0
  78. package/src/components/ui/accordion.tsx +71 -0
  79. package/src/components/ui/alert-dialog.tsx +187 -0
  80. package/src/components/ui/alert.tsx +75 -0
  81. package/src/components/ui/aspect-ratio.tsx +22 -0
  82. package/src/components/ui/attachment.tsx +207 -0
  83. package/src/components/ui/avatar.tsx +108 -0
  84. package/src/components/ui/badge.tsx +51 -0
  85. package/src/components/ui/breadcrumb.tsx +124 -0
  86. package/src/components/ui/bubble.tsx +127 -0
  87. package/src/components/ui/button-group.tsx +87 -0
  88. package/src/components/ui/button.tsx +57 -0
  89. package/src/components/ui/calendar.tsx +221 -0
  90. package/src/components/ui/card.tsx +102 -0
  91. package/src/components/ui/carousel.tsx +242 -0
  92. package/src/components/ui/chart.tsx +371 -0
  93. package/src/components/ui/checkbox.tsx +28 -0
  94. package/src/components/ui/collapsible.tsx +21 -0
  95. package/src/components/ui/combobox.tsx +297 -0
  96. package/src/components/ui/command.tsx +198 -0
  97. package/src/components/ui/context-menu.tsx +270 -0
  98. package/src/components/ui/dialog.tsx +160 -0
  99. package/src/components/ui/direction.tsx +6 -0
  100. package/src/components/ui/drawer.tsx +227 -0
  101. package/src/components/ui/dropdown-menu.tsx +269 -0
  102. package/src/components/ui/empty.tsx +103 -0
  103. package/src/components/ui/field.tsx +238 -0
  104. package/src/components/ui/hover-card.tsx +50 -0
  105. package/src/components/ui/input-group.tsx +158 -0
  106. package/src/components/ui/input-otp.tsx +86 -0
  107. package/src/components/ui/input.tsx +19 -0
  108. package/src/components/ui/item.tsx +201 -0
  109. package/src/components/ui/kbd.tsx +26 -0
  110. package/src/components/ui/label.tsx +19 -0
  111. package/src/components/ui/marker.tsx +70 -0
  112. package/src/components/ui/menubar.tsx +280 -0
  113. package/src/components/ui/message-scroller.tsx +131 -0
  114. package/src/components/ui/message.tsx +91 -0
  115. package/src/components/ui/native-select.tsx +60 -0
  116. package/src/components/ui/navigation-menu.tsx +167 -0
  117. package/src/components/ui/pagination.tsx +130 -0
  118. package/src/components/ui/popover.tsx +91 -0
  119. package/src/components/ui/progress.tsx +82 -0
  120. package/src/components/ui/questionnaire.tsx +324 -0
  121. package/src/components/ui/radio-group.tsx +37 -0
  122. package/src/components/ui/resizable.tsx +49 -0
  123. package/src/components/ui/scroll-area.tsx +54 -0
  124. package/src/components/ui/select.tsx +200 -0
  125. package/src/components/ui/separator.tsx +24 -0
  126. package/src/components/ui/sheet.tsx +138 -0
  127. package/src/components/ui/sidebar.tsx +730 -0
  128. package/src/components/ui/skeleton.tsx +13 -0
  129. package/src/components/ui/slider.tsx +51 -0
  130. package/src/components/ui/spinner.tsx +10 -0
  131. package/src/components/ui/switch.tsx +31 -0
  132. package/src/components/ui/table.tsx +115 -0
  133. package/src/components/ui/tabs.tsx +81 -0
  134. package/src/components/ui/textarea.tsx +17 -0
  135. package/src/components/ui/toast.tsx +234 -0
  136. package/src/components/ui/toggle-group.tsx +89 -0
  137. package/src/components/ui/toggle.tsx +44 -0
  138. package/src/components/ui/tooltip.tsx +65 -0
  139. package/src/hooks/canvas/use-flow-hover.ts +19 -0
  140. package/src/hooks/canvas/use-flow-viewport-persist.ts +34 -0
  141. package/src/hooks/page/use-fit-pages.ts +92 -0
  142. package/src/hooks/page/use-location-search.ts +31 -0
  143. package/src/hooks/page/use-page-preview.ts +41 -0
  144. package/src/hooks/page/use-paged-list.ts +21 -0
  145. package/src/hooks/readability/use-readability.ts +87 -0
  146. package/src/hooks/search/use-dialog.ts +42 -0
  147. package/src/hooks/search/use-highlight-query.ts +58 -0
  148. package/src/hooks/search/use-provider.ts +26 -0
  149. package/src/hooks/use-async-value.ts +60 -0
  150. package/src/hooks/use-close-on-scroll.ts +24 -0
  151. package/src/hooks/use-copy-button.ts +47 -0
  152. package/src/hooks/use-cycle-index.ts +76 -0
  153. package/src/hooks/use-document-title.ts +10 -0
  154. package/src/hooks/use-element-size.ts +36 -0
  155. package/src/hooks/use-external-meta.ts +133 -0
  156. package/src/hooks/use-hot-key.ts +34 -0
  157. package/src/hooks/use-hover-follow.ts +55 -0
  158. package/src/hooks/use-in-view.ts +31 -0
  159. package/src/hooks/use-lang.ts +9 -0
  160. package/src/hooks/use-last-value.ts +16 -0
  161. package/src/hooks/use-layout.ts +19 -0
  162. package/src/hooks/use-marquee.ts +52 -0
  163. package/src/hooks/use-media-query.ts +15 -0
  164. package/src/hooks/use-mobile.ts +20 -0
  165. package/src/hooks/use-modifier-keys.ts +32 -0
  166. package/src/hooks/use-on-change.ts +36 -0
  167. package/src/hooks/use-pane-keys.ts +29 -0
  168. package/src/hooks/use-sidebar.ts +64 -0
  169. package/src/hooks/use-swipe.ts +27 -0
  170. package/src/hooks/use-tree.ts +100 -0
  171. package/src/hooks/viewer/use-in-float-bar.ts +7 -0
  172. package/src/hooks/viewer/use-viewer-prefs.ts +78 -0
  173. package/src/lib/canvas/edge.ts +202 -0
  174. package/src/lib/canvas/geometry.ts +54 -0
  175. package/src/lib/canvas/state.ts +48 -0
  176. package/src/lib/canvas/viewport.ts +38 -0
  177. package/src/lib/canvas/xyflow.ts +2 -0
  178. package/src/lib/config.ts +106 -0
  179. package/src/lib/mdx/callout.ts +21 -0
  180. package/src/lib/mdx/gradient.ts +16 -0
  181. package/src/lib/mdx/mermaid.ts +15 -0
  182. package/src/lib/media/crop-opaque.ts +77 -0
  183. package/src/lib/media/nearby-indexes.ts +7 -0
  184. package/src/lib/media/trim-transparent.ts +118 -0
  185. package/src/lib/readability/config.ts +11 -0
  186. package/src/lib/readability/spotlight.ts +187 -0
  187. package/src/lib/readability/store.ts +147 -0
  188. package/src/lib/tree.ts +90 -0
  189. package/src/lib/utils/cn.ts +2 -0
  190. package/src/lib/utils/format.ts +22 -0
  191. package/src/lib/utils/highlight-style.ts +10 -0
  192. package/src/lib/utils/history.ts +10 -0
  193. package/src/lib/utils/merge-refs.ts +14 -0
  194. package/src/lib/utils/nav-active.ts +59 -0
  195. package/src/lib/utils/stored-value.ts +137 -0
  196. package/src/lib/utils/urls.ts +18 -0
  197. package/src/locales/en_us.json +110 -0
  198. package/src/locales/pl_pl.json +33 -0
  199. package/src/locales/ru_ru.json +110 -0
  200. package/src/locales/uk_ua.json +33 -0
  201. package/src/locales/zh_cn.json +15 -0
  202. package/src/locales/zh_tw.json +15 -0
  203. package/src/locales.ts +6 -0
  204. package/src/types/canvas.ts +54 -0
  205. package/src/types/glb.ts +26 -0
  206. package/src/types/mdx-directives.ts +106 -0
  207. package/src/types/nav.ts +96 -0
  208. package/src/types/preview.ts +15 -0
  209. package/src/types/readability.ts +29 -0
  210. package/src/types/search.ts +57 -0
  211. package/src/types/tree.ts +19 -0
  212. package/src/types/viewer.ts +54 -0
  213. package/styles/content/base.css +198 -0
  214. package/styles/content/default-colors.css +51 -0
  215. package/styles/content/shiki.css +107 -0
  216. package/styles/content/typography.mjs +3637 -0
  217. package/styles/content.css +5 -0
  218. package/styles/image-zoom.css +83 -0
  219. package/styles/layout.css +28 -0
  220. package/styles/left-sidebar.css +140 -0
  221. package/styles/readability.css +50 -0
  222. package/styles/right-sidebar.css +6 -0
  223. package/styles/workspace.css +26 -0
  224. package/styles.css +430 -0
  225. package/README.md +0 -3
@@ -0,0 +1,250 @@
1
+ 'use client';
2
+ import { Check, Clipboard } from 'lucide-react';
3
+ import {
4
+ type ComponentProps,
5
+ type CSSProperties,
6
+ createContext,
7
+ type HTMLAttributes,
8
+ type ReactNode,
9
+ type RefObject,
10
+ use,
11
+ useMemo,
12
+ useRef,
13
+ } from 'react';
14
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
15
+ import { useCopyButton } from '@terrafirmagreg-team/ui/hooks/use-copy-button';
16
+ import { buttonVariants } from '@terrafirmagreg-team/ui/components/ui/button';
17
+ import { useTranslations } from '@terrafirmagreg-team/translate/hooks/use-translations';
18
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from './tabs';
19
+ import { mergeRefs } from '@terrafirmagreg-team/ui/lib/utils/merge-refs';
20
+
21
+ export interface CodeBlockProps extends Omit<ComponentProps<'figure'>, 'title'> {
22
+ title?: ReactNode;
23
+
24
+ icon?: ReactNode;
25
+
26
+ allowCopy?: boolean | 'true' | 'false';
27
+
28
+ keepBackground?: boolean;
29
+
30
+ viewportProps?: HTMLAttributes<HTMLElement>;
31
+
32
+ 'data-line-numbers'?: boolean;
33
+
34
+ 'data-line-numbers-start'?: number;
35
+
36
+ Actions?: (props: { className?: string; children?: ReactNode }) => ReactNode;
37
+ }
38
+
39
+ const TabsContext = createContext<{
40
+ containerRef: RefObject<HTMLDivElement | null>;
41
+ nested: boolean;
42
+ } | null>(null);
43
+
44
+ export function Pre(props: ComponentProps<'pre'>) {
45
+ return (
46
+ <pre {...props} className={cn('min-w-full w-max *:flex *:flex-col', props.className)}>
47
+ {props.children}
48
+ </pre>
49
+ );
50
+ }
51
+
52
+ export function CodeBlock({
53
+ ref,
54
+ title,
55
+ allowCopy = true,
56
+ keepBackground = false,
57
+ icon,
58
+ viewportProps = {},
59
+ children,
60
+ Actions = (props) => <div {...props} className={cn('empty:hidden', props.className)} />,
61
+ ...props
62
+ }: CodeBlockProps) {
63
+ const inTab = use(TabsContext) !== null;
64
+ const areaRef = useRef<HTMLDivElement>(null);
65
+ if (allowCopy === 'true') allowCopy = true;
66
+ else if (allowCopy === 'false') allowCopy = false;
67
+ return (
68
+ <figure
69
+ ref={ref}
70
+ dir="ltr"
71
+ {...props}
72
+ tabIndex={-1}
73
+ className={cn(
74
+ inTab ? 'bg-secondary -mx-px -mb-px last:rounded-b-xl' : 'my-4 bg-card rounded-xl',
75
+ keepBackground && 'bg-(--shiki-light-bg) dark:bg-(--shiki-dark-bg)',
76
+
77
+ 'shiki relative border not-prose overflow-hidden text-sm',
78
+ props.className,
79
+ )}
80
+ >
81
+ {title ? (
82
+ <div className="flex text-muted-foreground items-center gap-2 h-9.5 border-b px-4">
83
+ {typeof icon === 'string' ? (
84
+ <div
85
+ className="[&_svg]:size-3.5"
86
+ dangerouslySetInnerHTML={{
87
+ __html: icon,
88
+ }}
89
+ />
90
+ ) : (
91
+ icon
92
+ )}
93
+ <figcaption className="flex-1 truncate">{title}</figcaption>
94
+ {Actions({
95
+ className: '-me-2',
96
+ children: allowCopy && <CopyButton containerRef={areaRef} />,
97
+ })}
98
+ </div>
99
+ ) : (
100
+ Actions({
101
+ className:
102
+ 'absolute top-2 right-2 z-2 backdrop-blur-lg rounded-lg text-muted-foreground',
103
+ children: allowCopy && <CopyButton containerRef={areaRef} />,
104
+ })
105
+ )}
106
+ <div
107
+ ref={areaRef}
108
+ {...viewportProps}
109
+ role="region"
110
+ tabIndex={0}
111
+ className={cn(
112
+ 'text-[0.8125rem] py-3.5 overflow-auto max-h-[600px] scroll-container focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',
113
+ viewportProps.className,
114
+ )}
115
+ style={
116
+ {
117
+
118
+ '--padding-right': !title ? 'calc(var(--spacing) * 8)' : undefined,
119
+ counterSet: props['data-line-numbers']
120
+ ? `line ${Number(props['data-line-numbers-start'] ?? 1) - 1}`
121
+ : undefined,
122
+ ...viewportProps.style,
123
+ } as CSSProperties
124
+ }
125
+ >
126
+ {children}
127
+ </div>
128
+ </figure>
129
+ );
130
+ }
131
+
132
+ function CopyButton({
133
+ className,
134
+ containerRef,
135
+ ...props
136
+ }: ComponentProps<'button'> & {
137
+ containerRef: RefObject<HTMLElement | null>;
138
+ }) {
139
+ const t = useTranslations();
140
+ const { checked, onClick } = useCopyButton(() => {
141
+ const pre = containerRef.current?.getElementsByTagName('pre').item(0);
142
+ if (!pre) return;
143
+
144
+ const clone = pre.cloneNode(true) as HTMLElement;
145
+ clone.querySelectorAll('.copy-ignore, .nd-copy-ignore').forEach((node) => {
146
+ node.replaceWith('\n');
147
+ });
148
+
149
+ return navigator.clipboard.writeText(clone.textContent ?? '');
150
+ });
151
+
152
+ return (
153
+ <button
154
+ type="button"
155
+ data-checked={checked || undefined}
156
+ className={cn(
157
+ buttonVariants({
158
+ variant: 'ghost',
159
+ className: 'hover:text-accent-foreground data-checked:text-accent-foreground',
160
+ size: 'icon-xs',
161
+ }),
162
+ className,
163
+ )}
164
+ aria-live="polite"
165
+ onClick={onClick}
166
+ {...props}
167
+ >
168
+ {checked ? <Check /> : <Clipboard />}
169
+ <span className="sr-only">
170
+ {checked
171
+ ? t('Copied Text', { note: 'ui.copied_text' })
172
+ : t('Copy Text', { note: 'ui.copy_text' })}
173
+ </span>
174
+ </button>
175
+ );
176
+ }
177
+
178
+ export function CodeBlockTabs({ ref, className, ...props }: ComponentProps<typeof Tabs>) {
179
+ const containerRef = useRef<HTMLDivElement>(null);
180
+ const nested = use(TabsContext) !== null;
181
+
182
+ return (
183
+ <Tabs
184
+ ref={mergeRefs(containerRef, ref)}
185
+ {...props}
186
+ className={(s) =>
187
+ cn(
188
+ 'bg-card rounded-xl border',
189
+ !nested && 'my-4',
190
+ typeof className === 'function' ? className(s) : className,
191
+ )
192
+ }
193
+ >
194
+ <TabsContext
195
+ value={useMemo(
196
+ () => ({
197
+ containerRef,
198
+ nested,
199
+ }),
200
+ [nested],
201
+ )}
202
+ >
203
+ {props.children}
204
+ </TabsContext>
205
+ </Tabs>
206
+ );
207
+ }
208
+
209
+ export function CodeBlockTabsList({ className, ...props }: ComponentProps<typeof TabsList>) {
210
+ return (
211
+ <TabsList
212
+ {...props}
213
+ className={(s) =>
214
+ cn(
215
+ 'flex flex-row px-2 overflow-x-auto text-muted-foreground',
216
+ typeof className === 'function' ? className(s) : className,
217
+ )
218
+ }
219
+ >
220
+ {props.children}
221
+ </TabsList>
222
+ );
223
+ }
224
+
225
+ export function CodeBlockTabsTrigger({
226
+ children,
227
+ className,
228
+ ...props
229
+ }: ComponentProps<typeof TabsTrigger>) {
230
+ return (
231
+ <TabsTrigger
232
+ {...props}
233
+ className={(s) =>
234
+ cn(
235
+ 'relative group inline-flex text-sm font-medium text-nowrap items-center transition-colors gap-2 px-2 py-1.5 [&_svg]:size-3.5 border-b-0',
236
+ s.active ? 'text-primary' : 'hover:text-accent-foreground',
237
+ typeof className === 'function' ? className(s) : className,
238
+ )
239
+ }
240
+ >
241
+ <div className="absolute inset-x-2 bottom-0 h-px group-data-active:bg-primary" />
242
+ {children}
243
+ </TabsTrigger>
244
+ );
245
+ }
246
+
247
+ export function CodeBlockTab(props: ComponentProps<typeof TabsContent>) {
248
+ return <TabsContent {...props} />;
249
+ }
250
+
@@ -0,0 +1,33 @@
1
+ 'use client';
2
+ import { Collapsible as Primitive } from '@base-ui/react/collapsible';
3
+ import type { ComponentProps } from 'react';
4
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
5
+
6
+ export const Collapsible = Primitive.Root;
7
+
8
+ export const CollapsibleTrigger = Primitive.Trigger;
9
+
10
+ export function CollapsibleContent({
11
+ children,
12
+ className,
13
+ ...props
14
+ }: ComponentProps<typeof Primitive.Panel>) {
15
+ return (
16
+ <Primitive.Panel
17
+ {...props}
18
+ className={(s) =>
19
+ cn(
20
+ "overflow-hidden [&[hidden]:not([hidden='until-found'])]:hidden h-(--collapsible-panel-height) transition-[height,opacity] data-starting-style:opacity-0 data-starting-style:h-0 data-ending-style:h-0 data-ending-style:opacity-0",
21
+ typeof className === 'function' ? className(s) : className,
22
+ )
23
+ }
24
+ >
25
+ {children}
26
+ </Primitive.Panel>
27
+ );
28
+ }
29
+
30
+ export type CollapsibleProps = Primitive.Root.Props;
31
+ export type CollapsibleContentProps = Primitive.Panel.Props;
32
+ export type CollapsibleTriggerProps = Primitive.Trigger.Props;
33
+
@@ -0,0 +1,63 @@
1
+ 'use client';
2
+
3
+ import { cva } from 'class-variance-authority';
4
+ import { FileIcon, FolderIcon, FolderOpen } from 'lucide-react';
5
+ import { type HTMLAttributes, type ReactNode, useState } from 'react';
6
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
7
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './collapsible';
8
+
9
+ const itemVariants = cva(
10
+ 'flex flex-row items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground [&_svg]:size-4',
11
+ );
12
+
13
+ export function Files({ className, ...props }: HTMLAttributes<HTMLDivElement>): React.ReactElement {
14
+ return (
15
+ <div className={cn('not-prose rounded-md border bg-card p-2', className)} {...props}>
16
+ {props.children}
17
+ </div>
18
+ );
19
+ }
20
+
21
+ export interface FileProps extends HTMLAttributes<HTMLDivElement> {
22
+ name: string;
23
+ icon?: ReactNode;
24
+ }
25
+
26
+ export interface FolderProps extends HTMLAttributes<HTMLDivElement> {
27
+ name: string;
28
+
29
+ disabled?: boolean;
30
+
31
+ defaultOpen?: boolean;
32
+ }
33
+
34
+ export function File({
35
+ name,
36
+ icon = <FileIcon />,
37
+ className,
38
+ ...rest
39
+ }: FileProps): React.ReactElement {
40
+ return (
41
+ <div className={cn(itemVariants({ className }))} {...rest}>
42
+ {icon}
43
+ {name}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ export function Folder({ name, defaultOpen = false, ...props }: FolderProps): React.ReactElement {
49
+ const [open, setOpen] = useState(defaultOpen);
50
+
51
+ return (
52
+ <Collapsible open={open} onOpenChange={setOpen} {...props}>
53
+ <CollapsibleTrigger className={cn(itemVariants({ className: 'w-full' }))}>
54
+ {open ? <FolderOpen /> : <FolderIcon />}
55
+ {name}
56
+ </CollapsibleTrigger>
57
+ <CollapsibleContent>
58
+ <div className="ms-2 flex flex-col border-l ps-2">{props.children}</div>
59
+ </CollapsibleContent>
60
+ </Collapsible>
61
+ );
62
+ }
63
+
@@ -0,0 +1,54 @@
1
+ import type { ComponentProps } from 'react';
2
+ import { gradientImage, type GradientProps } from '@terrafirmagreg-team/ui/lib/mdx/gradient';
3
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
4
+
5
+ export function GlowHeader({
6
+ fade,
7
+ gradient,
8
+ from,
9
+ to,
10
+ dir,
11
+ image,
12
+ style,
13
+ className,
14
+ children,
15
+ ...props
16
+ }: GradientProps & { fade?: boolean; gradient?: boolean } & ComponentProps<'span'>) {
17
+ const boxFrom = from ?? '#fa18cf';
18
+ const boxTo = to ?? '#ff7967';
19
+ const gradientBg = gradientImage({ from, to, dir, image });
20
+ const boxBg = `radial-gradient(color-mix(in srgb, ${boxFrom} 18%, transparent), color-mix(in srgb, ${boxTo} 8%, transparent))`;
21
+ return (
22
+ <span
23
+ className={cn(
24
+ 'relative mb-6 inline-block rounded-[20px] px-4 py-2.5 text-center',
25
+ className,
26
+ )}
27
+ style={{
28
+ backgroundImage: gradient ? `${gradientBg}, ${boxBg}` : boxBg,
29
+ ...(gradient && {
30
+ WebkitBackgroundClip: 'text, border-box',
31
+ backgroundClip: 'text, border-box',
32
+ WebkitTextFillColor: 'transparent',
33
+ }),
34
+ boxShadow: `0 10px 20px color-mix(in srgb, ${boxFrom} 25%, transparent)`,
35
+ ...style,
36
+ }}
37
+ {...props}
38
+ >
39
+ {children}
40
+ {fade && (
41
+ <span
42
+ aria-hidden
43
+ className="pointer-events-none absolute inset-x-4 -bottom-0.5 h-0.5 rounded-full"
44
+ style={{
45
+ backgroundImage: gradientBg,
46
+ maskImage:
47
+ 'linear-gradient(to right, transparent, black 25%, black 75%, transparent)',
48
+ }}
49
+ />
50
+ )}
51
+ </span>
52
+ );
53
+ }
54
+
@@ -0,0 +1,28 @@
1
+ import type { ComponentProps } from 'react';
2
+ import { gradientImage, type GradientProps } from '@terrafirmagreg-team/ui/lib/mdx/gradient';
3
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
4
+
5
+ export function GradientText({
6
+ from,
7
+ to,
8
+ dir,
9
+ image,
10
+ style,
11
+ className,
12
+ ...props
13
+ }: GradientProps & ComponentProps<'span'>) {
14
+ return (
15
+ <span
16
+ className={cn('text-transparent', className)}
17
+ style={{
18
+ backgroundImage: gradientImage({ from, to, dir, image }),
19
+ WebkitBackgroundClip: 'text',
20
+ backgroundClip: 'text',
21
+ WebkitTextFillColor: 'transparent',
22
+ ...style,
23
+ }}
24
+ {...props}
25
+ />
26
+ );
27
+ }
28
+
@@ -0,0 +1,35 @@
1
+ import { icons, type LucideProps } from 'lucide-react';
2
+ import * as SI from '@icons-pack/react-simple-icons';
3
+ import type { ComponentType } from 'react';
4
+ import { cn } from '@terrafirmagreg-team/ui/lib/utils/cn';
5
+
6
+ const registry = icons as Record<string, ComponentType<LucideProps>>;
7
+ const brands = SI as unknown as Record<string, ComponentType<LucideProps>>;
8
+
9
+ function toPascal(name: string): string {
10
+ return name
11
+ .split(/[-_\s]+/)
12
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
13
+ .join('');
14
+ }
15
+
16
+ export function Icon({
17
+ name,
18
+ className,
19
+ ...props
20
+ }: { name: string } & LucideProps) {
21
+ const Component =
22
+ registry[name] ?? registry[toPascal(name)] ?? brands[`Si${toPascal(name)}`];
23
+ if (!Component) return null;
24
+ return (
25
+ <Component
26
+ className={cn(
27
+ 'inline-block align-[-0.125em]',
28
+ props.size === undefined && 'size-[1em]',
29
+ className,
30
+ )}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+