torch-glare 1.0.2

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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/cli/bin/addComponent.js +278 -0
  4. package/cli/bin/addHooks.js +75 -0
  5. package/cli/bin/addLayout.js +71 -0
  6. package/cli/bin/addProvider.js +71 -0
  7. package/cli/bin/addUtils.js +74 -0
  8. package/cli/bin/cli.js +73 -0
  9. package/cli/bin/init/init.js +15 -0
  10. package/cli/bin/init/tailwindInit.js +174 -0
  11. package/cli/bin/update.js +147 -0
  12. package/lib/components/ActionButton.tsx +63 -0
  13. package/lib/components/ActionsGroup.tsx +34 -0
  14. package/lib/components/AlertDialog.tsx +211 -0
  15. package/lib/components/Badge.tsx +116 -0
  16. package/lib/components/BadgeField.tsx +192 -0
  17. package/lib/components/Button.tsx +277 -0
  18. package/lib/components/Card.tsx +63 -0
  19. package/lib/components/Checkbox.tsx +122 -0
  20. package/lib/components/CountBadge.tsx +54 -0
  21. package/lib/components/DatePicker.tsx +464 -0
  22. package/lib/components/Drawer.tsx +118 -0
  23. package/lib/components/DropdownMenu.tsx +399 -0
  24. package/lib/components/FieldHint.tsx +76 -0
  25. package/lib/components/ImageAttachment.tsx +180 -0
  26. package/lib/components/InnerLabelField.tsx +155 -0
  27. package/lib/components/Input.tsx +179 -0
  28. package/lib/components/InputField.tsx +147 -0
  29. package/lib/components/Label.tsx +107 -0
  30. package/lib/components/LabelField.tsx +75 -0
  31. package/lib/components/LabeledCheckBox.tsx +65 -0
  32. package/lib/components/LabeledRadio.tsx +45 -0
  33. package/lib/components/LinkButton.tsx +94 -0
  34. package/lib/components/LoginButton.tsx +56 -0
  35. package/lib/components/PasswordLevel.tsx +58 -0
  36. package/lib/components/Popover.tsx +274 -0
  37. package/lib/components/ProfileMenu.tsx +90 -0
  38. package/lib/components/Radio.tsx +77 -0
  39. package/lib/components/RadioCard.tsx +72 -0
  40. package/lib/components/RingLoading.tsx +190 -0
  41. package/lib/components/SearchField.tsx +49 -0
  42. package/lib/components/Select.tsx +417 -0
  43. package/lib/components/SlideDatePicker.tsx +120 -0
  44. package/lib/components/SpinLoading.tsx +190 -0
  45. package/lib/components/Switcher.tsx +56 -0
  46. package/lib/components/TabFormItem.tsx +158 -0
  47. package/lib/components/Table.tsx +395 -0
  48. package/lib/components/Textarea.tsx +108 -0
  49. package/lib/components/Tooltip.tsx +111 -0
  50. package/lib/components/TransparentLabel.tsx +72 -0
  51. package/lib/components/TreeDropDown.tsx +69 -0
  52. package/lib/hooks/MobileSlidePicker/components/Picker.tsx +218 -0
  53. package/lib/hooks/MobileSlidePicker/components/PickerColumn.tsx +238 -0
  54. package/lib/hooks/MobileSlidePicker/components/PickerItem.tsx +64 -0
  55. package/lib/hooks/MobileSlidePicker/index.ts +10 -0
  56. package/lib/hooks/useActiveTreeItem.tsx +61 -0
  57. package/lib/hooks/useClickOutside.tsx +20 -0
  58. package/lib/hooks/useResize.tsx +78 -0
  59. package/lib/layouts/CLayout.tsx +326 -0
  60. package/lib/layouts/FieldSection.tsx +64 -0
  61. package/lib/layouts/TreeSubLayout.tsx +187 -0
  62. package/lib/providers/ThemeProvider.tsx +99 -0
  63. package/lib/utils/cn.ts +6 -0
  64. package/lib/utils/convertImageFileToDataUrl.ts +17 -0
  65. package/lib/utils/resize.ts +35 -0
  66. package/lib/utils/types.ts +12 -0
  67. package/package.json +28 -0
  68. package/torch-glare.js +24 -0
