create-react-scaffold-cli 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/bin/index.js +34 -0
- package/package.json +15 -0
- package/scripts/createProject.js +30 -0
- package/templates/base/.env +1 -0
- package/templates/base/.husky/pre-commit +1 -0
- package/templates/base/.husky/pre-push +0 -0
- package/templates/base/.prettierrc +8 -0
- package/templates/base/.vscode/extensions.json +8 -0
- package/templates/base/.vscode/settings.json +16 -0
- package/templates/base/eslint.config.js +48 -0
- package/templates/base/index.html +16 -0
- package/templates/base/jsconfig.json +7 -0
- package/templates/base/package.json +64 -0
- package/templates/base/postcss.config.mjs +7 -0
- package/templates/base/readme.md +97 -0
- package/templates/base/src/app/App.jsx +13 -0
- package/templates/base/src/app/Router.jsx +4 -0
- package/templates/base/src/app/app_readme.md +74 -0
- package/templates/base/src/app/index.css +1 -0
- package/templates/base/src/app/main.jsx +10 -0
- package/templates/base/src/app/middlewares/index.js +0 -0
- package/templates/base/src/app/providers/QueryProvider.jsx +75 -0
- package/templates/base/src/app/providers/index.js +1 -0
- package/templates/base/src/features/features_readme.md +102 -0
- package/templates/base/src/features/index.js +0 -0
- package/templates/base/src/features/sample/components/index.js +0 -0
- package/templates/base/src/features/sample/constants/index.js +0 -0
- package/templates/base/src/features/sample/constants/sample.constants.js +0 -0
- package/templates/base/src/features/sample/hooks/index.js +0 -0
- package/templates/base/src/features/sample/pages/index.js +0 -0
- package/templates/base/src/features/sample/sample.assets.js +0 -0
- package/templates/base/src/features/sample/sample.context.js +0 -0
- package/templates/base/src/features/sample/sample.navigations.js +0 -0
- package/templates/base/src/features/sample/sample.queryKeys.js +0 -0
- package/templates/base/src/features/sample/sample.routes.jsx +0 -0
- package/templates/base/src/shared/constants/app.constants.js +4 -0
- package/templates/base/src/shared/constants/assets.constants.js +0 -0
- package/templates/base/src/shared/constants/index.js +0 -0
- package/templates/base/src/shared/contexts/index.js +0 -0
- package/templates/base/src/shared/hooks/index.js +3 -0
- package/templates/base/src/shared/hooks/useBooleanState.js +19 -0
- package/templates/base/src/shared/hooks/useDebounce.js +17 -0
- package/templates/base/src/shared/hooks/useToggleState.js +11 -0
- package/templates/base/src/shared/layouts/index.js +0 -0
- package/templates/base/src/shared/libs/axios.js +6 -0
- package/templates/base/src/shared/libs/cn.js +7 -0
- package/templates/base/src/shared/libs/index.js +2 -0
- package/templates/base/src/shared/shared_readme.md +98 -0
- package/templates/base/src/shared/theme/index.js +1 -0
- package/templates/base/src/shared/theme/theme.js +2138 -0
- package/templates/base/src/shared/ui/Box.jsx +200 -0
- package/templates/base/src/shared/ui/Button.jsx +150 -0
- package/templates/base/src/shared/ui/Checkbox.jsx +112 -0
- package/templates/base/src/shared/ui/DropdownMenu.jsx +152 -0
- package/templates/base/src/shared/ui/Flex.jsx +151 -0
- package/templates/base/src/shared/ui/FlexItem.jsx +96 -0
- package/templates/base/src/shared/ui/FormField.jsx +184 -0
- package/templates/base/src/shared/ui/Grid.jsx +151 -0
- package/templates/base/src/shared/ui/GridItem.jsx +95 -0
- package/templates/base/src/shared/ui/Modal.jsx +43 -0
- package/templates/base/src/shared/ui/Scrollable.jsx +47 -0
- package/templates/base/src/shared/ui/Select.jsx +207 -0
- package/templates/base/src/shared/ui/Sheet.jsx +112 -0
- package/templates/base/src/shared/ui/Text.jsx +122 -0
- package/templates/base/src/shared/ui/Toaster.jsx +31 -0
- package/templates/base/src/shared/ui/index.js +1 -0
- package/templates/base/src/shared/utils/getClassName.js +5 -0
- package/templates/base/src/shared/utils/index.js +4 -0
- package/templates/base/src/shared/utils/memo.js +3 -0
- package/templates/base/src/shared/utils/parser.js +41 -0
- package/templates/base/src/shared/utils/tryCatch.js +13 -0
- package/templates/base/vite.config.js +19 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
3
|
+
import { Scrollable } from './Scrollable';
|
|
4
|
+
import { cn } from '../libs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {object} ComponentProps
|
|
8
|
+
* @property {boolean} isOpen
|
|
9
|
+
* @property {() => void} onClose
|
|
10
|
+
* @property {string} [className]
|
|
11
|
+
* @param {React.PropsWithChildren & ComponentProps} props
|
|
12
|
+
* @returns {JSX.Element}
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const Component = ({ isOpen, onClose, className, children }) => {
|
|
16
|
+
const onOpenChange = React.useCallback(
|
|
17
|
+
(isOpen) => {
|
|
18
|
+
if (isOpen) return;
|
|
19
|
+
onClose();
|
|
20
|
+
},
|
|
21
|
+
[onClose]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Dialog.Root open={isOpen} onOpenChange={onOpenChange}>
|
|
26
|
+
<Dialog.Portal>
|
|
27
|
+
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/20 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" />
|
|
28
|
+
<Dialog.Content
|
|
29
|
+
aria-describedby={undefined}
|
|
30
|
+
className={cn(
|
|
31
|
+
'fixed left-[50%] top-[50%] z-50 p-5 grid translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-2xl bg-white font-inter overflow-hidden',
|
|
32
|
+
className
|
|
33
|
+
)}
|
|
34
|
+
>
|
|
35
|
+
<Dialog.Title className="sr-only"></Dialog.Title>
|
|
36
|
+
<Scrollable indicatorClassName="!w-1">{children}</Scrollable>
|
|
37
|
+
</Dialog.Content>
|
|
38
|
+
</Dialog.Portal>
|
|
39
|
+
</Dialog.Root>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Modal = memo(Component);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as ScrollArea from '@radix-ui/react-scroll-area';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { cn } from '../libs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {object} ComponentProps
|
|
7
|
+
* @property {'horizontal' | 'vertical'} [orientation]
|
|
8
|
+
* @property {string} [className]
|
|
9
|
+
* @property {string} [indicatorClassName]
|
|
10
|
+
* @param {React.PropsWithChildren<ComponentProps>} props
|
|
11
|
+
* @returns {JSX.Element}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const Component = ({
|
|
15
|
+
orientation = 'vertical',
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
style,
|
|
19
|
+
onClick,
|
|
20
|
+
indicatorClassName,
|
|
21
|
+
viewPortClassName,
|
|
22
|
+
}) => {
|
|
23
|
+
return (
|
|
24
|
+
<ScrollArea.Root
|
|
25
|
+
className={cn('size-full overflow-hidden', className)}
|
|
26
|
+
style={style}
|
|
27
|
+
onClick={onClick}
|
|
28
|
+
>
|
|
29
|
+
<ScrollArea.Viewport className={cn('size-full overflow-hidden', viewPortClassName)}>
|
|
30
|
+
{children}
|
|
31
|
+
</ScrollArea.Viewport>
|
|
32
|
+
|
|
33
|
+
<ScrollArea.Scrollbar
|
|
34
|
+
orientation={orientation}
|
|
35
|
+
className={cn(
|
|
36
|
+
orientation === 'vertical' ? 'w-1 lg:w-1.5 2xl:w-2' : 'h-1 lg:h-1.5 flex flex-col',
|
|
37
|
+
indicatorClassName
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
<ScrollArea.Thumb className="relative flex-1 rounded bg-gray-400/50 hover:bg-gray-800/50 transition-colors" />
|
|
41
|
+
</ScrollArea.Scrollbar>
|
|
42
|
+
<ScrollArea.Corner />
|
|
43
|
+
</ScrollArea.Root>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Scrollable = memo(Component);
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
3
|
+
import { FaChevronDown, FaChevronUp, FaCheck } from 'react-icons/fa6';
|
|
4
|
+
import { memo } from '../utils';
|
|
5
|
+
import { cn } from '../libs';
|
|
6
|
+
|
|
7
|
+
const SelectRoot = SelectPrimitive.Root;
|
|
8
|
+
|
|
9
|
+
const SelectValue = SelectPrimitive.Value;
|
|
10
|
+
|
|
11
|
+
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
|
|
12
|
+
<SelectPrimitive.Trigger
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn(
|
|
15
|
+
'flex w-full items-center justify-between whitespace-nowrap rounded-10rd border bg-transparent px-3 py-2.5 font-inter text-sm placeholder:!text-custom-grey-900 placeholder:!opacity-30 disabled:cursor-not-allowed disabled:bg-neutral-50 [&>span]:line-clamp-1',
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
>
|
|
20
|
+
{children}
|
|
21
|
+
<SelectPrimitive.Icon asChild>
|
|
22
|
+
<FaChevronDown size={12} className="text-neutral-300" />
|
|
23
|
+
</SelectPrimitive.Icon>
|
|
24
|
+
</SelectPrimitive.Trigger>
|
|
25
|
+
));
|
|
26
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
27
|
+
|
|
28
|
+
const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (
|
|
29
|
+
<SelectPrimitive.ScrollUpButton
|
|
30
|
+
ref={ref}
|
|
31
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
<FaChevronUp className="h-4 w-4" />
|
|
35
|
+
</SelectPrimitive.ScrollUpButton>
|
|
36
|
+
));
|
|
37
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
38
|
+
|
|
39
|
+
const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => (
|
|
40
|
+
<SelectPrimitive.ScrollDownButton
|
|
41
|
+
ref={ref}
|
|
42
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<FaChevronDown className="h-4 w-4" />
|
|
46
|
+
</SelectPrimitive.ScrollDownButton>
|
|
47
|
+
));
|
|
48
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
49
|
+
|
|
50
|
+
const SelectContent = React.forwardRef(
|
|
51
|
+
({ className, children, position = 'popper', ...props }, ref) => (
|
|
52
|
+
<SelectPrimitive.Portal>
|
|
53
|
+
<SelectPrimitive.Content
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn(
|
|
56
|
+
'relative z-[100] max-h-80 min-w-[8rem] font-inter overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-[var(--radix-select-trigger-width)]',
|
|
57
|
+
position === 'popper' &&
|
|
58
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
position={position}
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
<SelectScrollUpButton className="text-secondary" />
|
|
65
|
+
<SelectPrimitive.Viewport
|
|
66
|
+
className={cn(
|
|
67
|
+
'p-1',
|
|
68
|
+
position === 'popper' &&
|
|
69
|
+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] font-inter'
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{children}
|
|
73
|
+
</SelectPrimitive.Viewport>
|
|
74
|
+
<SelectScrollDownButton className="text-secondary" />
|
|
75
|
+
</SelectPrimitive.Content>
|
|
76
|
+
</SelectPrimitive.Portal>
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
80
|
+
|
|
81
|
+
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (
|
|
82
|
+
<SelectPrimitive.Label
|
|
83
|
+
ref={ref}
|
|
84
|
+
className={cn('px-2 py-1.5 text-13fs font-semibold font-inter', className)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
));
|
|
88
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
89
|
+
|
|
90
|
+
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (
|
|
91
|
+
<SelectPrimitive.Item
|
|
92
|
+
ref={ref}
|
|
93
|
+
className={cn(
|
|
94
|
+
'relative flex w-full cursor-pointer select-none items-center hover:bg-neutral-100 rounded-sm py-1.5 pl-2 pr-8 text-sm focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 outline-none',
|
|
95
|
+
className
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
>
|
|
99
|
+
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
100
|
+
<SelectPrimitive.ItemIndicator>
|
|
101
|
+
<FaCheck className="h-4 w-4 text-secondary" />
|
|
102
|
+
</SelectPrimitive.ItemIndicator>
|
|
103
|
+
</span>
|
|
104
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
105
|
+
</SelectPrimitive.Item>
|
|
106
|
+
));
|
|
107
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
108
|
+
|
|
109
|
+
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (
|
|
110
|
+
<SelectPrimitive.Separator
|
|
111
|
+
ref={ref}
|
|
112
|
+
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
));
|
|
116
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
*
|
|
121
|
+
* @template T
|
|
122
|
+
* @typedef {object} ComponentProps
|
|
123
|
+
* @property {string} [placeholder]
|
|
124
|
+
* @property {T[]} values
|
|
125
|
+
* @property {T | undefined} value
|
|
126
|
+
* @property {(value: T) => string | number} getValueId
|
|
127
|
+
* @property {(value: T) => React.ReactNode} getValueLabel
|
|
128
|
+
* @property {(value: T) => void} onChange
|
|
129
|
+
* @property {boolean} [fullWidth]
|
|
130
|
+
* @property {'xxxs' | 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'} [size]
|
|
131
|
+
* @property {'sm' | 'rounded' | 'md' | 'lg' | 'xl' | 'full'} [radius]
|
|
132
|
+
* @property {boolean} [disabled]
|
|
133
|
+
* @property {string} [className]
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
*
|
|
138
|
+
*
|
|
139
|
+
* @template T
|
|
140
|
+
* @param {ComponentProps<T>} props
|
|
141
|
+
* @returns {JSX.Element}
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
const Component = ({
|
|
145
|
+
placeholder = 'Seleccionar...',
|
|
146
|
+
value,
|
|
147
|
+
values,
|
|
148
|
+
getValueId = ({ id }) => id,
|
|
149
|
+
getValueLabel = ({ name }) => name,
|
|
150
|
+
onChange,
|
|
151
|
+
fullWidth,
|
|
152
|
+
customOption,
|
|
153
|
+
disabled,
|
|
154
|
+
contentClass,
|
|
155
|
+
}) => {
|
|
156
|
+
let id;
|
|
157
|
+
if (value) {
|
|
158
|
+
id = getValueId(value);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const valuesLookup = React.useMemo(
|
|
162
|
+
() =>
|
|
163
|
+
values.reduce((values, value) => {
|
|
164
|
+
const id = getValueId(value);
|
|
165
|
+
values[id] = value;
|
|
166
|
+
return values;
|
|
167
|
+
}, {}),
|
|
168
|
+
[getValueId, values]
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const onValueChange = React.useCallback(
|
|
172
|
+
(id) => {
|
|
173
|
+
const value = valuesLookup[id];
|
|
174
|
+
onChange(value);
|
|
175
|
+
},
|
|
176
|
+
[onChange, valuesLookup]
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<SelectRoot value={id} onValueChange={onValueChange} disabled={disabled}>
|
|
181
|
+
<SelectTrigger
|
|
182
|
+
className={cn(
|
|
183
|
+
'outline-none bg-white',
|
|
184
|
+
fullWidth ? 'w-full' : 'w-64',
|
|
185
|
+
'data-placeholder:text-black/25'
|
|
186
|
+
)}
|
|
187
|
+
>
|
|
188
|
+
<SelectValue placeholder={placeholder} />
|
|
189
|
+
</SelectTrigger>
|
|
190
|
+
<SelectContent className={contentClass}>
|
|
191
|
+
{values.map((value, key) => {
|
|
192
|
+
const id = getValueId(value);
|
|
193
|
+
const label = getValueLabel(value);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<SelectItem key={key} value={id}>
|
|
197
|
+
{label}
|
|
198
|
+
</SelectItem>
|
|
199
|
+
);
|
|
200
|
+
})}
|
|
201
|
+
{customOption}
|
|
202
|
+
</SelectContent>
|
|
203
|
+
</SelectRoot>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const Select = memo(Component);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as SheetPrimitive from '@radix-ui/react-dialog';
|
|
2
|
+
import { cn } from '../libs';
|
|
3
|
+
|
|
4
|
+
function Sheet({ ...props }) {
|
|
5
|
+
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function SheetTrigger({ ...props }) {
|
|
9
|
+
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function SheetClose({ ...props }) {
|
|
13
|
+
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function SheetPortal({ ...props }) {
|
|
17
|
+
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function SheetOverlay({ className, ...props }) {
|
|
21
|
+
return (
|
|
22
|
+
<SheetPrimitive.Overlay
|
|
23
|
+
data-slot="sheet-overlay"
|
|
24
|
+
className={cn(
|
|
25
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-40 bg-black/50',
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function SheetContent({ className, children, side = 'right', ...props }) {
|
|
34
|
+
return (
|
|
35
|
+
<SheetPortal>
|
|
36
|
+
<SheetOverlay />
|
|
37
|
+
<SheetPrimitive.Content
|
|
38
|
+
data-slot="sheet-content"
|
|
39
|
+
className={cn(
|
|
40
|
+
'bg-bg data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
|
41
|
+
side === 'right' &&
|
|
42
|
+
'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
|
|
43
|
+
side === 'left' &&
|
|
44
|
+
'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
|
|
45
|
+
side === 'top' &&
|
|
46
|
+
'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
|
|
47
|
+
side === 'bottom' &&
|
|
48
|
+
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
|
55
|
+
<XIcon className="size-4" />
|
|
56
|
+
<span className="sr-only">Close</span>
|
|
57
|
+
</SheetPrimitive.Close>
|
|
58
|
+
</SheetPrimitive.Content>
|
|
59
|
+
</SheetPortal>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function SheetHeader({ className, ...props }) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
data-slot="sheet-header"
|
|
67
|
+
className={cn('flex flex-col gap-1.5 p-4', className)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function SheetFooter({ className, ...props }) {
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
data-slot="sheet-footer"
|
|
77
|
+
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function SheetTitle({ className, ...props }) {
|
|
84
|
+
return (
|
|
85
|
+
<SheetPrimitive.Title
|
|
86
|
+
data-slot="sheet-title"
|
|
87
|
+
className={cn('text-foreground font-semibold', className)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function SheetDescription({ className, ...props }) {
|
|
94
|
+
return (
|
|
95
|
+
<SheetPrimitive.Description
|
|
96
|
+
data-slot="sheet-description"
|
|
97
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
Sheet,
|
|
105
|
+
SheetTrigger,
|
|
106
|
+
SheetClose,
|
|
107
|
+
SheetContent,
|
|
108
|
+
SheetHeader,
|
|
109
|
+
SheetFooter,
|
|
110
|
+
SheetTitle,
|
|
111
|
+
SheetDescription,
|
|
112
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
fontSizeLookup,
|
|
4
|
+
fontSizeMdLookup,
|
|
5
|
+
fontSizeLgLookup,
|
|
6
|
+
fontWeightLookup,
|
|
7
|
+
fontWeightMdLookup,
|
|
8
|
+
fontWeightLgLookup,
|
|
9
|
+
textAlignLookup,
|
|
10
|
+
textAlignMdLookup,
|
|
11
|
+
textAlignLgLookup,
|
|
12
|
+
colorLookup,
|
|
13
|
+
fontFamilyLookup,
|
|
14
|
+
fontFamilyMdLookup,
|
|
15
|
+
fontFamilyLgLookup,
|
|
16
|
+
fontSizeXlLookup,
|
|
17
|
+
fontWeightXlLookup,
|
|
18
|
+
textAlignXlLookup,
|
|
19
|
+
fontFamilyXlLookup,
|
|
20
|
+
fontSize2xlLookup,
|
|
21
|
+
fontWeight2xlLookup,
|
|
22
|
+
colorMdLookup,
|
|
23
|
+
colorLgLookup,
|
|
24
|
+
colorXlLookup,
|
|
25
|
+
} from '../theme';
|
|
26
|
+
import { cn } from '../libs';
|
|
27
|
+
import { getClassName } from '../utils';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {'base' | 'md' | 'lg' | 'xl' | '2xl'} Breakpoint
|
|
31
|
+
*
|
|
32
|
+
* @typedef {'xs'
|
|
33
|
+
* | 'sm'
|
|
34
|
+
* | 'base'
|
|
35
|
+
* | 'lg'
|
|
36
|
+
* | 'xl'
|
|
37
|
+
* | '2xl'
|
|
38
|
+
* | '3xl'
|
|
39
|
+
* | '4xl'
|
|
40
|
+
* | '5xl'
|
|
41
|
+
* | '6xl'
|
|
42
|
+
* | '7xl'
|
|
43
|
+
* | '8xl'
|
|
44
|
+
* | '9xl'} Size
|
|
45
|
+
*
|
|
46
|
+
*
|
|
47
|
+
* @typedef {'left' | 'center' | 'right' | 'justify' | 'start' | 'end'} Align
|
|
48
|
+
*
|
|
49
|
+
* @typedef {'thin'
|
|
50
|
+
* | 'extralight'
|
|
51
|
+
* | 'light'
|
|
52
|
+
* | 'normal'
|
|
53
|
+
* | 'medium'
|
|
54
|
+
* | 'semibold'
|
|
55
|
+
* | 'bold'
|
|
56
|
+
* | 'extrabold'
|
|
57
|
+
* | 'black'} Weight
|
|
58
|
+
*
|
|
59
|
+
*
|
|
60
|
+
* @typedef {''} Font
|
|
61
|
+
*
|
|
62
|
+
* @typedef {'primary' | 'secondary' | 'success' | 'danger' | 'white' | 'black'} Color
|
|
63
|
+
*
|
|
64
|
+
* @typedef {object} ComponentProps
|
|
65
|
+
* @property {Size | Record<Breakpoint, Size>} [size]
|
|
66
|
+
* @property {Weight | Record<Breakpoint, Weight>} [weight]
|
|
67
|
+
* @property {Font | Record<Breakpoint, Font>} [font]
|
|
68
|
+
* @property {Align | Record<Breakpoint, Align>} [align]
|
|
69
|
+
* @property {boolean | Record<Breakpoint, boolean>} [truncate]
|
|
70
|
+
* @property {Color | Record<Breakpoint, Color>} [color]
|
|
71
|
+
* @param {React.ComponentProps<'p'> & ComponentProps} props
|
|
72
|
+
* @returns {JSX.Element}
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
const Component = (
|
|
76
|
+
{ size, weight, align, truncate, color, font, animation, className, ...rest },
|
|
77
|
+
ref
|
|
78
|
+
) => {
|
|
79
|
+
return (
|
|
80
|
+
<p
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn(
|
|
83
|
+
typeof size !== 'object' && getClassName(size, fontSizeLookup),
|
|
84
|
+
getClassName(size?.base, fontSizeLookup),
|
|
85
|
+
getClassName(size?.md, fontSizeMdLookup),
|
|
86
|
+
getClassName(size?.lg, fontSizeLgLookup),
|
|
87
|
+
getClassName(size?.xl, fontSizeXlLookup),
|
|
88
|
+
getClassName(size?.['2xl'], fontSize2xlLookup),
|
|
89
|
+
typeof weight !== 'object' && getClassName(weight, fontWeightLookup),
|
|
90
|
+
getClassName(weight?.base, fontWeightLookup),
|
|
91
|
+
getClassName(weight?.md, fontWeightMdLookup),
|
|
92
|
+
getClassName(weight?.lg, fontWeightLgLookup),
|
|
93
|
+
getClassName(weight?.xl, fontWeightXlLookup),
|
|
94
|
+
getClassName(weight?.['2xl'], fontWeight2xlLookup),
|
|
95
|
+
typeof align !== 'object' && getClassName(align, textAlignLookup),
|
|
96
|
+
getClassName(align?.base, textAlignLookup),
|
|
97
|
+
getClassName(align?.md, textAlignMdLookup),
|
|
98
|
+
getClassName(align?.lg, textAlignLgLookup),
|
|
99
|
+
getClassName(align?.xl, textAlignXlLookup),
|
|
100
|
+
typeof font !== 'object' && getClassName(font, fontFamilyLookup),
|
|
101
|
+
getClassName(font?.base, fontFamilyLookup),
|
|
102
|
+
getClassName(font?.md, fontFamilyMdLookup),
|
|
103
|
+
getClassName(font?.lg, fontFamilyLgLookup),
|
|
104
|
+
getClassName(font?.xl, fontFamilyXlLookup),
|
|
105
|
+
typeof font !== 'object' && getClassName(color, colorLookup),
|
|
106
|
+
getClassName(color?.base, colorLookup),
|
|
107
|
+
getClassName(color?.md, colorMdLookup),
|
|
108
|
+
getClassName(color?.lg, colorLgLookup),
|
|
109
|
+
getClassName(color?.xl, colorXlLookup),
|
|
110
|
+
typeof truncate !== 'object' && truncate && 'truncate',
|
|
111
|
+
truncate?.base && 'truncate',
|
|
112
|
+
truncate?.md && 'md:truncate',
|
|
113
|
+
truncate?.lg && 'lg:truncate',
|
|
114
|
+
truncate?.xl && 'xl:truncate',
|
|
115
|
+
className
|
|
116
|
+
)}
|
|
117
|
+
{...rest}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const Text = memo(React.forwardRef(Component));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Toaster as Toasts } from 'react-hot-toast';
|
|
3
|
+
|
|
4
|
+
export const Toaster = React.memo(() => {
|
|
5
|
+
return (
|
|
6
|
+
<Toasts
|
|
7
|
+
position="top-right"
|
|
8
|
+
toastOptions={{
|
|
9
|
+
style: {
|
|
10
|
+
borderRadius: '8px',
|
|
11
|
+
fontSize: '13px',
|
|
12
|
+
background: '#fff',
|
|
13
|
+
color: '#000',
|
|
14
|
+
},
|
|
15
|
+
error: {
|
|
16
|
+
style: {
|
|
17
|
+
background: '#fe8686',
|
|
18
|
+
color: '#fff',
|
|
19
|
+
backdropFilter: 'blur(20px)',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
success: {
|
|
23
|
+
style: {
|
|
24
|
+
background: '#c2fcbf',
|
|
25
|
+
backdropFilter: 'blur(20px)',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Toaster } from './Toaster';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const parseString = (value) => {
|
|
2
|
+
const fallback = '';
|
|
3
|
+
if (!value) return fallback;
|
|
4
|
+
const isString = typeof value === 'string';
|
|
5
|
+
if (!isString) return fallback;
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const parseArray = (value) => {
|
|
10
|
+
const fallback = [];
|
|
11
|
+
if (!value) return fallback;
|
|
12
|
+
const isArray = Array.isArray(value);
|
|
13
|
+
if (!isArray) return value;
|
|
14
|
+
return value;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const parseNumberForValidator = (value) => {
|
|
18
|
+
const fallback = '';
|
|
19
|
+
if (!value) return fallback;
|
|
20
|
+
const isNullish = value === undefined || value === null;
|
|
21
|
+
if (isNullish) return fallback;
|
|
22
|
+
const isValid = typeof value === 'number';
|
|
23
|
+
if (!isValid) return fallback;
|
|
24
|
+
return fallback;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const parseJSON = (value) => {
|
|
28
|
+
const fallback = {};
|
|
29
|
+
if (!value) return fallback;
|
|
30
|
+
const isNotValid = typeof value === 'string';
|
|
31
|
+
if (isNotValid) return fallback;
|
|
32
|
+
const isValid = typeof value === 'object';
|
|
33
|
+
if (isValid) return value;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(value);
|
|
37
|
+
return parsed;
|
|
38
|
+
} catch {
|
|
39
|
+
return fallback;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const tryCatch = (fn, ...args) => {
|
|
2
|
+
try {
|
|
3
|
+
const result = fn(...args);
|
|
4
|
+
|
|
5
|
+
if (result instanceof Promise) {
|
|
6
|
+
return result.then((result) => [null, result]).catch((error) => [error, null]);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return [null, result];
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return [error, null];
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// https://vite.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
"@": path.resolve(import.meta.dirname, "./src"),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
preview: {
|
|
14
|
+
port: 3000,
|
|
15
|
+
},
|
|
16
|
+
server: {
|
|
17
|
+
port: 3000,
|
|
18
|
+
},
|
|
19
|
+
});
|