pxengine 0.1.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.
- package/README.md +175 -0
- package/config/tailwind-preset.js +106 -0
- package/dist/index.d.mts +1259 -0
- package/dist/index.d.ts +1259 -0
- package/dist/index.js +5175 -0
- package/dist/index.mjs +4929 -0
- package/package.json +94 -0
- package/src/atoms/AccordionAtom.tsx +44 -0
- package/src/atoms/AlertAtom.tsx +46 -0
- package/src/atoms/AlertDialogAtom.tsx +66 -0
- package/src/atoms/AspectRatioAtom.tsx +27 -0
- package/src/atoms/AvatarAtom.tsx +20 -0
- package/src/atoms/BadgeAtom.tsx +25 -0
- package/src/atoms/BreadcrumbAtom.tsx +36 -0
- package/src/atoms/ButtonAtom.tsx +63 -0
- package/src/atoms/CalendarAtom.tsx +24 -0
- package/src/atoms/CardAtom.tsx +64 -0
- package/src/atoms/CarouselAtom.tsx +40 -0
- package/src/atoms/CollapsibleAtom.tsx +44 -0
- package/src/atoms/CommandAtom.tsx +46 -0
- package/src/atoms/DialogAtom.tsx +68 -0
- package/src/atoms/InputAtom.tsx +162 -0
- package/src/atoms/LayoutAtom.tsx +43 -0
- package/src/atoms/PaginationAtom.tsx +49 -0
- package/src/atoms/PopoverAtom.tsx +40 -0
- package/src/atoms/ProgressAtom.tsx +15 -0
- package/src/atoms/ScrollAreaAtom.tsx +31 -0
- package/src/atoms/SeparatorAtom.tsx +16 -0
- package/src/atoms/SheetAtom.tsx +72 -0
- package/src/atoms/SkeletonAtom.tsx +22 -0
- package/src/atoms/SpinnerAtom.tsx +26 -0
- package/src/atoms/TableAtom.tsx +58 -0
- package/src/atoms/TabsAtom.tsx +40 -0
- package/src/atoms/TextAtom.tsx +35 -0
- package/src/atoms/TooltipAtom.tsx +39 -0
- package/src/atoms/index.ts +28 -0
- package/src/components/index.ts +178 -0
- package/src/components/ui/accordion.tsx +56 -0
- package/src/components/ui/alert-dialog.tsx +139 -0
- package/src/components/ui/alert.tsx +59 -0
- package/src/components/ui/aspect-ratio.tsx +5 -0
- package/src/components/ui/avatar.tsx +50 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/breadcrumb.tsx +115 -0
- package/src/components/ui/button-group.tsx +83 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/calendar.tsx +213 -0
- package/src/components/ui/card.tsx +79 -0
- package/src/components/ui/carousel.tsx +260 -0
- package/src/components/ui/chart.tsx +367 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/command.tsx +153 -0
- package/src/components/ui/context-menu.tsx +198 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drawer.tsx +116 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/empty.tsx +104 -0
- package/src/components/ui/field.tsx +244 -0
- package/src/components/ui/form.tsx +176 -0
- package/src/components/ui/hover-card.tsx +27 -0
- package/src/components/ui/input-group.tsx +168 -0
- package/src/components/ui/input-otp.tsx +69 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/item.tsx +193 -0
- package/src/components/ui/kbd.tsx +28 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/menubar.tsx +254 -0
- package/src/components/ui/navigation-menu.tsx +128 -0
- package/src/components/ui/pagination.tsx +117 -0
- package/src/components/ui/popover.tsx +29 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/radio-group.tsx +42 -0
- package/src/components/ui/resizable.tsx +45 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.tsx +160 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.tsx +140 -0
- package/src/components/ui/sidebar.tsx +771 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/slider.tsx +26 -0
- package/src/components/ui/sonner.tsx +45 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/components/ui/table.tsx +117 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/toggle-group.tsx +61 -0
- package/src/components/ui/toggle.tsx +43 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.ts +24 -0
- package/src/lib/countries.ts +203 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/utils.ts +15 -0
- package/src/lib/validators/index.ts +1 -0
- package/src/lib/validators/theme.ts +148 -0
- package/src/molecules/creator-discovery/CampaignSeedCard/CampaignSeedCard.tsx +123 -0
- package/src/molecules/creator-discovery/CampaignSeedCard/CampaignSeedCard.types.ts +13 -0
- package/src/molecules/creator-discovery/CampaignSeedCard/index.ts +2 -0
- package/src/molecules/creator-discovery/MCQCard/MCQCard.tsx +165 -0
- package/src/molecules/creator-discovery/MCQCard/MCQCard.types.ts +71 -0
- package/src/molecules/creator-discovery/MCQCard/index.ts +2 -0
- package/src/molecules/creator-discovery/SearchSpecCard/CustomFieldRenderers.tsx +334 -0
- package/src/molecules/creator-discovery/SearchSpecCard/SearchSpecCard.tsx +111 -0
- package/src/molecules/creator-discovery/SearchSpecCard/SearchSpecCard.types.ts +18 -0
- package/src/molecules/creator-discovery/SearchSpecCard/index.ts +3 -0
- package/src/molecules/creator-discovery/index.ts +3 -0
- package/src/molecules/generic/ActionButton/ActionButton.tsx +137 -0
- package/src/molecules/generic/ActionButton/ActionButton.types.ts +68 -0
- package/src/molecules/generic/ActionButton/index.ts +2 -0
- package/src/molecules/generic/EditableField/EditableField.tsx +229 -0
- package/src/molecules/generic/EditableField/EditableField.types.ts +73 -0
- package/src/molecules/generic/EditableField/index.ts +2 -0
- package/src/molecules/generic/FormCard/FormCard.tsx +136 -0
- package/src/molecules/generic/FormCard/FormCard.types.ts +93 -0
- package/src/molecules/generic/FormCard/index.ts +2 -0
- package/src/molecules/generic/index.ts +3 -0
- package/src/molecules/index.ts +2 -0
- package/src/render/PXEngineRenderer.tsx +272 -0
- package/src/render/index.ts +1 -0
- package/src/styles/globals.css +146 -0
- package/src/types/atoms.ts +294 -0
- package/src/types/common.ts +116 -0
- package/src/types/index.ts +3 -0
- package/src/types/molecules.ts +54 -0
- package/src/types/schema.ts +12 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogContent,
|
|
5
|
+
DialogDescription,
|
|
6
|
+
DialogHeader,
|
|
7
|
+
DialogTitle,
|
|
8
|
+
DialogTrigger,
|
|
9
|
+
DialogFooter,
|
|
10
|
+
} from "@/components/ui/dialog";
|
|
11
|
+
import { DialogAtomType, UIComponent } from "../types/schema";
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
13
|
+
|
|
14
|
+
interface Props extends DialogAtomType {
|
|
15
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const DialogAtom: React.FC<Props> = ({
|
|
19
|
+
title,
|
|
20
|
+
description,
|
|
21
|
+
trigger,
|
|
22
|
+
children,
|
|
23
|
+
footer,
|
|
24
|
+
className,
|
|
25
|
+
renderComponent,
|
|
26
|
+
}) => {
|
|
27
|
+
return (
|
|
28
|
+
<Dialog>
|
|
29
|
+
<DialogTrigger asChild>
|
|
30
|
+
<div className={cn("inline-block cursor-pointer", className)}>
|
|
31
|
+
{trigger.map((child) => (
|
|
32
|
+
<React.Fragment key={child.id}>
|
|
33
|
+
{renderComponent(child)}
|
|
34
|
+
</React.Fragment>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
</DialogTrigger>
|
|
38
|
+
<DialogContent className="sm:max-w-[425px] rounded-3xl p-6 bg-white/95 backdrop-blur-md shadow-3xl border-gray-100">
|
|
39
|
+
<DialogHeader>
|
|
40
|
+
<DialogTitle className="text-xl font-bold bg-gradient-to-r from-purple600 to-indigo-600 bg-clip-text text-transparent">
|
|
41
|
+
{title}
|
|
42
|
+
</DialogTitle>
|
|
43
|
+
{description && (
|
|
44
|
+
<DialogDescription className="text-gray-500 font-medium pt-1">
|
|
45
|
+
{description}
|
|
46
|
+
</DialogDescription>
|
|
47
|
+
)}
|
|
48
|
+
</DialogHeader>
|
|
49
|
+
<div className="py-4">
|
|
50
|
+
{children.map((child) => (
|
|
51
|
+
<React.Fragment key={child.id}>
|
|
52
|
+
{renderComponent(child)}
|
|
53
|
+
</React.Fragment>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
{footer && (
|
|
57
|
+
<DialogFooter className="pt-2">
|
|
58
|
+
{footer.map((child) => (
|
|
59
|
+
<React.Fragment key={child.id}>
|
|
60
|
+
{renderComponent(child)}
|
|
61
|
+
</React.Fragment>
|
|
62
|
+
))}
|
|
63
|
+
</DialogFooter>
|
|
64
|
+
)}
|
|
65
|
+
</DialogContent>
|
|
66
|
+
</Dialog>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Input } from "@/components/ui/input";
|
|
3
|
+
import { Textarea } from "@/components/ui/textarea";
|
|
4
|
+
import { Label } from "@/components/ui/label";
|
|
5
|
+
import { Checkbox } from "@/components/ui/checkbox";
|
|
6
|
+
import { Switch } from "@/components/ui/switch";
|
|
7
|
+
import {
|
|
8
|
+
Select,
|
|
9
|
+
SelectContent,
|
|
10
|
+
SelectItem,
|
|
11
|
+
SelectTrigger,
|
|
12
|
+
SelectValue,
|
|
13
|
+
} from "@/components/ui/select";
|
|
14
|
+
import { Slider } from "@/components/ui/slider";
|
|
15
|
+
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
|
16
|
+
import {
|
|
17
|
+
InputOTP,
|
|
18
|
+
InputOTPGroup,
|
|
19
|
+
InputOTPSlot,
|
|
20
|
+
} from "@/components/ui/input-otp";
|
|
21
|
+
import { InputAtomType } from "../types/schema";
|
|
22
|
+
import { cn } from "@/lib/utils";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* InputAtom
|
|
26
|
+
* A multi-purpose input wrapper that switches based on inputType in schema
|
|
27
|
+
*/
|
|
28
|
+
export const InputAtom: React.FC<InputAtomType> = ({
|
|
29
|
+
inputType,
|
|
30
|
+
label,
|
|
31
|
+
placeholder,
|
|
32
|
+
defaultValue,
|
|
33
|
+
required,
|
|
34
|
+
disabled,
|
|
35
|
+
options,
|
|
36
|
+
config,
|
|
37
|
+
className,
|
|
38
|
+
}) => {
|
|
39
|
+
const containerClass = cn("flex flex-col gap-1.5 w-full", className);
|
|
40
|
+
|
|
41
|
+
const renderLabel = () => {
|
|
42
|
+
if (!label) return null;
|
|
43
|
+
return (
|
|
44
|
+
<Label className="text-xs font-bold text-gray-400 uppercase tracking-widest pl-1">
|
|
45
|
+
{label} {required && <span className="text-destructive">*</span>}
|
|
46
|
+
</Label>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const renderInput = () => {
|
|
51
|
+
switch (inputType) {
|
|
52
|
+
case "textarea":
|
|
53
|
+
return (
|
|
54
|
+
<Textarea
|
|
55
|
+
placeholder={placeholder}
|
|
56
|
+
defaultValue={defaultValue}
|
|
57
|
+
disabled={disabled}
|
|
58
|
+
rows={config?.rows || 3}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
case "select":
|
|
62
|
+
return (
|
|
63
|
+
<Select defaultValue={defaultValue} disabled={disabled}>
|
|
64
|
+
<SelectTrigger>
|
|
65
|
+
<SelectValue placeholder={placeholder || "Select option"} />
|
|
66
|
+
</SelectTrigger>
|
|
67
|
+
<SelectContent>
|
|
68
|
+
{options?.map((opt) => (
|
|
69
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
70
|
+
{opt.label}
|
|
71
|
+
</SelectItem>
|
|
72
|
+
))}
|
|
73
|
+
</SelectContent>
|
|
74
|
+
</Select>
|
|
75
|
+
);
|
|
76
|
+
case "slider":
|
|
77
|
+
return (
|
|
78
|
+
<div className="pt-4 pb-2">
|
|
79
|
+
<Slider
|
|
80
|
+
defaultValue={[defaultValue || config?.min || 0]}
|
|
81
|
+
max={config?.max || 100}
|
|
82
|
+
min={config?.min || 0}
|
|
83
|
+
step={config?.step || 1}
|
|
84
|
+
disabled={disabled}
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
case "checkbox":
|
|
89
|
+
return (
|
|
90
|
+
<div className="flex items-center space-x-2 py-2">
|
|
91
|
+
<Checkbox
|
|
92
|
+
id={label}
|
|
93
|
+
defaultChecked={defaultValue}
|
|
94
|
+
disabled={disabled}
|
|
95
|
+
/>
|
|
96
|
+
<label
|
|
97
|
+
htmlFor={label}
|
|
98
|
+
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
99
|
+
>
|
|
100
|
+
{label}
|
|
101
|
+
</label>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
case "switch":
|
|
105
|
+
return (
|
|
106
|
+
<div className="flex items-center space-x-2 py-2">
|
|
107
|
+
<Switch
|
|
108
|
+
id={label}
|
|
109
|
+
defaultChecked={defaultValue}
|
|
110
|
+
disabled={disabled}
|
|
111
|
+
/>
|
|
112
|
+
<Label htmlFor={label}>{label}</Label>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
case "radio":
|
|
116
|
+
return (
|
|
117
|
+
<RadioGroup defaultValue={defaultValue} disabled={disabled}>
|
|
118
|
+
{options?.map((opt) => (
|
|
119
|
+
<div key={opt.value} className="flex items-center space-x-2">
|
|
120
|
+
<RadioGroupItem
|
|
121
|
+
value={opt.value}
|
|
122
|
+
id={`${label}-${opt.value}`}
|
|
123
|
+
/>
|
|
124
|
+
<Label htmlFor={`${label}-${opt.value}`}>{opt.label}</Label>
|
|
125
|
+
</div>
|
|
126
|
+
))}
|
|
127
|
+
</RadioGroup>
|
|
128
|
+
);
|
|
129
|
+
case "otp":
|
|
130
|
+
return (
|
|
131
|
+
<InputOTP
|
|
132
|
+
maxLength={config?.maxLength || 6}
|
|
133
|
+
disabled={disabled}
|
|
134
|
+
defaultValue={defaultValue}
|
|
135
|
+
>
|
|
136
|
+
<InputOTPGroup>
|
|
137
|
+
{Array.from({ length: config?.maxLength || 6 }).map((_, i) => (
|
|
138
|
+
<InputOTPSlot key={i} index={i} />
|
|
139
|
+
))}
|
|
140
|
+
</InputOTPGroup>
|
|
141
|
+
</InputOTP>
|
|
142
|
+
);
|
|
143
|
+
default:
|
|
144
|
+
return (
|
|
145
|
+
<Input
|
|
146
|
+
type={inputType}
|
|
147
|
+
placeholder={placeholder}
|
|
148
|
+
defaultValue={defaultValue}
|
|
149
|
+
disabled={disabled}
|
|
150
|
+
required={required}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div className={containerClass}>
|
|
158
|
+
{inputType !== "checkbox" && inputType !== "switch" && renderLabel()}
|
|
159
|
+
{renderInput()}
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { LayoutAtomType, UIComponent } from "../types/schema";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
interface Props extends LayoutAtomType {
|
|
6
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* LayoutAtom
|
|
11
|
+
* Standardized container with flex/grid support from schema
|
|
12
|
+
*/
|
|
13
|
+
export const LayoutAtom: React.FC<Props> = ({
|
|
14
|
+
direction,
|
|
15
|
+
gap = "md",
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
renderComponent,
|
|
19
|
+
}) => {
|
|
20
|
+
const gapMap: Record<string, string> = {
|
|
21
|
+
none: "gap-0",
|
|
22
|
+
sm: "gap-2",
|
|
23
|
+
md: "gap-4",
|
|
24
|
+
lg: "gap-8",
|
|
25
|
+
xl: "gap-12",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const classes = cn(
|
|
29
|
+
"flex",
|
|
30
|
+
direction === "vertical" ? "flex-col" : "flex-row flex-wrap",
|
|
31
|
+
direction === "grid" && "grid grid-cols-1 md:grid-cols-2",
|
|
32
|
+
gapMap[gap],
|
|
33
|
+
className,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className={classes}>
|
|
38
|
+
{children.map((child) => (
|
|
39
|
+
<React.Fragment key={child.id}>{renderComponent(child)}</React.Fragment>
|
|
40
|
+
))}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Pagination,
|
|
4
|
+
PaginationContent,
|
|
5
|
+
PaginationEllipsis,
|
|
6
|
+
PaginationItem,
|
|
7
|
+
PaginationLink,
|
|
8
|
+
PaginationNext,
|
|
9
|
+
PaginationPrevious,
|
|
10
|
+
} from "@/components/ui/pagination";
|
|
11
|
+
import { PaginationAtomType } from "../types/schema";
|
|
12
|
+
|
|
13
|
+
export const PaginationAtom: React.FC<PaginationAtomType> = ({
|
|
14
|
+
currentPage,
|
|
15
|
+
totalPages,
|
|
16
|
+
hasNext = true,
|
|
17
|
+
hasPrev = true,
|
|
18
|
+
className,
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<Pagination className={className}>
|
|
22
|
+
<PaginationContent>
|
|
23
|
+
{hasPrev && (
|
|
24
|
+
<PaginationItem>
|
|
25
|
+
<PaginationPrevious href="#" />
|
|
26
|
+
</PaginationItem>
|
|
27
|
+
)}
|
|
28
|
+
|
|
29
|
+
<PaginationItem>
|
|
30
|
+
<PaginationLink href="#" isActive>
|
|
31
|
+
{currentPage}
|
|
32
|
+
</PaginationLink>
|
|
33
|
+
</PaginationItem>
|
|
34
|
+
|
|
35
|
+
{totalPages > currentPage && (
|
|
36
|
+
<PaginationItem>
|
|
37
|
+
<PaginationEllipsis />
|
|
38
|
+
</PaginationItem>
|
|
39
|
+
)}
|
|
40
|
+
|
|
41
|
+
{hasNext && (
|
|
42
|
+
<PaginationItem>
|
|
43
|
+
<PaginationNext href="#" />
|
|
44
|
+
</PaginationItem>
|
|
45
|
+
)}
|
|
46
|
+
</PaginationContent>
|
|
47
|
+
</Pagination>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Popover,
|
|
4
|
+
PopoverContent,
|
|
5
|
+
PopoverTrigger,
|
|
6
|
+
} from "@/components/ui/popover";
|
|
7
|
+
import { PopoverAtomType, UIComponent } from "../types/schema";
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
interface Props extends PopoverAtomType {
|
|
11
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const PopoverAtom: React.FC<Props> = ({
|
|
15
|
+
trigger,
|
|
16
|
+
content,
|
|
17
|
+
className,
|
|
18
|
+
renderComponent,
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<Popover>
|
|
22
|
+
<PopoverTrigger asChild>
|
|
23
|
+
<div className={cn("inline-block cursor-pointer", className)}>
|
|
24
|
+
{trigger.map((child) => (
|
|
25
|
+
<React.Fragment key={child.id}>
|
|
26
|
+
{renderComponent(child)}
|
|
27
|
+
</React.Fragment>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</PopoverTrigger>
|
|
31
|
+
<PopoverContent className="w-80 rounded-2xl shadow-2xl border-gray-100 p-4 bg-white/95 backdrop-blur-sm">
|
|
32
|
+
{content.map((child) => (
|
|
33
|
+
<React.Fragment key={child.id}>
|
|
34
|
+
{renderComponent(child)}
|
|
35
|
+
</React.Fragment>
|
|
36
|
+
))}
|
|
37
|
+
</PopoverContent>
|
|
38
|
+
</Popover>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Progress } from "@/components/ui/progress";
|
|
3
|
+
import { ProgressAtomType } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
export const ProgressAtom: React.FC<ProgressAtomType> = ({
|
|
7
|
+
value,
|
|
8
|
+
className,
|
|
9
|
+
}) => {
|
|
10
|
+
return (
|
|
11
|
+
<div className={cn("w-full py-2", className)}>
|
|
12
|
+
<Progress value={value} className="h-2 bg-gray-100" />
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
|
3
|
+
import { ScrollAreaAtomType, UIComponent } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
interface Props extends ScrollAreaAtomType {
|
|
7
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const ScrollAreaAtom: React.FC<Props> = ({
|
|
11
|
+
maxHeight = "300px",
|
|
12
|
+
children,
|
|
13
|
+
className,
|
|
14
|
+
renderComponent,
|
|
15
|
+
}) => {
|
|
16
|
+
return (
|
|
17
|
+
<ScrollArea
|
|
18
|
+
className={cn("rounded-xl border", className)}
|
|
19
|
+
style={{ height: maxHeight }}
|
|
20
|
+
>
|
|
21
|
+
<div className="p-4">
|
|
22
|
+
{children.map((child) => (
|
|
23
|
+
<React.Fragment key={child.id}>
|
|
24
|
+
{renderComponent(child)}
|
|
25
|
+
</React.Fragment>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
<ScrollBar orientation="vertical" />
|
|
29
|
+
</ScrollArea>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Separator } from "@/components/ui/separator";
|
|
3
|
+
import { SeparatorAtomType } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
export const SeparatorAtom: React.FC<SeparatorAtomType> = ({
|
|
7
|
+
orientation = "horizontal",
|
|
8
|
+
className,
|
|
9
|
+
}) => {
|
|
10
|
+
return (
|
|
11
|
+
<Separator
|
|
12
|
+
orientation={orientation}
|
|
13
|
+
className={cn("bg-gray-100", className)}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Sheet,
|
|
4
|
+
SheetContent,
|
|
5
|
+
SheetDescription,
|
|
6
|
+
SheetHeader,
|
|
7
|
+
SheetTitle,
|
|
8
|
+
SheetTrigger,
|
|
9
|
+
SheetFooter,
|
|
10
|
+
} from "@/components/ui/sheet";
|
|
11
|
+
import { SheetAtomType, UIComponent } from "../types/schema";
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
13
|
+
|
|
14
|
+
interface Props extends SheetAtomType {
|
|
15
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const SheetAtom: React.FC<Props> = ({
|
|
19
|
+
side = "right",
|
|
20
|
+
title,
|
|
21
|
+
description,
|
|
22
|
+
trigger,
|
|
23
|
+
children,
|
|
24
|
+
footer,
|
|
25
|
+
className,
|
|
26
|
+
renderComponent,
|
|
27
|
+
}) => {
|
|
28
|
+
return (
|
|
29
|
+
<Sheet>
|
|
30
|
+
<SheetTrigger asChild>
|
|
31
|
+
<div className={cn("inline-block cursor-pointer", className)}>
|
|
32
|
+
{trigger.map((child) => (
|
|
33
|
+
<React.Fragment key={child.id}>
|
|
34
|
+
{renderComponent(child)}
|
|
35
|
+
</React.Fragment>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
</SheetTrigger>
|
|
39
|
+
<SheetContent
|
|
40
|
+
side={side}
|
|
41
|
+
className="bg-white/95 backdrop-blur-md border-l-gray-100 shadow-2xl p-6"
|
|
42
|
+
>
|
|
43
|
+
<SheetHeader>
|
|
44
|
+
<SheetTitle className="text-xl font-bold text-gray-900">
|
|
45
|
+
{title}
|
|
46
|
+
</SheetTitle>
|
|
47
|
+
{description && (
|
|
48
|
+
<SheetDescription className="text-gray-500 font-medium">
|
|
49
|
+
{description}
|
|
50
|
+
</SheetDescription>
|
|
51
|
+
)}
|
|
52
|
+
</SheetHeader>
|
|
53
|
+
<div className="py-8">
|
|
54
|
+
{children.map((child) => (
|
|
55
|
+
<React.Fragment key={child.id}>
|
|
56
|
+
{renderComponent(child)}
|
|
57
|
+
</React.Fragment>
|
|
58
|
+
))}
|
|
59
|
+
</div>
|
|
60
|
+
{footer && (
|
|
61
|
+
<SheetFooter className="absolute bottom-6 left-6 right-6">
|
|
62
|
+
{footer.map((child) => (
|
|
63
|
+
<React.Fragment key={child.id}>
|
|
64
|
+
{renderComponent(child)}
|
|
65
|
+
</React.Fragment>
|
|
66
|
+
))}
|
|
67
|
+
</SheetFooter>
|
|
68
|
+
)}
|
|
69
|
+
</SheetContent>
|
|
70
|
+
</Sheet>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
3
|
+
import { SkeletonAtomType } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
export const SkeletonAtom: React.FC<SkeletonAtomType> = ({
|
|
7
|
+
shape = "rect",
|
|
8
|
+
width,
|
|
9
|
+
height,
|
|
10
|
+
className,
|
|
11
|
+
}) => {
|
|
12
|
+
return (
|
|
13
|
+
<Skeleton
|
|
14
|
+
className={cn(
|
|
15
|
+
shape === "circle" ? "rounded-full" : "rounded-md",
|
|
16
|
+
"bg-gray-100",
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
style={{ width, height }}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Loader2 } from "lucide-react";
|
|
3
|
+
import { SpinnerAtomType } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
export const SpinnerAtom: React.FC<SpinnerAtomType> = ({
|
|
7
|
+
size = "md",
|
|
8
|
+
className,
|
|
9
|
+
}) => {
|
|
10
|
+
const sizeMap = {
|
|
11
|
+
sm: "h-4 w-4",
|
|
12
|
+
md: "h-6 w-6",
|
|
13
|
+
lg: "h-8 w-8",
|
|
14
|
+
xl: "h-12 w-12",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Loader2
|
|
19
|
+
className={cn(
|
|
20
|
+
"animate-spin text-purple500",
|
|
21
|
+
sizeMap[size] || sizeMap.md,
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Table,
|
|
4
|
+
TableBody,
|
|
5
|
+
TableCell,
|
|
6
|
+
TableHead,
|
|
7
|
+
TableHeader,
|
|
8
|
+
TableRow,
|
|
9
|
+
} from "@/components/ui/table";
|
|
10
|
+
import { TableAtomType } from "../types/schema";
|
|
11
|
+
import { cn } from "@/lib/utils";
|
|
12
|
+
|
|
13
|
+
export const TableAtom: React.FC<TableAtomType> = ({
|
|
14
|
+
headers,
|
|
15
|
+
rows,
|
|
16
|
+
className,
|
|
17
|
+
}) => {
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className={cn(
|
|
21
|
+
"rounded-2xl border border-gray-100 overflow-hidden bg-white",
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
<Table>
|
|
26
|
+
<TableHeader className="bg-gray-50/50">
|
|
27
|
+
<TableRow>
|
|
28
|
+
{headers.map((header, i) => (
|
|
29
|
+
<TableHead
|
|
30
|
+
key={i}
|
|
31
|
+
className="text-xs font-bold text-gray-400 uppercase tracking-widest px-6 py-4"
|
|
32
|
+
>
|
|
33
|
+
{header}
|
|
34
|
+
</TableHead>
|
|
35
|
+
))}
|
|
36
|
+
</TableRow>
|
|
37
|
+
</TableHeader>
|
|
38
|
+
<TableBody>
|
|
39
|
+
{rows.map((row, i) => (
|
|
40
|
+
<TableRow
|
|
41
|
+
key={i}
|
|
42
|
+
className="hover:bg-purple-50/30 transition-colors border-gray-50"
|
|
43
|
+
>
|
|
44
|
+
{row.map((cell, j) => (
|
|
45
|
+
<TableCell
|
|
46
|
+
key={j}
|
|
47
|
+
className="text-sm text-gray-700 px-6 py-4 font-medium"
|
|
48
|
+
>
|
|
49
|
+
{cell}
|
|
50
|
+
</TableCell>
|
|
51
|
+
))}
|
|
52
|
+
</TableRow>
|
|
53
|
+
))}
|
|
54
|
+
</TableBody>
|
|
55
|
+
</Table>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
|
3
|
+
import { TabsAtomType, UIComponent } from "../types/schema";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
interface Props extends TabsAtomType {
|
|
7
|
+
renderComponent: (component: UIComponent) => React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const TabsAtom: React.FC<Props> = ({
|
|
11
|
+
defaultValue,
|
|
12
|
+
tabs,
|
|
13
|
+
className,
|
|
14
|
+
renderComponent,
|
|
15
|
+
}) => {
|
|
16
|
+
return (
|
|
17
|
+
<Tabs defaultValue={defaultValue} className={cn("w-full", className)}>
|
|
18
|
+
<TabsList className="bg-gray-100/50 p-1 rounded-xl">
|
|
19
|
+
{tabs.map((tab) => (
|
|
20
|
+
<TabsTrigger
|
|
21
|
+
key={tab.value}
|
|
22
|
+
value={tab.value}
|
|
23
|
+
className="rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-sm"
|
|
24
|
+
>
|
|
25
|
+
{tab.label}
|
|
26
|
+
</TabsTrigger>
|
|
27
|
+
))}
|
|
28
|
+
</TabsList>
|
|
29
|
+
{tabs.map((tab) => (
|
|
30
|
+
<TabsContent key={tab.value} value={tab.value} className="mt-4">
|
|
31
|
+
{tab.content.map((child) => (
|
|
32
|
+
<React.Fragment key={child.id}>
|
|
33
|
+
{renderComponent(child)}
|
|
34
|
+
</React.Fragment>
|
|
35
|
+
))}
|
|
36
|
+
</TabsContent>
|
|
37
|
+
))}
|
|
38
|
+
</Tabs>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TextAtomType } from "../types/schema";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TextAtom
|
|
7
|
+
* Renders standardized text styles from UISchema
|
|
8
|
+
*/
|
|
9
|
+
export const TextAtom: React.FC<TextAtomType> = ({
|
|
10
|
+
content,
|
|
11
|
+
variant = "p",
|
|
12
|
+
className,
|
|
13
|
+
}) => {
|
|
14
|
+
const baseStyles: Record<string, string> = {
|
|
15
|
+
h1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-gray-900",
|
|
16
|
+
h2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0 text-gray-900",
|
|
17
|
+
h3: "scroll-m-20 text-2xl font-semibold tracking-tight text-gray-900",
|
|
18
|
+
h4: "scroll-m-20 text-xl font-semibold tracking-tight text-gray-900",
|
|
19
|
+
p: "leading-7 [&:not(:first-child)]:mt-6 text-gray-700",
|
|
20
|
+
small: "text-sm font-medium leading-none text-gray-600",
|
|
21
|
+
muted: "text-sm text-muted-foreground",
|
|
22
|
+
label: "text-[10px] font-bold text-gray-400 uppercase tracking-widest pl-1",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const Component =
|
|
26
|
+
variant === "small" || variant === "muted" || variant === "label"
|
|
27
|
+
? "p"
|
|
28
|
+
: variant;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Component className={cn(baseStyles[variant], className)}>
|
|
32
|
+
{content}
|
|
33
|
+
</Component>
|
|
34
|
+
);
|
|
35
|
+
};
|