@@ -0,0 +1,78 @@
1
+ import {
2
+ MutableRefObject,
3
+ RefObject,
4
+ useEffect,
5
+ useState,
6
+ } from "react";
7
+ import { calculateNewWidthFromMouse, calculateNewWidthFromTouch } from "../utils/resize";
8
+
9
+
10
+ // Hook to handle resizing with RTL support
11
+ export const useResize = (
12
+ resizableRef: MutableRefObject<HTMLElement> | RefObject<HTMLElement>
13
+ ) => {
14
+ const [width, setWidth] = useState<number>();
15
+ const [isResizing, setIsResizing] = useState<boolean>(false);
16
+ const [isRTL, setIsRTL] = useState<boolean>(false);
17
+
18
+
19
+
20
+ // Start the resize process
21
+ const handleStartResize = () => {
22
+ setIsResizing(true);
23
+ };
24
+
25
+ // Stop the resize process
26
+ const handleStopResize = () => {
27
+ setIsResizing(false);
28
+ };
29
+
30
+ // Handle mouse move events
31
+ const handleMouseMove = (event: MouseEvent) => {
32
+ if (!isResizing) return;
33
+ const newWidth = calculateNewWidthFromMouse(event, resizableRef, isRTL);
34
+ setWidth(newWidth);
35
+ };
36
+
37
+ // Handle touch move events
38
+ const handleTouchMove = (event: TouchEvent) => {
39
+ if (!isResizing) return;
40
+ event.preventDefault(); // Prevent scrolling or other touch-related behaviors
41
+ const newWidth = calculateNewWidthFromTouch(event, resizableRef, isRTL);
42
+ setWidth(newWidth);
43
+ };
44
+
45
+ useEffect(() => {
46
+ let htmlDir = ''
47
+ if (document) {
48
+ htmlDir = document.documentElement.getAttribute("dir") || "ltr"
49
+ }
50
+ // Determine the direction of the document
51
+ setIsRTL(htmlDir === "rtl");
52
+ }, []);
53
+
54
+ useEffect(() => {
55
+ if (!resizableRef.current) return;
56
+
57
+ // Add event listeners for mouse and touch events
58
+ document.addEventListener("mousemove", handleMouseMove);
59
+ document.addEventListener("mouseup", handleStopResize);
60
+ document.addEventListener("touchmove", handleTouchMove, { passive: false });
61
+ document.addEventListener("touchend", handleStopResize);
62
+
63
+ // Cleanup event listeners on unmount
64
+ return () => {
65
+ document.removeEventListener("mousemove", handleMouseMove);
66
+ document.removeEventListener("mouseup", handleStopResize);
67
+ document.removeEventListener("touchmove", handleTouchMove);
68
+ document.removeEventListener("touchend", handleStopResize);
69
+ };
70
+ }, [isResizing, isRTL]); // Depend on `isRtl` to handle direction changes dynamically
71
+
72
+ return {
73
+ width,
74
+ isResizing,
75
+ handleStartResize,
76
+ };
77
+ };
78
+
@@ -0,0 +1,326 @@
1
+ import React, { HTMLAttributes, ReactNode, ButtonHTMLAttributes } from "react";
2
+ import { cn } from "../utils/cn";
3
+ import { Themes } from "../utils/types";
4
+ import { cva, VariantProps } from "class-variance-authority";
5
+ import { Slot } from "@radix-ui/react-slot";
6
+ import Counter from "../components/CountBadge";
7
+ import { Tooltip } from "../components/Tooltip";
8
+
9
+ interface LayoutProps
10
+ extends HTMLAttributes<HTMLDivElement> {
11
+ }
12
+ function Layout({ ...props }: LayoutProps) {
13
+ return (
14
+ <section {...props} className="flex h-screen gap-[10px] bg-background-system-body-base lg:p-[16px]">
15
+ {props.children}
16
+ </section>
17
+ );
18
+ }
19
+
20
+
21
+ interface BodyProps
22
+ extends HTMLAttributes<HTMLDivElement> {
23
+ }
24
+ function Body({ ...props }: BodyProps) {
25
+ return (
26
+ <main {...props} className={cn("flex flex-grow flex-1 overflow-hidden", props.className)}>
27
+ <div className="flex lg:rounded-xl bg-background-system-body-tertiary shadow-[0px_0px_18px_0px_rgba(0,0,0,0.75)] flex-1 flex-grow lg:p-1">
28
+ <div
29
+ className="lg:rounded-lg flex-1 flex-grow overflow-scroll scrollbar-hide lg:p-[2px] lg:bg-[linear-gradient(130deg,var(--blue-sparkle-600)_0px,rgba(44,45,46,1)_46px)]"
30
+ >
31
+ {props.children}
32
+ </div>
33
+ </div>
34
+ </main>
35
+ );
36
+ }
37
+
38
+
39
+ interface SideBarProps
40
+ extends HTMLAttributes<HTMLDivElement> {
41
+ iconButtons?: ReactNode
42
+ headerChild?: ReactNode
43
+ navigationChildren?: ReactNode
44
+ footerChildren?: ReactNode
45
+ children?: ReactNode
46
+ }
47
+ function SideBar({ children, footerChildren, headerChild, navigationChildren, iconButtons, ...props }: SideBarProps) {
48
+ return (
49
+ <aside
50
+ {...props}
51
+ className={cn("hidden w-[265px] p-1 flex-shrink-0 items-start rounded-xl bg-background-system-body-tertiary shadow-[0px_0px_18px_0px_rgba(0,0,0,0.75)] h-full lg:flex", props.className)}
52
+ >
53
+ <div className={cn("grid grid-rows-[56px_1fr] w-full rounded-lg border border-border-system-global-primary h-full gap-[1px]", {
54
+ "flex": children
55
+ })}>
56
+ {children ? (
57
+ children
58
+ ) : (
59
+ <>
60
+ <div className="bg-background-system-body-base w-full h-full rounded-t-lg flex justify-center items-center">
61
+ {headerChild}
62
+ </div>
63
+
64
+ <div className="grid grid-cols-[46px_1fr] gap-[1px] w-full h-full rounded-b-lg overflow-hidden">
65
+ {/* Icon Buttons Section */}
66
+ <div className="scrollbar-hide overflow-scroll flex flex-col justify-start items-center gap-[3px] w-[46px] h-full bg-background-system-body-base rounded-bl-lg rtl:rounded-br-lg rtl:rounded-bl-none">
67
+ {iconButtons}
68
+ </div>
69
+
70
+ {/* Navigation Section */}
71
+ <div className="scrollbar-hide h-full gap-[1px] overflow-scroll grid grid-rows-[1fr_auto] grid-cols-1 rounded-br-lg rtl:rounded-bl-lg rtl:rounded-br-none">
72
+ <div className="flex flex-col h-full overflow-scroll scrollbar-hide"
73
+ >
74
+ <div className="flex flex-col gap-[1px] overflow-scroll scrollbar-hide">
75
+ {Array.isArray(navigationChildren) ? (
76
+ navigationChildren.map((child, index) => (
77
+ <SideBarChildContainer key={index}>{child}</SideBarChildContainer>
78
+ ))
79
+ ) : (
80
+ navigationChildren
81
+ )}
82
+ </div>
83
+ <SideBarChildContainer className="flex-1" />
84
+ </div>
85
+
86
+ <SideBarChildContainer className="p-1 pt-[8px]">
87
+ {footerChildren}
88
+ </SideBarChildContainer>
89
+ </div>
90
+
91
+ </div>
92
+ </>
93
+ )}
94
+ </div>
95
+ </aside>
96
+ );
97
+ }
98
+
99
+
100
+ interface ChildProps
101
+ extends HTMLAttributes<HTMLDivElement> {
102
+ theme?: Themes
103
+ }
104
+
105
+ const SideBarChildContainer = ({ theme, ...props }: ChildProps) => {
106
+ return (
107
+ <div {...props} data-theme={theme} className={cn("w-full py-2 bg-background-system-body-base pr-2", props.className)}>
108
+ {props.children}
109
+ </div>
110
+ )
111
+ }
112
+
113
+
114
+ const SideBarItemStyles = cva([
115
+ "h-[40px] w-full px-[8px] flex gap-[6px] typography-body-small-medium justify-start items-center",
116
+ "text-content-system-global-primary border-l-[2px] rtl:border-r-[2px] border-transparent outline-none",
117
+ "hover:bg-white-alpha-075 hover:border-black-300 hover:text-content-system-action-primary-hover hover:px-[14px]",
118
+ "rounded-r-[4px] text-start whitespace-nowrap transition-all duration-150 ease-in-out",
119
+
120
+ ],
121
+ {
122
+ variants: {
123
+ disabled: {
124
+ true: "text-content-system-global-disabled bg-transparent hover:bg-transparent fucus:bg-transparent active:bg-transparent"
125
+ },
126
+ active: {
127
+ true: "hover:px-[8px] !px-[8px]"
128
+ },
129
+ iconOnly: {
130
+ true: "w-[40px] justify-center overflow-hidden"
131
+ },
132
+ variant: {
133
+ default: [
134
+ "fucus:bg-background-system-action-primary-hover fucus:border-border-system-action-primary-hover"],
135
+ secondary: [
136
+ "focus:bg-wavy-navy-1000 focus:border-border-system-action-field-hover-selected",
137
+ ],
138
+
139
+ }
140
+ },
141
+ compoundVariants: [
142
+ {
143
+ active: true,
144
+ variant: "default",
145
+ className: [
146
+ "bg-background-system-action-primary-hover border-border-system-action-primary-hover !px-[8px] hover:px-[8px]",
147
+ ]
148
+ },
149
+ {
150
+ active: true,
151
+ variant: "secondary",
152
+ className: [
153
+ "bg-wavy-navy-1000 border-border-system-action-field-hover-selected !px-[8px] hover:px-[8px]",
154
+ ]
155
+ },
156
+ {
157
+ disabled: true,
158
+ variant: "secondary",
159
+ className: [
160
+ "bg-transparent hover:bg-transparent focus:bg-transparent active:bg-transparent hover:p-[8px] hover:text-content-system-global-disabled",
161
+ ]
162
+ },
163
+ {
164
+ disabled: true,
165
+ variant: "default",
166
+ className: [
167
+ "bg-transparent hover:bg-transparent focus:bg-transparent active:bg-transparent hover:p-[8px] hover:text-content-system-global-disabled",
168
+ ]
169
+ }
170
+ ],
171
+ defaultVariants: {
172
+ variant: "default",
173
+ },
174
+ });
175
+
176
+
177
+
178
+ interface Props
179
+ extends ButtonHTMLAttributes<HTMLButtonElement>,
180
+ VariantProps<typeof SideBarItemStyles> {
181
+ asChild?: boolean;
182
+ as?: React.ElementType;
183
+ theme?: Themes
184
+ variant?: "default" | "secondary"
185
+ iconOnly?: boolean
186
+ active?: boolean
187
+ disabled?: boolean
188
+ }
189
+ const SideBarItem = ({ active, disabled, iconOnly, asChild, as: Tag = "span", theme, variant, ...props }: Props) => {
190
+ const Component = asChild ? Slot : Tag;
191
+
192
+ return (
193
+ <Component {...props} data-theme={theme} disabled={disabled} className={cn(SideBarItemStyles({ variant, iconOnly, active, disabled }), props.className)}>
194
+
195
+ </Component>
196
+ )
197
+ }
198
+
199
+
200
+ const SideBarIconButtonStyles = cva([
201
+ "h-[36px] w-[36px] flex text-content-system-global-primary text-[20px] justify-center items-center rounded-[8px] border border-transparent outline-none",
202
+ "fucus:bg-border-system-action-primary-Hover active:bg-border-system-action-primary-Hover",
203
+ "transition-all duration-200 ease-in-out flex-shrink-0 m-[5px] relative",
204
+ ],
205
+ {
206
+ variants: {
207
+ active: {
208
+ true: ""
209
+ },
210
+ variant: {
211
+ default: ["hover:bg-background-system-action-secondary-hover hover:border-border-system-action-primary-hover"],
212
+ secondary: ["hover:bg-wavy-navy-1000 hover:border-border-system-action-field-hover-selected"],
213
+
214
+ }
215
+ },
216
+ compoundVariants: [
217
+ {
218
+ active: true,
219
+ variant: "default",
220
+ className: [
221
+ "bg-background-system-action-secondary-hover border-border-system-action-primary-hover"]
222
+ },
223
+ {
224
+ active: true,
225
+ variant: "secondary",
226
+ className: [
227
+ "bg-background-system-action-secondary-hover border-border-system-action-primary-hover"
228
+ ]
229
+ }
230
+ ],
231
+ defaultVariants: {
232
+ variant: "default",
233
+ },
234
+ });
235
+
236
+
237
+ interface SideBarIconButtonProps
238
+ extends ButtonHTMLAttributes<HTMLButtonElement>,
239
+ VariantProps<typeof SideBarItemStyles> {
240
+ asChild?: boolean;
241
+ as?: React.ElementType;
242
+ theme?: Themes
243
+ variant?: "default" | "secondary"
244
+ active?: boolean
245
+ count?: number
246
+ message?: ReactNode
247
+ disabled?: boolean
248
+ }
249
+
250
+ const SideBarIconButton = ({ count, active, asChild, message, as: Tag = "button", theme, variant, ...props }: SideBarIconButtonProps) => {
251
+ const Component = asChild ? Slot : Tag;
252
+
253
+ return (
254
+ message ?
255
+ <Tooltip variant={"highlight"} text={message} toolTipSide='left' className='z-[1000]'>
256
+ <Component {...props} data-theme={theme} className={cn(SideBarIconButtonStyles({ variant, active }))}>
257
+ {props.children}
258
+ {count && <Counter className=' absolute top-[2px] right-[2px]' label={count} />}
259
+ </Component>
260
+ </Tooltip>
261
+ :
262
+ <Component {...props} data-theme={theme} className={cn(SideBarIconButtonStyles({ variant, active }))}>
263
+ {props.children}
264
+ {count && <Counter className=' absolute top-[2px] right-[2px]' label={count} />}
265
+ </Component>
266
+ )
267
+ }
268
+
269
+
270
+ interface SideBarFooterItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {
271
+ theme?: Themes
272
+ as?: React.ElementType;
273
+ asChild?: boolean;
274
+ variant?: "primary" | "secondary"
275
+ }
276
+
277
+ const glareFeedbackItemStyle = cva(
278
+ [
279
+ "h-[40px] w-full flex justify-center items-center rounded-[4px] px-2",
280
+ "text-content-system-global-primary typography-body-small-medium",
281
+ "border border-transparent outline-none bg-background-system-body-base",
282
+ "focus:bg-background-system-action-primary-selected",
283
+ "transition-all duration-200 ease-in-out",
284
+ ], {
285
+ variants: {
286
+ variant: {
287
+ primary:
288
+ [
289
+ "hover:bg-background-system-action-primary-hover hover:border-border-system-action-primary-hover",
290
+ "active:bg-background-system-action-primary-hover active:border-border-system-action-primary-hover "],
291
+ secondary: [
292
+ "hover:bg-wavy-navy-1000 hover:border-border-system-action-field-hover-selected",
293
+ "active:bg-wavy-navy-1000 active:border-border-system-action-field-hover-selected"],
294
+ }
295
+ },
296
+ defaultVariants: {
297
+ variant: "primary"
298
+ }
299
+ }
300
+ );
301
+
302
+
303
+ const SideBarFooterItem: React.FC<SideBarFooterItemProps> = ({ asChild,
304
+ as: Tag = "button", theme, variant, ...props }) => {
305
+ const Component = asChild ? Slot : Tag;
306
+
307
+ return (
308
+ <Component
309
+ data-theme={theme}
310
+ {...props}
311
+ className={cn(glareFeedbackItemStyle({ variant }), props.className)}
312
+ >
313
+ </Component>
314
+ );
315
+ };
316
+
317
+
318
+ export {
319
+ SideBar,
320
+ SideBarFooterItem,
321
+ SideBarItem,
322
+ SideBarChildContainer,
323
+ SideBarIconButton,
324
+ Body,
325
+ Layout
326
+ }
@@ -0,0 +1,64 @@
1
+ import { cn } from "../utils/cn";
2
+ import { ReactNode } from "react";
3
+ import { Label } from "../components/Label";
4
+ import { Themes } from "../utils/types";
5
+
6
+ interface Props {
7
+ label?: ReactNode;
8
+ secondaryLabel?: ReactNode;
9
+ requiredLabel?: ReactNode;
10
+ size?: "S" | "M" | "L";
11
+ childrenUnderLabel?: ReactNode;
12
+ theme?: Themes;
13
+ className?: string;
14
+ children?: ReactNode;
15
+ direction?: "horizontal" | "vertical" | "flexible";
16
+ }
17
+
18
+ export function FieldSection({
19
+ children,
20
+ label,
21
+ secondaryLabel,
22
+ direction = "flexible",
23
+ requiredLabel,
24
+ size,
25
+ theme,
26
+ className,
27
+ childrenUnderLabel,
28
+ ...props
29
+ }: Props) {
30
+ return (
31
+ <section
32
+ {...props}
33
+ data-theme={theme}
34
+ className={cn(
35
+ "grid border-t border-border-presentation-global-primary py-[16px] px-[12px] w-full max-w-[1200px] min-w-[0px] ",
36
+ direction === "vertical" && "grid-rows-[auto_1fr] gap-[12px]",
37
+ direction === "horizontal" && "grid-cols-[350px_1fr] gap-[24px]",
38
+ direction === "flexible" &&
39
+ "grid-rows-[auto_1fr] gap-[12px] lg:grid-cols-[350px_1fr] lg:grid-rows-[1fr] lg:gap-[24px]",
40
+ className
41
+ )}
42
+ >
43
+ {/* Fixed width section for labels */}
44
+ <div className="flex flex-col gap-[12px]">
45
+ {label && (
46
+ <Label
47
+ size={size}
48
+ label={label}
49
+ requiredLabel={requiredLabel}
50
+ directions={"horizontal"}
51
+ />
52
+ )}
53
+
54
+ {secondaryLabel && (
55
+ <Label size={size} secondaryLabel={secondaryLabel} />
56
+ )}
57
+ {childrenUnderLabel}
58
+ </div>
59
+
60
+ {/* Flexible section that takes up the remaining space */}
61
+ <div className="flex flex-col items-end gap-[12px]">{children}</div>
62
+ </section>
63
+ );
64
+ }
@@ -0,0 +1,187 @@
1
+ 'use client';
2
+ import { usePathname } from "next/navigation";
3
+ import TabFormItem from "@/components/TabFormItem";
4
+ import { cn } from "@/utils/cn";
5
+ import Link from "next/link";
6
+ import { useActiveTreeItem } from "@/hooks/useActiveTreeItem";
7
+
8
+ interface TreeItem {
9
+ id: string;
10
+ title: string;
11
+ subTree?: TreeItem[];
12
+ }
13
+ export type PathConfig = {
14
+ [key: string]: {
15
+ pageHeader: string;
16
+ subTitle?: string;
17
+ TabsTree: TreeItem[];
18
+ };
19
+ };
20
+
21
+ export default function TreeSubLayout({
22
+ children,
23
+ treeData,
24
+ }: {
25
+ children: React.ReactNode;
26
+ treeData: PathConfig;
27
+ }) {
28
+ const pathname = usePathname();
29
+ const allIds = treeData[pathname].TabsTree?.flatMap((item) => [
30
+ item.id,
31
+ ...(item.subTree?.map((sub) => sub.id) || []),
32
+ ]);
33
+ const { activeId } = useActiveTreeItem(allIds);
34
+
35
+
36
+ return (
37
+ <div
38
+ className={cn(
39
+ "flex gap-[2px] h-full overflow-hidden transition-all ease-in-out delay-150 lg:bg-none lg:rounded-2 ",
40
+ )}
41
+ >
42
+ <div className="grid grid-rows-[60px_1fr] h-full flex-1 gap-[2px] rounded-2 flex-shrink-0 min-w-[300px]">
43
+ <HeaderPage
44
+ title={treeData[pathname]?.pageHeader}
45
+ subTitle={treeData[pathname]?.subTitle}
46
+ />
47
+ <div className="grid grid-cols-[1fr] overflow-hidden lg:rounded-b-[6px] xl:grid-cols-[1fr_300px]">
48
+ <div className="scrollbar-hide overflow-scroll scroll-smooth bg-background-system-body-base h-full">
49
+ <div className="overflow-scroll scrollbar-hide scroll-smooth bg-[#B2D0FF0D] h-full w-full p-[12px]">
50
+ {children}
51
+ </div>
52
+ </div>
53
+
54
+ <div className="border-l border-border-presentation-global-primary bg-background-system-body-base scrollbar-hide hidden xl:block">
55
+ <div className="flex flex-col items-start gap-3 h-full py-8 px-6 overflow-y-auto scrollbar-hide">
56
+ {treeData[pathname].TabsTree.map((item) => (
57
+ <TreeSection
58
+ key={item.id}
59
+ href={`${item.id}`}
60
+ isActive={
61
+ activeId === item.id ||
62
+ item.subTree?.some((sub) => sub.id === activeId)
63
+ }
64
+ title={item?.title}
65
+ subTitles={item?.subTree?.map((sub) => ({
66
+ ...sub,
67
+ isActive: activeId === sub.id,
68
+ }))}
69
+ />
70
+ ))}
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ );
77
+ }
78
+
79
+
80
+
81
+ function TreeSection({
82
+ href,
83
+ isActive,
84
+ title,
85
+ subTitles,
86
+ }: {
87
+ href: string;
88
+ isActive?: boolean;
89
+ title: string;
90
+ subTitles?: { id: string; title: string; isActive?: boolean }[];
91
+ }) {
92
+
93
+ return (
94
+ <div
95
+ className={`flex flex-col items-start gap-[12px] w-full transition-colors duration-200`}
96
+ >
97
+ <TabFormItem
98
+ componentType="tree"
99
+ active={isActive}
100
+ className={`w-full`}
101
+ asChild
102
+ >
103
+ <Link href={`#${href}`}>
104
+ {title}
105
+ </Link>
106
+ </TabFormItem>
107
+ {subTitles && <div
108
+ className={`w-full h-[1px]
109
+ bg-border-presentation-global-primary
110
+ `}
111
+ ></div>}
112
+ {subTitles &&
113
+ <div className="flex items-start flex-1 w-full pl-4">
114
+ <div
115
+ className={`w-[1px] h-full bg-border-presentation-global-primary`}
116
+ />
117
+ <div className="flex p-[4px_0px_4px_8px] flex-col items-start gap-1 w-full flex-1">
118
+ {subTitles?.map((item) => (
119
+ <TabFormItem
120
+ componentType="tree"
121
+ key={item.id}
122
+ active={item.isActive}
123
+ className="w-full"
124
+ asChild
125
+ >
126
+ <Link href={`#${item.id}`}>
127
+ {item.title}
128
+ </Link>
129
+ </TabFormItem>
130
+ ))}
131
+ </div>
132
+ </div>
133
+ }
134
+ </div>
135
+ );
136
+ }
137
+
138
+
139
+ export function HeaderPage({
140
+ title,
141
+ subTitle,
142
+ children,
143
+ type = "start",
144
+ className,
145
+ }: {
146
+ title: string;
147
+ subTitle?: string;
148
+ children?: React.ReactNode;
149
+ type?: "space-between" | "start";
150
+ className?: string;
151
+ }) {
152
+ return (
153
+ <div
154
+ className={cn("w-full h-fit transition-all duration-300 ease-in-out lg:rounded-[8px_8px_0px_0px] lg:z-auto",
155
+ "bg-[linear-gradient(90deg,var(--blue-sparkle-600)_0px,rgba(44,45,46,1)_190px)] lg:bg-background-system-body-base",
156
+ "pb-[2px] lg:pb-0",
157
+ className)}
158
+ >
159
+ <div className="w-full h-full flex flex-col justify-center items-start rounded-[6px_6px_0px_0px] transition-all duration-300 ease-in-out lg:bg-none lg:bg-background-system-body-base lg:h-fit">
160
+ <div className="lg:hidden w-full bg-background-system-body-base px-[12px] h-[52px] flex justify-start items-center overflow-y-scroll border-b-[2px] border-[#2c2d2e]">
161
+ </div>
162
+ <div
163
+ className={cn(
164
+ `flex h-fit relative gap-2 items-center w-full lg:w-fit `,
165
+ "bg-background-system-body-secondary lg:bg-transparent",
166
+ "h-[52px] px-[16px] lg:py-[16px] rtl:pr-4 ltr:pl-4 lg:h-[60px]",
167
+ className
168
+ )}
169
+ >
170
+ <h1 className="text-content-system-global-primary whitespace-nowrap leading-none typography-display-large-semibold z-20 text-left lg:typography-display-medium-regular lg:uppercase">
171
+ {title}
172
+ </h1>
173
+ <p className="hidden mb-[-6px] sm:block text-content-presentation-global-secondary typography-headers-medium-regular z-20 lg:uppercase">{subTitle}</p>
174
+ <div className="h-[24px] hidden w-[1px] bg-border-presentation-global-primary z-20 sm:block"></div>
175
+ </div>
176
+ <div
177
+ className={cn(
178
+ "w-full flex rtl:pl-4 items-center ltr:pr-4",
179
+ type === "space-between" && "justify-end"
180
+ )}
181
+ >
182
+ {children}
183
+ </div>
184
+ </div>
185
+ </div>
186
+ );
187
+ }