@ourtrip/ui 1.0.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/dist/components/accordion.js +19 -0
- package/dist/components/alert.js +36 -0
- package/dist/components/badge.js +47 -0
- package/dist/components/breadcrumbs.js +22 -0
- package/dist/components/button.js +155 -0
- package/dist/components/card.js +29 -0
- package/dist/components/checkbox.js +24 -0
- package/dist/components/collapse.js +16 -0
- package/dist/components/divider.js +38 -0
- package/dist/components/input.js +58 -0
- package/dist/components/modal.js +10 -0
- package/dist/components/phone.js +53 -0
- package/dist/components/popover.js +35 -0
- package/dist/components/radio.js +38 -0
- package/dist/components/range.js +19 -0
- package/dist/components/select.js +84 -0
- package/dist/components/sheet.js +82 -0
- package/dist/components/stars.js +10 -0
- package/dist/components/step-marker.js +18 -0
- package/dist/components/switch.js +15 -0
- package/dist/components/tag.js +16 -0
- package/dist/components/tooltip.js +9 -0
- package/dist/index.js +22 -0
- package/dist/types/components/accordion.d.ts +7 -0
- package/dist/types/components/alert.d.ts +10 -0
- package/dist/types/components/badge.d.ts +12 -0
- package/dist/types/components/breadcrumbs.d.ts +11 -0
- package/dist/types/components/button.d.ts +19 -0
- package/dist/types/components/card.d.ts +6 -0
- package/dist/types/components/checkbox.d.ts +11 -0
- package/dist/types/components/collapse.d.ts +15 -0
- package/dist/types/components/divider.d.ts +8 -0
- package/dist/types/components/input.d.ts +14 -0
- package/dist/types/components/modal.d.ts +10 -0
- package/dist/types/components/phone.d.ts +18 -0
- package/dist/types/components/popover.d.ts +6 -0
- package/dist/types/components/radio.d.ts +8 -0
- package/dist/types/components/range.d.ts +10 -0
- package/dist/types/components/select.d.ts +13 -0
- package/dist/types/components/sheet.d.ts +25 -0
- package/dist/types/components/stars.d.ts +6 -0
- package/dist/types/components/step-marker.d.ts +11 -0
- package/dist/types/components/switch.d.ts +9 -0
- package/dist/types/components/tag.d.ts +11 -0
- package/dist/types/components/tooltip.d.ts +8 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/utils/classes.d.ts +1 -0
- package/dist/types/utils/validation.d.ts +12 -0
- package/dist/utils/classes.js +7 -0
- package/dist/utils/validation.js +128 -0
- package/ourtrip-ui-1.0.0.tgz +0 -0
- package/package.json +47 -0
- package/src/components/accordion.tsx +52 -0
- package/src/components/alert.tsx +56 -0
- package/src/components/badge.tsx +84 -0
- package/src/components/breadcrumbs.tsx +48 -0
- package/src/components/button.tsx +187 -0
- package/src/components/card.tsx +23 -0
- package/src/components/checkbox.tsx +70 -0
- package/src/components/collapse.tsx +56 -0
- package/src/components/divider.tsx +28 -0
- package/src/components/input.tsx +105 -0
- package/src/components/modal.tsx +40 -0
- package/src/components/phone.tsx +104 -0
- package/src/components/popover.tsx +31 -0
- package/src/components/radio.tsx +44 -0
- package/src/components/range.tsx +54 -0
- package/src/components/select.tsx +160 -0
- package/src/components/sheet.tsx +140 -0
- package/src/components/stars.tsx +30 -0
- package/src/components/step-marker.tsx +49 -0
- package/src/components/switch.tsx +42 -0
- package/src/components/tag.tsx +52 -0
- package/src/components/tooltip.tsx +30 -0
- package/src/index.tsx +22 -0
- package/src/utils/classes.ts +2 -0
- package/src/utils/validation.ts +164 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isBefore, isValid, parse, subYears } from 'date-fns';
|
|
2
|
+
export var isValidCpf = function (formatedCpf) {
|
|
3
|
+
var cpf = formatedCpf.replace(/\D/g, '');
|
|
4
|
+
if (cpf.length !== 11 || /^(\d)\1+$/.test(cpf)) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
// Calcular el primer dígito verificador
|
|
8
|
+
var soma = 0;
|
|
9
|
+
for (var i = 0; i < 9; i++) {
|
|
10
|
+
soma += parseInt(cpf.charAt(i), 10) * (10 - i);
|
|
11
|
+
}
|
|
12
|
+
var digito1 = 11 - (soma % 11);
|
|
13
|
+
if (digito1 > 9) {
|
|
14
|
+
digito1 = 0;
|
|
15
|
+
}
|
|
16
|
+
// Calcular el segundo dígito verificador
|
|
17
|
+
soma = 0;
|
|
18
|
+
for (var i = 0; i < 10; i++) {
|
|
19
|
+
soma += parseInt(cpf.charAt(i), 10) * (11 - i);
|
|
20
|
+
}
|
|
21
|
+
var digito2 = 11 - (soma % 11);
|
|
22
|
+
if (digito2 > 9) {
|
|
23
|
+
digito2 = 0;
|
|
24
|
+
}
|
|
25
|
+
// Verificar si los dígitos verificadores son iguales a los últimos dos dígitos del CPF
|
|
26
|
+
if (parseInt(cpf.charAt(9), 10) === digito1 &&
|
|
27
|
+
parseInt(cpf.charAt(10), 10) === digito2) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
export var isValidCNPJ = function (formatedCnpj) {
|
|
33
|
+
var cnpj = formatedCnpj.replace(/[^\d]+/g, '');
|
|
34
|
+
if (cnpj.length !== 14) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (/^(\d)\1+$/.test(cnpj)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
var length = cnpj.length - 2;
|
|
41
|
+
var numbers = cnpj.substring(0, length);
|
|
42
|
+
var digitosVerificadores = cnpj.substring(length);
|
|
43
|
+
var soma = 0;
|
|
44
|
+
var pos = length - 7;
|
|
45
|
+
for (var i = length; i >= 1; i--) {
|
|
46
|
+
soma += parseInt(numbers.charAt(length - i), 10) * pos--;
|
|
47
|
+
if (pos < 2) {
|
|
48
|
+
pos = 9;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
var resultado = soma % 11 < 2 ? 0 : 11 - (soma % 11);
|
|
52
|
+
if (resultado !== parseInt(digitosVerificadores.charAt(0), 10)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
length += 1;
|
|
56
|
+
numbers = cnpj.substring(0, length);
|
|
57
|
+
soma = 0;
|
|
58
|
+
pos = length - 7;
|
|
59
|
+
for (var i = length; i >= 1; i--) {
|
|
60
|
+
soma += parseInt(numbers.charAt(length - i), 10) * pos--;
|
|
61
|
+
if (pos < 2) {
|
|
62
|
+
pos = 9;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var segundoDigito = soma % 11 < 2 ? 0 : 11 - (soma % 11);
|
|
66
|
+
return segundoDigito === parseInt(digitosVerificadores.charAt(1), 10);
|
|
67
|
+
};
|
|
68
|
+
export var isCPF = function (document) {
|
|
69
|
+
var onlyNumbers = document === null || document === void 0 ? void 0 : document.replace(/\D/g, '');
|
|
70
|
+
if ((onlyNumbers === null || onlyNumbers === void 0 ? void 0 : onlyNumbers.length) === 11 && isValidCpf(onlyNumbers))
|
|
71
|
+
return true;
|
|
72
|
+
return false;
|
|
73
|
+
};
|
|
74
|
+
export var isCNPJ = function (document) {
|
|
75
|
+
var onlyNumbers = document === null || document === void 0 ? void 0 : document.replace(/\D/g, '');
|
|
76
|
+
if ((onlyNumbers === null || onlyNumbers === void 0 ? void 0 : onlyNumbers.length) === 14 && isValidCNPJ(onlyNumbers))
|
|
77
|
+
return true;
|
|
78
|
+
return false;
|
|
79
|
+
};
|
|
80
|
+
export var isFullName = function (name) {
|
|
81
|
+
return /^(?:[A-Za-zÀ-ÿ]{2,}(?: [A-Za-zÀ-ÿ]{2,})+)$/.test(name.trim());
|
|
82
|
+
};
|
|
83
|
+
export var isValidName = function (name) {
|
|
84
|
+
return /^[A-Za-zÀ-ÿ\s.'-]+(?: [A-Za-zÀ-ÿ\s.'-]+)*$/.test(name.trim());
|
|
85
|
+
};
|
|
86
|
+
export var isValidEmail = function (email) {
|
|
87
|
+
return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(email.trim());
|
|
88
|
+
};
|
|
89
|
+
export var isValidPhoneNumber = function (number) {
|
|
90
|
+
var phoneNumber = number.replace('-', '');
|
|
91
|
+
return /^\d{8}$/.test(phoneNumber) || /^\d{9}$/.test(phoneNumber);
|
|
92
|
+
};
|
|
93
|
+
export var isValidNumberCode = function (numberCode) {
|
|
94
|
+
return /^\d{2}$/.test(numberCode.replace(/[()]/g, ''));
|
|
95
|
+
};
|
|
96
|
+
export var isValidDDD = function (areaCode) {
|
|
97
|
+
var dddList = [
|
|
98
|
+
11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 28, 31, 32, 33, 34, 35,
|
|
99
|
+
37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 53, 54, 55, 61, 62, 64, 63,
|
|
100
|
+
65, 66, 67, 68, 69, 71, 73, 74, 75, 77, 79, 81, 82, 83, 84, 85, 86, 87, 88,
|
|
101
|
+
89, 91, 92, 93, 94, 95, 96, 97, 98, 99
|
|
102
|
+
];
|
|
103
|
+
return dddList.includes(parseFloat(areaCode === null || areaCode === void 0 ? void 0 : areaCode.replace(/\D/g, '')));
|
|
104
|
+
};
|
|
105
|
+
export var isValidChildDate = function (date) {
|
|
106
|
+
if (!date)
|
|
107
|
+
return 'Data inválida';
|
|
108
|
+
var birthDate = parse(date, 'yyyy-MM-dd', new Date());
|
|
109
|
+
if (!isValid(birthDate)) {
|
|
110
|
+
return 'Data inválida';
|
|
111
|
+
}
|
|
112
|
+
var currentDate = new Date();
|
|
113
|
+
var adultAge = subYears(currentDate, 18);
|
|
114
|
+
if (isBefore(adultAge, birthDate) && isBefore(birthDate, currentDate)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return 'Idade deve ser entre 1 a 17 anos';
|
|
118
|
+
};
|
|
119
|
+
export var isValidAdult = function (date) {
|
|
120
|
+
if (!date)
|
|
121
|
+
return 'Data inválida';
|
|
122
|
+
var birthDate = parse(date, 'yyyy-MM-dd', new Date());
|
|
123
|
+
if (!isValid(birthDate)) {
|
|
124
|
+
return 'Data inválida';
|
|
125
|
+
}
|
|
126
|
+
var adultAge = subYears(new Date(), 18);
|
|
127
|
+
return isBefore(birthDate, adultAge) || 'Adulto deve ter mais de 18 anos';
|
|
128
|
+
};
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ourtrip/ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist/index.js",
|
|
6
|
+
"types": "dist/types/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"description": "",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@babel/core": "^7.26.10",
|
|
16
|
+
"@babel/preset-env": "^7.26.9",
|
|
17
|
+
"@babel/preset-react": "^7.26.3",
|
|
18
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
19
|
+
"@radix-ui/react-dialog": "^1.1.6",
|
|
20
|
+
"@radix-ui/react-popover": "^1.1.6",
|
|
21
|
+
"@radix-ui/react-select": "^2.1.6",
|
|
22
|
+
"@types/react": "^19.0.10",
|
|
23
|
+
"@types/react-dom": "^19.0.4",
|
|
24
|
+
"@types/react-slider": "^1.3.6",
|
|
25
|
+
"date-fns": "^4.1.0",
|
|
26
|
+
"framer-motion": "^12.5.0",
|
|
27
|
+
"microbundle": "^0.15.1",
|
|
28
|
+
"react": "^19.0.0",
|
|
29
|
+
"react-dom": "^19.0.0",
|
|
30
|
+
"react-hook-form": "^7.54.2",
|
|
31
|
+
"react-slider": "^2.0.6",
|
|
32
|
+
"typescript": "^5.8.2"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
36
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@phosphor-icons/react": "^2.1.7",
|
|
40
|
+
"@tailwindcss/cli": "^4.0.13",
|
|
41
|
+
"@tailwindcss/postcss": "^4.0.13",
|
|
42
|
+
"class-variance-authority": "^0.7.1",
|
|
43
|
+
"classnames": "^2.5.1",
|
|
44
|
+
"postcss": "^8.5.3",
|
|
45
|
+
"tailwindcss": "^4.0.13"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
interface IAccordionProps {
|
|
6
|
+
title: string;
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Accordion = ({ title, text }: IAccordionProps) => {
|
|
11
|
+
const [open, setOpen] = useState<boolean>(false);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
className='w-full flex flex-col p-6 border border-gray-200 rounded-default cursor-pointer'
|
|
16
|
+
onClick={() => setOpen(prev => !prev)}
|
|
17
|
+
>
|
|
18
|
+
<div className='flex items-center gap-6'>
|
|
19
|
+
<div
|
|
20
|
+
className={`relative w-10 h-10 rounded-full flex justify-center items-center transition-colors duration-300 ${
|
|
21
|
+
open ? 'bg-primary-900' : 'bg-gray-100'
|
|
22
|
+
}`}
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
className={`absolute w-4 h-0.5 rounded transition-transform duration-300 ${
|
|
26
|
+
open
|
|
27
|
+
? 'bg-primary-900 transform rotate-[-90deg]'
|
|
28
|
+
: 'bg-primary-900 transform rotate-[-180deg]'
|
|
29
|
+
}`}
|
|
30
|
+
/>
|
|
31
|
+
<div
|
|
32
|
+
className={`absolute w-4 h-0.5 rounded transition-transform duration-300 ${
|
|
33
|
+
open
|
|
34
|
+
? 'bg-white transform rotate-0'
|
|
35
|
+
: 'bg-primary-900 transform rotate-[-90deg]'
|
|
36
|
+
}`}
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<h2 className='font-medium text-lg text-primary-900'>{title}</h2>
|
|
40
|
+
</div>
|
|
41
|
+
<div
|
|
42
|
+
className={`pl-16 overflow-hidden transition-max-height duration-500 ease-in-out ${
|
|
43
|
+
open ? 'max-h-56' : 'max-h-0'
|
|
44
|
+
}`}
|
|
45
|
+
>
|
|
46
|
+
<p className='pt-2.5 text-base text-gray-500 leading-7'>{text}</p>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default Accordion;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { FC, ReactNode } from 'react';
|
|
4
|
+
import { Check, Info, Warning, WarningCircle } from '@phosphor-icons/react';
|
|
5
|
+
|
|
6
|
+
type TAlertType = 'info' | 'success' | 'danger' | 'warning';
|
|
7
|
+
type TAlertVariant = 'fill' | 'outline';
|
|
8
|
+
|
|
9
|
+
interface IAlertProps {
|
|
10
|
+
type: TAlertType;
|
|
11
|
+
variant: TAlertVariant;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const iconByAlertType: Record<TAlertType, ReactNode> = {
|
|
16
|
+
danger: <WarningCircle size={24} />,
|
|
17
|
+
success: <Check size={24} />,
|
|
18
|
+
info: <Info size={24} />,
|
|
19
|
+
warning: <Warning size={24} />
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const Alert: FC<IAlertProps> = ({ type, variant, children }) => {
|
|
23
|
+
const baseClasses = 'rounded-default p-4 flex items-start gap-4';
|
|
24
|
+
const typeVariantClasses: Record<
|
|
25
|
+
TAlertType,
|
|
26
|
+
Record<TAlertVariant, string>
|
|
27
|
+
> = {
|
|
28
|
+
info: {
|
|
29
|
+
fill: 'bg-info-500 text-white',
|
|
30
|
+
outline: 'border border-info-500 text-info-500'
|
|
31
|
+
},
|
|
32
|
+
success: {
|
|
33
|
+
fill: 'bg-success-500 text-white',
|
|
34
|
+
outline: 'border border-success-500 text-success-500'
|
|
35
|
+
},
|
|
36
|
+
danger: {
|
|
37
|
+
fill: 'bg-danger-500 text-white',
|
|
38
|
+
outline: 'border border-danger-500 text-danger-500'
|
|
39
|
+
},
|
|
40
|
+
warning: {
|
|
41
|
+
fill: 'bg-warning-500 text-white',
|
|
42
|
+
outline: 'border border-warning-500 text-warning-500'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const className = `${baseClasses} ${typeVariantClasses[type][variant]}`;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={className}>
|
|
50
|
+
{iconByAlertType[type]}
|
|
51
|
+
<div>{children}</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default Alert;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { FC, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
type BadgeSize = 'small' | 'normal' | 'large';
|
|
6
|
+
|
|
7
|
+
interface IBadgeProps {
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
type:
|
|
11
|
+
| 'success'
|
|
12
|
+
| 'warning'
|
|
13
|
+
| 'danger'
|
|
14
|
+
| 'info'
|
|
15
|
+
| 'white'
|
|
16
|
+
| 'primary'
|
|
17
|
+
| 'secondary';
|
|
18
|
+
size?: BadgeSize;
|
|
19
|
+
mobile?: boolean;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Badge: FC<IBadgeProps> = ({
|
|
24
|
+
children,
|
|
25
|
+
icon,
|
|
26
|
+
type,
|
|
27
|
+
size = 'normal',
|
|
28
|
+
mobile,
|
|
29
|
+
className
|
|
30
|
+
}) => {
|
|
31
|
+
const baseClasses = `flex items-center rounded-button ${
|
|
32
|
+
mobile ? 'lg:hidden md:flex' : ''
|
|
33
|
+
} ${className || ''}`;
|
|
34
|
+
let typeClasses = '';
|
|
35
|
+
|
|
36
|
+
const sizeClasses = {
|
|
37
|
+
small: 'px-2 py-1 gap-0',
|
|
38
|
+
normal: 'py-2 px-3 gap-2',
|
|
39
|
+
large: 'py-3 px-4 gap-3'
|
|
40
|
+
}[size];
|
|
41
|
+
|
|
42
|
+
const textSizesClasses = {
|
|
43
|
+
small: 'text-xs font-normal',
|
|
44
|
+
normal: 'text-sm font-semibold',
|
|
45
|
+
large: 'text-base font-semibold'
|
|
46
|
+
}[size];
|
|
47
|
+
|
|
48
|
+
switch (type) {
|
|
49
|
+
case 'success':
|
|
50
|
+
typeClasses = 'bg-success-100 text-success-600';
|
|
51
|
+
break;
|
|
52
|
+
case 'warning':
|
|
53
|
+
typeClasses = 'bg-warning-100 text-warning-600';
|
|
54
|
+
break;
|
|
55
|
+
case 'danger':
|
|
56
|
+
typeClasses = 'bg-danger-100 text-danger-600';
|
|
57
|
+
break;
|
|
58
|
+
case 'info':
|
|
59
|
+
typeClasses = 'bg-info-100 text-info-900';
|
|
60
|
+
break;
|
|
61
|
+
case 'white':
|
|
62
|
+
typeClasses = 'bg-white text-gray-900';
|
|
63
|
+
break;
|
|
64
|
+
case 'primary':
|
|
65
|
+
typeClasses = 'bg-primary-500 text-white';
|
|
66
|
+
break;
|
|
67
|
+
case 'secondary':
|
|
68
|
+
typeClasses = 'bg-gray-100 text-primary-500';
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
typeClasses = '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const textClasses = `font-semibold whitespace-nowrap ${textSizesClasses}`;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={`${baseClasses} ${typeClasses} ${sizeClasses}`}>
|
|
78
|
+
{icon && <span className='mr-2'>{icon}</span>}
|
|
79
|
+
<p className={textClasses}>{children}</p>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default Badge;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
4
|
+
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
|
5
|
+
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { CaretRight } from '@phosphor-icons/react';
|
|
8
|
+
|
|
9
|
+
export type BreadcrumbsItemType = {
|
|
10
|
+
id: string;
|
|
11
|
+
text: string;
|
|
12
|
+
href: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
interface IBreadcrumbsProps {
|
|
16
|
+
items: BreadcrumbsItemType[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const Breadcrumbs = ({ items }: IBreadcrumbsProps) => {
|
|
20
|
+
return (
|
|
21
|
+
<div className='flex items-center gap-2.5'>
|
|
22
|
+
{items?.map((item, index) => {
|
|
23
|
+
const isActive = index !== items.length - 1;
|
|
24
|
+
return (
|
|
25
|
+
<div key={item.id} className='flex items-center gap-2.5'>
|
|
26
|
+
<a
|
|
27
|
+
onClick={() => {
|
|
28
|
+
if (isActive) {
|
|
29
|
+
window.open(item.href, '_blank');
|
|
30
|
+
}
|
|
31
|
+
}}
|
|
32
|
+
className={`no-underline text-blue-900 text-sm ${
|
|
33
|
+
isActive
|
|
34
|
+
? 'hover:text-blue-500 hover:cursor-pointer'
|
|
35
|
+
: 'cursor-text'
|
|
36
|
+
}`}
|
|
37
|
+
>
|
|
38
|
+
{item.text}
|
|
39
|
+
</a>
|
|
40
|
+
{isActive && <CaretRight />}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
})}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default Breadcrumbs;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { CircleNotch } from '@phosphor-icons/react';
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
6
|
+
import { cn } from '../utils/classes';
|
|
7
|
+
|
|
8
|
+
const buttonVariants = cva(
|
|
9
|
+
'flex items-center justify-center gap-2 whitespace-nowrap transition-colors focus:outline-hidden',
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
fill: '',
|
|
14
|
+
outline: 'bg-transparent border'
|
|
15
|
+
},
|
|
16
|
+
color: {
|
|
17
|
+
primary: '',
|
|
18
|
+
secondary: '',
|
|
19
|
+
danger: '',
|
|
20
|
+
gray: '',
|
|
21
|
+
white: ''
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
small: 'h-[32px] px-4 text-sm',
|
|
25
|
+
normal: 'h-[40px] px-6 text-base',
|
|
26
|
+
large: 'h-[48px] px-8 text-lg',
|
|
27
|
+
icon: 'h-[40px] w-[40px] p-0'
|
|
28
|
+
},
|
|
29
|
+
shape: {
|
|
30
|
+
default: 'rounded-inner',
|
|
31
|
+
rounded: 'rounded-full'
|
|
32
|
+
},
|
|
33
|
+
fontWeight: {
|
|
34
|
+
normal: 'font-normal',
|
|
35
|
+
bold: 'font-medium'
|
|
36
|
+
},
|
|
37
|
+
fullWidth: {
|
|
38
|
+
true: 'w-full',
|
|
39
|
+
false: ''
|
|
40
|
+
},
|
|
41
|
+
fullHeight: {
|
|
42
|
+
true: 'h-full',
|
|
43
|
+
false: ''
|
|
44
|
+
},
|
|
45
|
+
disabled: {
|
|
46
|
+
true: 'bg-gray-200 text-gray-900 border-none cursor-not-allowed hover:bg-gray-200 hover:text-gray-900',
|
|
47
|
+
false: ''
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
compoundVariants: [
|
|
51
|
+
{
|
|
52
|
+
variant: 'fill',
|
|
53
|
+
color: 'primary',
|
|
54
|
+
disabled: false,
|
|
55
|
+
className: 'bg-primary-500 text-white hover:bg-primary-400 active:bg-primary-600'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
variant: 'fill',
|
|
59
|
+
color: 'secondary',
|
|
60
|
+
disabled: false,
|
|
61
|
+
className: 'bg-secondary-500 text-white hover:bg-secondary-400 active:bg-secondary-600'
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
variant: 'fill',
|
|
65
|
+
color: 'danger',
|
|
66
|
+
disabled: false,
|
|
67
|
+
className: 'bg-red-500 text-white hover:bg-red-400 active:bg-red-600'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
variant: 'fill',
|
|
71
|
+
color: 'gray',
|
|
72
|
+
disabled: false,
|
|
73
|
+
className: 'bg-gray-100 text-gray-700 hover:bg-gray-200 active:bg-gray-300'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
variant: 'fill',
|
|
77
|
+
color: 'white',
|
|
78
|
+
disabled: false,
|
|
79
|
+
className: 'bg-white text-black hover:bg-gray-200'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
variant: 'outline',
|
|
83
|
+
color: 'primary',
|
|
84
|
+
disabled: false,
|
|
85
|
+
className:
|
|
86
|
+
'text-primary-500 border-primary-500 hover:text-primary-400 hover:border-primary-400'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
variant: 'outline',
|
|
90
|
+
color: 'secondary',
|
|
91
|
+
disabled: false,
|
|
92
|
+
className:
|
|
93
|
+
'text-secondary-500 border-secondary-500 hover:text-secondary-400 hover:border-secondary-400'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
variant: 'outline',
|
|
97
|
+
color: 'danger',
|
|
98
|
+
disabled: false,
|
|
99
|
+
className:
|
|
100
|
+
'text-red-500 border-red-500 hover:text-red-400 hover:border-red-400'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
variant: 'outline',
|
|
104
|
+
color: 'gray',
|
|
105
|
+
disabled: false,
|
|
106
|
+
className:
|
|
107
|
+
'text-gray-300 border-gray-300 hover:text-gray-500 hover:border-gray-400'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
variant: 'outline',
|
|
111
|
+
color: 'white',
|
|
112
|
+
disabled: false,
|
|
113
|
+
className:
|
|
114
|
+
'text-white border-white hover:text-gray-200 hover:border-gray-200'
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
defaultVariants: {
|
|
118
|
+
variant: 'fill',
|
|
119
|
+
color: 'primary',
|
|
120
|
+
size: 'normal',
|
|
121
|
+
shape: 'default',
|
|
122
|
+
fontWeight: 'normal',
|
|
123
|
+
fullWidth: false,
|
|
124
|
+
fullHeight: false,
|
|
125
|
+
disabled: false
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
interface ButtonProps
|
|
131
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
132
|
+
VariantProps<typeof buttonVariants> {
|
|
133
|
+
loading?: boolean;
|
|
134
|
+
color?: 'primary' | 'secondary' | 'danger' | 'gray' | 'white';
|
|
135
|
+
disabled?: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
139
|
+
(
|
|
140
|
+
{
|
|
141
|
+
className,
|
|
142
|
+
variant,
|
|
143
|
+
color,
|
|
144
|
+
size,
|
|
145
|
+
shape,
|
|
146
|
+
fontWeight,
|
|
147
|
+
fullWidth,
|
|
148
|
+
fullHeight,
|
|
149
|
+
disabled,
|
|
150
|
+
loading = false,
|
|
151
|
+
children,
|
|
152
|
+
...props
|
|
153
|
+
},
|
|
154
|
+
ref
|
|
155
|
+
) => {
|
|
156
|
+
return (
|
|
157
|
+
<button
|
|
158
|
+
className={cn(
|
|
159
|
+
buttonVariants({
|
|
160
|
+
variant,
|
|
161
|
+
color,
|
|
162
|
+
size,
|
|
163
|
+
shape,
|
|
164
|
+
fontWeight,
|
|
165
|
+
fullWidth,
|
|
166
|
+
fullHeight,
|
|
167
|
+
disabled: disabled || loading
|
|
168
|
+
}),
|
|
169
|
+
className
|
|
170
|
+
)}
|
|
171
|
+
ref={ref}
|
|
172
|
+
disabled={disabled || loading}
|
|
173
|
+
{...props}
|
|
174
|
+
>
|
|
175
|
+
{loading ? (
|
|
176
|
+
<CircleNotch className='animate-spin' weight='bold' />
|
|
177
|
+
) : (
|
|
178
|
+
children
|
|
179
|
+
)}
|
|
180
|
+
</button>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
Button.displayName = 'Button';
|
|
186
|
+
|
|
187
|
+
export default Button;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { FC, HTMLAttributes, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
interface ICardProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Card: FC<ICardProps & HTMLAttributes<HTMLDivElement>> = ({
|
|
10
|
+
children,
|
|
11
|
+
...props
|
|
12
|
+
}) => {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
className='p-4 rounded-default border bg-white border-gray-200'
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default Card;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { ReactNode, memo, useEffect, useState } from 'react';
|
|
4
|
+
import { Check } from '@phosphor-icons/react';
|
|
5
|
+
import Stars from './stars';
|
|
6
|
+
|
|
7
|
+
interface ICheckbox {
|
|
8
|
+
value?: boolean;
|
|
9
|
+
// eslint-disable-next-line no-unused-vars
|
|
10
|
+
onChange?: (checked: boolean) => void;
|
|
11
|
+
label?: ReactNode;
|
|
12
|
+
trailing?: string | number;
|
|
13
|
+
textColor?: 'primary';
|
|
14
|
+
type?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Checkbox = ({
|
|
18
|
+
value,
|
|
19
|
+
onChange,
|
|
20
|
+
label,
|
|
21
|
+
trailing,
|
|
22
|
+
textColor,
|
|
23
|
+
type
|
|
24
|
+
}: ICheckbox) => {
|
|
25
|
+
const [checked, setChecked] = useState<boolean>(value || false);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (value !== undefined) setChecked(value);
|
|
28
|
+
}, [value]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className='w-full flex items-center justify-between cursor-pointer gap-2 select-none'
|
|
33
|
+
onClick={() => {
|
|
34
|
+
setChecked(prev => !prev);
|
|
35
|
+
onChange?.(!checked);
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<div className='flex items-center gap-2'>
|
|
39
|
+
<div
|
|
40
|
+
className={`w-5 h-5 flex items-center justify-center border border-primary-500 rounded-md flex-none mt-[3px] hover:bg-primary-500 ${
|
|
41
|
+
checked ? 'bg-primary-500' : ''
|
|
42
|
+
}`}
|
|
43
|
+
>
|
|
44
|
+
{checked && <Check size={12} color='white' weight='bold' />}
|
|
45
|
+
</div>
|
|
46
|
+
{label && (
|
|
47
|
+
<p
|
|
48
|
+
className={`flex items-center gap-1 text-sm mt-1 ${
|
|
49
|
+
textColor === 'primary' ? 'text-primary-900' : 'text-gray-500'
|
|
50
|
+
}`}
|
|
51
|
+
>
|
|
52
|
+
{type === 'stars' ? (
|
|
53
|
+
<Stars rate={parseFloat(label.toString())} />
|
|
54
|
+
) : (
|
|
55
|
+
label
|
|
56
|
+
)}
|
|
57
|
+
</p>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
60
|
+
{trailing !== undefined && (
|
|
61
|
+
<p className='text-sm text-gray-500'>{trailing}</p>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const propsAreEqual = (prevProps: ICheckbox, nextProps: ICheckbox) =>
|
|
68
|
+
prevProps.value === nextProps.value && prevProps.label === nextProps.label;
|
|
69
|
+
|
|
70
|
+
export default memo(Checkbox, propsAreEqual);
|