naria-ui 0.1.35 → 0.1.37
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/naria-ui.css +1 -0
- package/lib/components/Button/Button.tsx +16 -0
- package/lib/components/Button/index.ts +1 -0
- package/lib/components/Input/Input.tsx +59 -0
- package/lib/components/Input/index.ts +1 -0
- package/lib/components/Select/Select.tsx +171 -0
- package/lib/components/Select/index.ts +1 -0
- package/lib/components/Select/select.scss +52 -0
- package/lib/components/index.ts +3 -0
- package/lib/index.ts +2 -0
- package/lib/utils/capitalize.ts +4 -0
- package/lib/utils/index.ts +2 -0
- package/lib/utils/navigator.ts +29 -0
- package/package.json +5 -5
- package/src/App.css +0 -0
- package/src/App.tsx +15 -0
- package/src/assets/icons/angle-down.svg +1 -0
- package/src/assets/icons/angle-left.svg +1 -0
- package/src/assets/icons/angle-right.svg +1 -0
- package/src/assets/icons/angle-up.svg +1 -0
- package/src/assets/icons/close.svg +1 -0
- package/src/assets/styles/index.css +1 -0
- package/src/assets/styles/select.scss +52 -0
- package/src/index.css +0 -0
- package/src/main.tsx +10 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.naria-select{position:relative}.naria-select .wrapper{overflow:hidden}.naria-select .wrapper.mobile{position:fixed;top:0;right:0;height:100%;width:100%;z-index:97}.naria-select .list{display:flex;flex-direction:column;width:100%;z-index:99}.naria-select .list.mobile{position:relative;height:100%}.naria-select .list.desktop{overflow:auto;position:absolute;animation:fadeInTranslateY .3s ease-out forwards}.naria-select .backdrop-select{position:fixed;top:0;left:0;bottom:0;width:100%;height:100%;z-index:98;background-color:#0003}@keyframes fadeInTranslateY{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, {FC} from "react";
|
|
2
|
+
|
|
3
|
+
export interface props extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
|
4
|
+
type?: "button" | "submit";
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
export const Button: FC<props> = ({type = "button", value}) => {
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<button type={type}>
|
|
11
|
+
{value}
|
|
12
|
+
</button>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Button } from './Button';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {FC} from "react";
|
|
2
|
+
|
|
3
|
+
export interface props {
|
|
4
|
+
type?: "password" | "text";
|
|
5
|
+
wrapperClass?: string;
|
|
6
|
+
labelClass?: string;
|
|
7
|
+
inputClass?: string;
|
|
8
|
+
errorClass?: string;
|
|
9
|
+
placeholder: string;
|
|
10
|
+
label: string;
|
|
11
|
+
hasError?: string | null;
|
|
12
|
+
register?: any;
|
|
13
|
+
name?: string;
|
|
14
|
+
isDisabled?: boolean;
|
|
15
|
+
autocomplete?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Input: FC<props> = ({
|
|
19
|
+
type = "text",
|
|
20
|
+
placeholder,
|
|
21
|
+
wrapperClass = "",
|
|
22
|
+
labelClass = "",
|
|
23
|
+
inputClass = "",
|
|
24
|
+
errorClass = "",
|
|
25
|
+
label,
|
|
26
|
+
hasError,
|
|
27
|
+
register, name,
|
|
28
|
+
isDisabled = false,
|
|
29
|
+
autocomplete = false,
|
|
30
|
+
...otherProps
|
|
31
|
+
}) => {
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className={wrapperClass}>
|
|
35
|
+
<label
|
|
36
|
+
htmlFor={name}
|
|
37
|
+
className={`${labelClass} ${hasError && "error"}`}>
|
|
38
|
+
{label}
|
|
39
|
+
<input
|
|
40
|
+
disabled={isDisabled}
|
|
41
|
+
autoComplete={autocomplete ? "on" : "off"}
|
|
42
|
+
id={name}
|
|
43
|
+
{...register}
|
|
44
|
+
{...otherProps}
|
|
45
|
+
type={type}
|
|
46
|
+
name={name}
|
|
47
|
+
className={`${inputClass} ${hasError && "error"} ${errorClass}`}
|
|
48
|
+
placeholder={placeholder}
|
|
49
|
+
/>
|
|
50
|
+
</label>
|
|
51
|
+
{
|
|
52
|
+
hasError &&
|
|
53
|
+
<p className={errorClass}>{hasError}</p>
|
|
54
|
+
}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Input } from './Input';
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {FC, useEffect, useState} from "react";
|
|
2
|
+
import AngleDown from "../../../src/assets/icons/angle-down.svg?react";
|
|
3
|
+
import Close from '../../../src/assets/icons/close.svg?react';
|
|
4
|
+
import {useWidth} from "../../../hooks/use-width";
|
|
5
|
+
import Loading from "../../../shared/loading/Loading";
|
|
6
|
+
import './select.scss';
|
|
7
|
+
import {addNavigation, onHashChanges, removeNavigation} from "../../utils/navigator";
|
|
8
|
+
|
|
9
|
+
export interface props {
|
|
10
|
+
list?: any[];
|
|
11
|
+
label?: string;
|
|
12
|
+
title: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
api?: any;
|
|
15
|
+
maxHeight?: string;
|
|
16
|
+
theme?: "secondary";
|
|
17
|
+
hasError?: string | null;
|
|
18
|
+
size?: "md" | "sm";
|
|
19
|
+
onSelectChange?: any;
|
|
20
|
+
selected?: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Select: FC<props> = ({
|
|
24
|
+
list, label, hasError,
|
|
25
|
+
title, value, api,
|
|
26
|
+
maxHeight = "max-h-64", theme = "secondary", size = "md",
|
|
27
|
+
onSelectChange,
|
|
28
|
+
selected
|
|
29
|
+
}) => {
|
|
30
|
+
const getDeviceWidth = useWidth();
|
|
31
|
+
const [isShow, setIsShow] = useState(false);
|
|
32
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
33
|
+
const [localSelected, setLocalSelected] = useState(null);
|
|
34
|
+
const [localList, setLocalList] = useState(null);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (api) {
|
|
37
|
+
setIsLoading(true);
|
|
38
|
+
api().then((res) => {
|
|
39
|
+
setIsLoading(false);
|
|
40
|
+
setLocalList(res?.data?.message ? [] : res.data);
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}, [api]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (getDeviceWidth < 1024) {
|
|
46
|
+
|
|
47
|
+
if (isShow) {
|
|
48
|
+
addNavigation('select');
|
|
49
|
+
document.body.style.overflow = 'hidden';
|
|
50
|
+
} else {
|
|
51
|
+
|
|
52
|
+
if (window.location.hash && !document.referrer.includes('#')) {
|
|
53
|
+
removeNavigation();
|
|
54
|
+
}
|
|
55
|
+
document.body.style.overflow = 'auto';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}, [isShow]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (label?.length) {
|
|
62
|
+
setLocalSelected(localList?.find(item => item[label] === selected));
|
|
63
|
+
} else {
|
|
64
|
+
setLocalSelected(selected);
|
|
65
|
+
}
|
|
66
|
+
}, [selected, localList]);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (list?.length) {
|
|
70
|
+
setLocalList(list)
|
|
71
|
+
}
|
|
72
|
+
}, [list]);
|
|
73
|
+
|
|
74
|
+
const onToggle = () => {
|
|
75
|
+
setIsShow(prevState => !prevState);
|
|
76
|
+
}
|
|
77
|
+
const onToggleEvent = (e) => {
|
|
78
|
+
if (e?.target?.className.toString()?.includes('backdrop-select')) {
|
|
79
|
+
onToggle()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const onSelect = (item) => {
|
|
83
|
+
setLocalSelected(item);
|
|
84
|
+
onToggle();
|
|
85
|
+
onSelectChange(item);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const getActiveClass = (item) => {
|
|
89
|
+
if (!localSelected) {
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
if (label?.length && item[label] === localSelected[label]) {
|
|
93
|
+
return "bg-grey-100"
|
|
94
|
+
}
|
|
95
|
+
if (item === localSelected) {
|
|
96
|
+
return "bg-grey-100"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return (
|
|
100
|
+
<div className="naria-select">
|
|
101
|
+
<label
|
|
102
|
+
className={`cursor-pointer
|
|
103
|
+
${hasError && "!text-danger-100"}`}>
|
|
104
|
+
<span className={``}>{title}</span>
|
|
105
|
+
<button type="button"
|
|
106
|
+
className={`relative z-20 flex items-center mt-1 text-base justify-between gap-2 w-full
|
|
107
|
+
${localSelected ? "text-dark-100" : "text-grey-300"}
|
|
108
|
+
${hasError && "!border-danger-100 focus:border-danger-100 outline-danger-100"}`}
|
|
109
|
+
onClick={onToggle}>
|
|
110
|
+
{
|
|
111
|
+
localSelected ? (
|
|
112
|
+
value?.length ? localSelected[value] : localSelected
|
|
113
|
+
) : "انتخاب"
|
|
114
|
+
} <AngleDown
|
|
115
|
+
className={`w-4 h-4 transition ease duration-200 ${!isShow ? "rotate-0" : "rotate-180"}`}/>
|
|
116
|
+
</button>
|
|
117
|
+
</label>
|
|
118
|
+
|
|
119
|
+
{
|
|
120
|
+
isShow ? (
|
|
121
|
+
<div
|
|
122
|
+
className={`wrapper ${getDeviceWidth < 1024 ? "mobile" : ""}`}>
|
|
123
|
+
<div
|
|
124
|
+
className={`list ${getDeviceWidth < 1024 ? "mobile" : `desktop ${maxHeight}`}`}>
|
|
125
|
+
{
|
|
126
|
+
api && isLoading ? (
|
|
127
|
+
<div className="py-10 flex justify-center">
|
|
128
|
+
<Loading size="w-7 h-7"/>
|
|
129
|
+
</div>
|
|
130
|
+
) : (
|
|
131
|
+
<>
|
|
132
|
+
{
|
|
133
|
+
getDeviceWidth < 1024 ? (
|
|
134
|
+
<div className="sticky top-0 text-left">
|
|
135
|
+
<button className="p-3" onClick={onToggle}>
|
|
136
|
+
<Close className="w-6"/>
|
|
137
|
+
</button>
|
|
138
|
+
</div>
|
|
139
|
+
) : undefined
|
|
140
|
+
}
|
|
141
|
+
{
|
|
142
|
+
localList?.map((item, index) => {
|
|
143
|
+
return (
|
|
144
|
+
<button type="button" onClick={() => onSelect(item)}
|
|
145
|
+
key={index.toString()}
|
|
146
|
+
className={`text-right py-2.5 px-4 text-base hover:bg-grey-100 rounded-lg ${getActiveClass(item)}`}>
|
|
147
|
+
{value?.length ? item[value] : item}
|
|
148
|
+
</button>
|
|
149
|
+
)
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
</>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
</div>
|
|
156
|
+
<div
|
|
157
|
+
className={`backdrop-select`}
|
|
158
|
+
onClick={onToggleEvent}>
|
|
159
|
+
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
) : undefined
|
|
163
|
+
}
|
|
164
|
+
{
|
|
165
|
+
hasError &&
|
|
166
|
+
<p className="text-xs mt-1 text-danger-100">{hasError}</p>
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Select } from './Select';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.naria-select {
|
|
2
|
+
position: relative;
|
|
3
|
+
.wrapper {
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
&.mobile {
|
|
6
|
+
position: fixed;
|
|
7
|
+
top: 0;
|
|
8
|
+
right: 0;
|
|
9
|
+
height: 100%;
|
|
10
|
+
width: 100%;
|
|
11
|
+
z-index: 97;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
.list {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
width: 100%;
|
|
18
|
+
z-index: 99;
|
|
19
|
+
&.mobile {
|
|
20
|
+
position: relative;
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
&.desktop {
|
|
24
|
+
overflow: auto;
|
|
25
|
+
position: absolute;
|
|
26
|
+
animation: fadeInTranslateY 0.3s ease-out forwards;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
.backdrop-select {
|
|
30
|
+
position: fixed;
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
bottom: 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
z-index: 98;
|
|
37
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@keyframes fadeInTranslateY {
|
|
44
|
+
from {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transform: translateY(10px);
|
|
47
|
+
}
|
|
48
|
+
to {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
transform: translateY(0);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {useEffect, useState} from "react";
|
|
2
|
+
|
|
3
|
+
export const removeNavigation = () => {
|
|
4
|
+
const newUrl = `${window.location.pathname}${window.location.search}`;
|
|
5
|
+
window.history.replaceState(null, '', newUrl);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const addNavigation = (state: string) => {
|
|
9
|
+
window.location.hash = state;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export const onHashChanges = () => {
|
|
14
|
+
const [isHashChanged, setIsHashChanged] = useState(false)
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const handleHashChange = (e) => {
|
|
17
|
+
if(window.location.hash !== "#modal") {
|
|
18
|
+
setIsHashChanged(true);
|
|
19
|
+
} else {
|
|
20
|
+
setIsHashChanged(false);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
window.addEventListener('hashchange', handleHashChange);
|
|
24
|
+
return () => {
|
|
25
|
+
window.removeEventListener('hashchange', handleHashChange);
|
|
26
|
+
};
|
|
27
|
+
}, [])
|
|
28
|
+
return isHashChanged
|
|
29
|
+
};
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Mohammad Mehdi Mohammadi",
|
|
6
6
|
"url": ""
|
|
7
7
|
},
|
|
8
|
-
"version": "0.1.
|
|
8
|
+
"version": "0.1.37",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"main": "dist/naria-ui.cjs.js",
|
|
11
11
|
"module": "dist/naria-ui.es.js",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"import": "./dist/naria-ui.es.js",
|
|
17
17
|
"require": "./dist/naria-ui.cjs.js"
|
|
18
|
-
}
|
|
18
|
+
},
|
|
19
|
+
"./dist/*.css": "./dist/*.css",
|
|
20
|
+
"./assets/*.css": "./assets/*.css"
|
|
19
21
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
],
|
|
22
|
+
"files": ["*.md", "dist", "lib", "es", "src"],
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
package/src/App.css
ADDED
|
File without changes
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import './App.css'
|
|
2
|
+
import {Button, Input, Select} from "../lib";
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<>
|
|
8
|
+
<Button value="sadasd"/>
|
|
9
|
+
<Input placeholder="test" label="test"/>
|
|
10
|
+
<Select label="id" value="name" list = {[{id: 1, name: "sad"}]} />
|
|
11
|
+
</>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default App
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M241 337c-9.4 9.4-24.6 9.4-33.9 0L47 177c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l143 143L367 143c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9L241 337z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc. --><path d="M47 239c-9.4 9.4-9.4 24.6 0 33.9L207 433c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9L97.9 256 241 113c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0L47 239z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc. --><path d="M273 239c9.4 9.4 9.4 24.6 0 33.9L113 433c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l143-143L79 113c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0L273 239z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M207 143c9.4-9.4 24.6-9.4 33.9 0L401 303c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-143-143L81 337c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9L207 143z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M480-424 284-228q-11 11-28 11t-28-11q-11-11-11-28t11-28l196-196-196-196q-11-11-11-28t11-28q11-11 28-11t28 11l196 196 196-196q11-11 28-11t28 11q11 11 11 28t-11 28L536-480l196 196q11 11 11 28t-11 28q-11 11-28 11t-28-11L480-424Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./select.scss";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.naria-select {
|
|
2
|
+
position: relative;
|
|
3
|
+
.wrapper {
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
&.mobile {
|
|
6
|
+
position: fixed;
|
|
7
|
+
top: 0;
|
|
8
|
+
right: 0;
|
|
9
|
+
height: 100%;
|
|
10
|
+
width: 100%;
|
|
11
|
+
z-index: 97;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
.list {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
width: 100%;
|
|
18
|
+
z-index: 99;
|
|
19
|
+
&.mobile {
|
|
20
|
+
position: relative;
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
&.desktop {
|
|
24
|
+
overflow: auto;
|
|
25
|
+
position: absolute;
|
|
26
|
+
animation: fadeInTranslateY 0.3s ease-out forwards;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
.backdrop-select {
|
|
30
|
+
position: fixed;
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
bottom: 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
z-index: 98;
|
|
37
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@keyframes fadeInTranslateY {
|
|
44
|
+
from {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transform: translateY(10px);
|
|
47
|
+
}
|
|
48
|
+
to {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
transform: translateY(0);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/index.css
ADDED
|
File without changes
|
package/src/main.tsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|