mirror of
https://github.com/FranP-code/Crypto-Prices.git
synced 2025-10-12 23:53:06 +00:00
Individual Crypto Page done
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
"react": "^17.0.2",
|
||||
"react-chartjs-2": "^4.0.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "5.0.0",
|
||||
"styled-components": "^5.3.3",
|
||||
"web-vitals": "^2.1.4"
|
||||
|
||||
70
src/App.jsx
70
src/App.jsx
@@ -1,42 +1,22 @@
|
||||
import React, { useState } from 'react'
|
||||
|
||||
import styled from 'styled-components'
|
||||
import Loading from './components/Loading/Loading';
|
||||
import Loading from './components/CryptoGalleryLoading/CryptoGalleryLoading';
|
||||
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Switch,
|
||||
Route,
|
||||
Link
|
||||
} from "react-router-dom";
|
||||
import Crypto from './components/Crypto/Crypto';
|
||||
|
||||
function App() {
|
||||
|
||||
const Div = styled.div`
|
||||
const GlobalStyles = styled.div`
|
||||
|
||||
/* height: 100%; */
|
||||
|
||||
background-image: radial-gradient( circle farthest-corner at 12.3% 19.3%, rgba(85,88,218,1) 0%, rgba(95,209,249,1) 100.2% );
|
||||
|
||||
.paths {
|
||||
|
||||
height: 100%;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
z-index: 1;
|
||||
|
||||
.path {
|
||||
|
||||
&::before {
|
||||
|
||||
content: "";
|
||||
background: red;
|
||||
}
|
||||
|
||||
/* background: #ffffff45; */
|
||||
background: rgb(255,255,255);
|
||||
background: linear-gradient(135deg, #ffffff4e 0%, #2e426965 100%);
|
||||
|
||||
position: absolute;
|
||||
}
|
||||
}`
|
||||
background-image: radial-gradient( circle farthest-corner at 12.3% 19.3%, rgba(85,88,218,1) 0%, rgba(95,209,249,1) 100.2% );
|
||||
`
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
@@ -47,14 +27,30 @@ function App() {
|
||||
document.body.style.overflow = "hidden"
|
||||
|
||||
} else {
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
document.body.style.overflow = "visible"
|
||||
|
||||
document.body.style.overflow = "visible"
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
} //https://stackoverflow.com/questions/39962757/prevent-scrolling-using-css-on-react-rendered-components
|
||||
}, [loading])
|
||||
|
||||
return (
|
||||
<Div>
|
||||
<Loading loading={loading} setLoading={setLoading}/>
|
||||
</Div>
|
||||
<GlobalStyles>
|
||||
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route path="/crypto/:cryptoID">
|
||||
<Crypto />
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Loading loading={loading} setLoading={setLoading}/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</GlobalStyles>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { CustomPath } from './CustomPath.styled';
|
||||
|
||||
const Background = ({loading}) => {
|
||||
@@ -97,6 +98,33 @@ const Background = ({loading}) => {
|
||||
transform: "rotate(40deg)"
|
||||
}
|
||||
]
|
||||
|
||||
const BackgroundStyles = styled.div`
|
||||
|
||||
height: 100%;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
z-index: 1;
|
||||
|
||||
.path {
|
||||
|
||||
&::before {
|
||||
|
||||
content: "";
|
||||
background: red;
|
||||
}
|
||||
|
||||
/* background: #ffffff45; */
|
||||
background: rgb(255,255,255);
|
||||
background: linear-gradient(135deg, #ffffff4e 0%, #2e426965 100%);
|
||||
|
||||
position: absolute;
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
const pathFunction = () => {
|
||||
@@ -119,7 +147,7 @@ const Background = ({loading}) => {
|
||||
}, [])
|
||||
|
||||
|
||||
return <>
|
||||
return <BackgroundStyles>
|
||||
{
|
||||
|
||||
seriesOfPaths.map(serie => (
|
||||
@@ -152,7 +180,7 @@ const Background = ({loading}) => {
|
||||
))
|
||||
|
||||
}
|
||||
</>
|
||||
</BackgroundStyles>
|
||||
};
|
||||
|
||||
export default Background;
|
||||
|
||||
363
src/components/Crypto/Crypto.jsx
Normal file
363
src/components/Crypto/Crypto.jsx
Normal file
@@ -0,0 +1,363 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import moment from 'moment';
|
||||
import {useParams} from 'react-router-dom'
|
||||
|
||||
import { Chart as ChartJS } from 'chart.js/auto'
|
||||
import { Chart, Line } from 'react-chartjs-2' //WTF https://stackoverflow.com/questions/67727603/error-category-is-not-a-registered-scale
|
||||
import { Grid, Button, capitalize } from '@mui/material';
|
||||
import styled from 'styled-components';
|
||||
import CryptoPricesModule from './CryptoPricesModule';
|
||||
import CryptoButtonModule from './CryptoButtonModule';
|
||||
import { Box } from '@mui/system';
|
||||
import Loading from './Loading';
|
||||
|
||||
const Crypto = () => {
|
||||
|
||||
const CryptoStyles = styled(Grid)`
|
||||
|
||||
height: 100vh;
|
||||
|
||||
header {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
margin: 1vw;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
||||
font-family: 'Raleway', 'Arial';
|
||||
color: #fff;
|
||||
|
||||
font-size: 2.5rem;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
|
||||
margin-right: 5vw;
|
||||
margin-top: 3vh;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
||||
height: 100%;
|
||||
|
||||
.line {
|
||||
|
||||
margin: 1vw;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const StylesCryptoPricesModule = styled.div`
|
||||
|
||||
.card {
|
||||
|
||||
margin: 1vw;
|
||||
background-color: #ffffff44;
|
||||
}
|
||||
`
|
||||
|
||||
const StylesCryptoButtonModule = styled(Button)`
|
||||
|
||||
background-color: #555555 !important;
|
||||
`
|
||||
|
||||
const BackToTheGalleryStyles = styled(Button)`
|
||||
|
||||
width: 94%;
|
||||
box-sizing: border-box;
|
||||
|
||||
/* padding: 0 !important; */
|
||||
|
||||
background: #4CAF50 !important;
|
||||
|
||||
svg {
|
||||
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
@media(max-width: 900px) {
|
||||
|
||||
width: 98%;
|
||||
}
|
||||
`
|
||||
|
||||
const plugin = {
|
||||
id: 'custom_canvas_background_color',
|
||||
beforeDraw: (chart) => {
|
||||
const ctx = chart.canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'destination-over';
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillRect(0, 0, chart.width, chart.height);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const cryptoID = useParams().cryptoID
|
||||
|
||||
const [cryptoData, setCryptoData] = useState(false)
|
||||
const [cryptoPrices, setCryptoPrices] = useState(false)
|
||||
const [dates, setDates] = useState(false)
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [loadingURL, setLoadingURL] = useState('https://i.ibb.co/Dwygw0t/Logo-reduced.png')
|
||||
const [contentLoaded, setContentLoaded] = useState(false)
|
||||
|
||||
const [lineDatesInterval, setLineDatesInterval] = useState('week')
|
||||
|
||||
const getCryptoData = async () => {
|
||||
|
||||
try {
|
||||
|
||||
let today = moment().format('l').split('/')
|
||||
today = `${today[1]}-${today[0]}-${today[2]}`
|
||||
|
||||
const requestData = await fetch(`https://api.coingecko.com/api/v3/coins/${cryptoID}/history?date=${today}`)
|
||||
const data = await requestData.json()
|
||||
return data
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const getCryptoPrice = async (days) => {
|
||||
|
||||
if (typeof(days) === 'number') {
|
||||
|
||||
days -= 1
|
||||
}
|
||||
|
||||
console.log(days)
|
||||
|
||||
try {
|
||||
|
||||
const requestData = await fetch(`https://api.coingecko.com/api/v3/coins/${cryptoID}/market_chart?vs_currency=usd&days=${days}&interval=daily`)
|
||||
const data = await requestData.json()
|
||||
|
||||
return data.prices.map(arr => {
|
||||
return arr[1]
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const getDates = (days) => {
|
||||
|
||||
let result = []
|
||||
|
||||
for (let i = 0; i < days; i++) {
|
||||
|
||||
const day = moment().subtract(i, 'days').format('DD-MM-YY')
|
||||
result.push(day)
|
||||
}
|
||||
|
||||
return result.reverse()
|
||||
}
|
||||
|
||||
const effectHandler = async () => {
|
||||
|
||||
const data = await getCryptoData()
|
||||
console.log(data);
|
||||
|
||||
const cryptoPricesPrevious = {}
|
||||
cryptoPricesPrevious.week = await getCryptoPrice(7)
|
||||
cryptoPricesPrevious.month = await getCryptoPrice(30)
|
||||
cryptoPricesPrevious.threeMonths = await getCryptoPrice(90)
|
||||
cryptoPricesPrevious.year = await getCryptoPrice(365)
|
||||
setCryptoPrices(cryptoPricesPrevious)
|
||||
|
||||
const datesPrevious = {}
|
||||
datesPrevious.week = getDates(7)
|
||||
datesPrevious.month = getDates(30)
|
||||
datesPrevious.threeMonths = getDates(90)
|
||||
datesPrevious.year = getDates(365)
|
||||
setDates(datesPrevious)
|
||||
|
||||
console.log(dates);
|
||||
|
||||
const maxValue = Math.max(...cryptoPricesPrevious.year)
|
||||
const minValue = Math.min(...cryptoPricesPrevious.year)
|
||||
|
||||
data.maxValue = {
|
||||
price: maxValue,
|
||||
date: datesPrevious.year[cryptoPricesPrevious.year.indexOf(maxValue)]
|
||||
}
|
||||
data.minValue = {
|
||||
price: minValue,
|
||||
date: datesPrevious.year[cryptoPricesPrevious.year.indexOf(minValue)]
|
||||
}
|
||||
|
||||
setCryptoData(data)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
effectHandler()
|
||||
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
if (cryptoData) {
|
||||
|
||||
setLoadingURL(cryptoData.image.small)
|
||||
}
|
||||
|
||||
if (cryptoData && cryptoPrices && dates) {
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
}, [cryptoData, cryptoPrices, dates])
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
if (loading) {
|
||||
|
||||
document.body.style.overflow = "hidden"
|
||||
|
||||
} else {
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
document.body.style.overflow = "visible"
|
||||
setContentLoaded(true)
|
||||
}, 2000);
|
||||
|
||||
} //https://stackoverflow.com/questions/39962757/prevent-scrolling-using-css-on-react-rendered-components
|
||||
}, [loading])
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
!contentLoaded ?
|
||||
<Loading loading={loading} loadingURL={loadingURL}/>
|
||||
: null
|
||||
}
|
||||
{
|
||||
loading ? null :
|
||||
<CryptoStyles container columnSpacing={2}>
|
||||
<Grid item md={4} sm={12} xs={12}>
|
||||
<header>
|
||||
<img src={cryptoData.image.small} alt="crypto" />
|
||||
<h1>{cryptoData.name}</h1>
|
||||
</header>
|
||||
<CryptoPricesModule
|
||||
text="Highest value (Last year)"
|
||||
price={cryptoData.maxValue.price}
|
||||
date={cryptoData.maxValue.date}
|
||||
Styles={StylesCryptoPricesModule}
|
||||
/>
|
||||
<CryptoPricesModule
|
||||
text="Lowest value (Last year)"
|
||||
price={cryptoData.minValue.price}
|
||||
date={cryptoData.minValue.date}
|
||||
Styles={StylesCryptoPricesModule}
|
||||
/>
|
||||
<BackToTheGalleryStyles
|
||||
variant="contained"
|
||||
onClick={() => window.location = '../../'}
|
||||
sx={{
|
||||
// width: "100%",
|
||||
margin: "0px 0px 0px 1vw"
|
||||
}}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="icon icon-tabler icon-tabler-arrow-narrow-left" width="44" height="44" viewBox="0 0 24 24" strokeWidth="1.5" stroke="#ffffff" fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
<line x1="5" y1="12" x2="9" y2="16" />
|
||||
<line x1="5" y1="12" x2="9" y2="8" />
|
||||
</svg>
|
||||
Back to the gallery
|
||||
</BackToTheGalleryStyles>
|
||||
</Grid>
|
||||
<Grid item md={8} sm={12} xs={12}>
|
||||
<Line
|
||||
data={{
|
||||
labels: dates[lineDatesInterval],
|
||||
label: false,
|
||||
datasets: [
|
||||
{
|
||||
data: cryptoPrices[lineDatesInterval],
|
||||
borderColor: "#fff"
|
||||
}
|
||||
]
|
||||
}}
|
||||
options={{
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
aspectRatio: 1.8,
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
color: 'rgba(253, 91, 91, 0)',
|
||||
borderColor: 'rgba(187, 187, 187, 0)',
|
||||
opacity: 0
|
||||
},
|
||||
ticks: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
y: {
|
||||
grid: {
|
||||
color: 'rgba(253, 91, 91, 0)',
|
||||
borderColor: 'rgba(187, 187, 187, 0)',
|
||||
opacity: 0
|
||||
},
|
||||
ticks: {
|
||||
color: "#fff"
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
plugin,
|
||||
legend: {
|
||||
display: false, // https://stackoverflow.com/a/67055974
|
||||
labels: {
|
||||
fontColor: '#666'
|
||||
}
|
||||
}
|
||||
},
|
||||
}}
|
||||
className='line'
|
||||
/>
|
||||
<Box
|
||||
sx={{display: 'flex', justifyContent: "space-around", padding: {md: "1.5vh 13vw", xs: "1vh 13vw 5vh 13vw"}}}
|
||||
>
|
||||
{
|
||||
[
|
||||
{text: "Week", propierty: "week"},
|
||||
{text: "Month", propierty: "month"},
|
||||
{text: "Three months", propierty: "threeMonths"},
|
||||
{text: "Year", propierty: "year"}
|
||||
].map((obj) => (
|
||||
|
||||
<CryptoButtonModule
|
||||
Styles={StylesCryptoButtonModule}
|
||||
text={obj.text}
|
||||
onClickFunction={setLineDatesInterval}
|
||||
value={obj.propierty}
|
||||
key={obj.text}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Box>
|
||||
</Grid>
|
||||
</CryptoStyles>
|
||||
}
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
export default Crypto;
|
||||
24
src/components/Crypto/CryptoButtonModule.jsx
Normal file
24
src/components/Crypto/CryptoButtonModule.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
const CryptoButtonModule = ({text, onClickFunction, value, Styles}) => {
|
||||
|
||||
return (
|
||||
<Styles
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
onClickFunction(value)
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
window.scrollTo(0,document.body.scrollHeight); //https://stackoverflow.com/questions/11715646/scroll-automatically-to-the-bottom-of-the-page
|
||||
|
||||
}, 50)
|
||||
}}
|
||||
variant="contained"
|
||||
>
|
||||
{text}
|
||||
</Styles>
|
||||
)
|
||||
};
|
||||
|
||||
export default CryptoButtonModule;
|
||||
39
src/components/Crypto/CryptoPricesModule.jsx
Normal file
39
src/components/Crypto/CryptoPricesModule.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Card, CardContent, List, ListItem, ListItemText, Typography } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
const CryptoPricesModule = ({text, price, date, Styles}) => {
|
||||
|
||||
return (
|
||||
|
||||
<Styles>
|
||||
<Card className="card">
|
||||
<CardContent>
|
||||
<Typography
|
||||
variant="h5"
|
||||
fontWeight="bold"
|
||||
fontFamily="Raleway"
|
||||
color="#fff"
|
||||
>
|
||||
{text}
|
||||
</Typography>
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={`USD ${Math.round(price * 100) / 100}`} //https://stackoverflow.com/a/11832950
|
||||
primaryTypographyProps={{
|
||||
color: '#eee'
|
||||
}}
|
||||
secondary={date}
|
||||
secondaryTypographyProps={{
|
||||
color: '#ddd'
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Styles>
|
||||
)
|
||||
};
|
||||
|
||||
export default CryptoPricesModule;
|
||||
74
src/components/Crypto/Loading.jsx
Normal file
74
src/components/Crypto/Loading.jsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import styled from 'styled-components';
|
||||
import React, {useState} from 'react';
|
||||
|
||||
const Loading = ({loading, loadingURL}) => {
|
||||
|
||||
const LoadingStyles = styled.div`
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
z-index: 10000;
|
||||
|
||||
background-image: radial-gradient( circle farthest-corner at 10% 20%, rgba(90,92,106,1) 0%, rgba(32,45,58,1) 81.3% );
|
||||
|
||||
img {
|
||||
|
||||
width: 108px;
|
||||
|
||||
margin-bottom: 3vh;
|
||||
|
||||
animation: imgRotate 2s linear infinite;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
color: #fff;
|
||||
font-family: "Raleway"
|
||||
}
|
||||
|
||||
@keyframes imgRotate{
|
||||
0% {
|
||||
transform: rotate(0deg)
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
|
||||
animation: hiddeLoading 2s ease-in-out forwards;
|
||||
}
|
||||
|
||||
@keyframes hiddeLoading {
|
||||
50%{
|
||||
transform: translate(0, 0%)
|
||||
}
|
||||
100% {
|
||||
transform: translate(0, -100%)
|
||||
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return (
|
||||
|
||||
<LoadingStyles className={loading ? null : 'hidden'}>
|
||||
<img src={loadingURL} alt="loading" />
|
||||
<h2>Loading</h2>
|
||||
</LoadingStyles>
|
||||
)
|
||||
};
|
||||
|
||||
export default Loading;
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Grid } from '@mui/material';
|
||||
import styled from 'styled-components';
|
||||
import Crypto from './Crypto';
|
||||
import Crypto from './CryptoGalleryItem';
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
@@ -7,8 +7,12 @@ import { Chart, Line } from 'react-chartjs-2' //WTF https://stackover
|
||||
import Cookies from 'js-cookie';
|
||||
import { borderRadius } from '@mui/system';
|
||||
|
||||
import { withRouter, useHistory } from 'react-router-dom';
|
||||
|
||||
const Crypto = ({CryptoStyles, data, cryptoPrices, dates, index, cryptoListLength, setLoading}) => {
|
||||
|
||||
const history = useHistory()
|
||||
|
||||
const plugin = {
|
||||
id: 'custom_canvas_background_color',
|
||||
beforeDraw: (chart) => {
|
||||
@@ -40,7 +44,13 @@ const Crypto = ({CryptoStyles, data, cryptoPrices, dates, index, cryptoListLengt
|
||||
|
||||
return (
|
||||
<>
|
||||
<CryptoStyles item md={4} sm={6} xs={12}>
|
||||
<CryptoStyles
|
||||
item
|
||||
lg={4}
|
||||
md={6}
|
||||
sm={12}
|
||||
onClick={() => history.push(`/crypto/${data.id}`)}
|
||||
>
|
||||
<Card className="card">
|
||||
<CardContent
|
||||
className="container"
|
||||
@@ -137,4 +147,4 @@ const Crypto = ({CryptoStyles, data, cryptoPrices, dates, index, cryptoListLengt
|
||||
)
|
||||
};
|
||||
|
||||
export default Crypto;
|
||||
export default withRouter(Crypto);
|
||||
@@ -1,7 +1,7 @@
|
||||
import {React, useState} from 'react';
|
||||
import styled from 'styled-components';
|
||||
import Background from '../Background/Background';
|
||||
import Cryptos from '../Cryptos/Cryptos';
|
||||
import Cryptos from '../CryptoGallery/CryptoGallery';
|
||||
import Header from '../Header/Header';
|
||||
|
||||
const Loading = ({loading, setLoading}) => {
|
||||
@@ -53,11 +53,11 @@ const Loading = ({loading, setLoading}) => {
|
||||
|
||||
&.hidden {
|
||||
|
||||
animation: hiddeLoading 1s ease-in-out forwards;
|
||||
animation: hiddeLoading 2s ease-in-out forwards;
|
||||
}
|
||||
|
||||
@keyframes hiddeLoading {
|
||||
0%{
|
||||
50%{
|
||||
transform: translate(0, 0%)
|
||||
}
|
||||
100% {
|
||||
Reference in New Issue
Block a user