mirror of
https://github.com/hazemKrimi/react-weather-app.git
synced 2026-05-01 18:30:25 +00:00
Replace framer motion with elastic carousel for animation
This commit is contained in:
+58
-79
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
// @ts-ignore
|
||||
import Carousel, { consts } from 'react-elastic-carousel';
|
||||
import { Wrapper } from './styles';
|
||||
import { Weather, WeatherSearchResponse } from '../../types/weather';
|
||||
import { Forecast, ForecastResponse } from '../../types/forecast';
|
||||
@@ -15,8 +16,36 @@ const Search: React.FC = () => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string>('');
|
||||
const { query } = useParams<{ query: string }>();
|
||||
const [dailyForecastGrid, setDailyForecastGrid] = useState<number>(0);
|
||||
const [hourlyForecastGrid, setHourlyForecastGrid] = useState<number>(0);
|
||||
|
||||
const carouselSettings = {
|
||||
pagination: false,
|
||||
itemsToShow: 1,
|
||||
enableSwipe: true,
|
||||
isRTL: false,
|
||||
disableArrowsOnEnd: true,
|
||||
enableTilt: false,
|
||||
renderArrow: ({
|
||||
type,
|
||||
onClick,
|
||||
isEdge
|
||||
}: {
|
||||
type: string;
|
||||
onClick: () => void;
|
||||
isEdge: boolean;
|
||||
}) => (
|
||||
<>
|
||||
{type !== consts.PREV ? (
|
||||
<button onClick={onClick} disabled={isEdge} type='button' className='carousel-arrow'>
|
||||
<img src={RightArrow} alt='Left slider arrow' />
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={onClick} disabled={isEdge} type='button' className='carousel-arrow'>
|
||||
<img src={LeftArrow} alt='Right slider arrow' />
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -75,85 +104,35 @@ const Search: React.FC = () => {
|
||||
</div>
|
||||
<div className='daily-forecast'>
|
||||
<h2>Daily Forecast</h2>
|
||||
<div className='slider'>
|
||||
<motion.img
|
||||
src={LeftArrow}
|
||||
alt='Left slider arrow'
|
||||
onTap={() => {
|
||||
if (dailyForecastGrid <= forecast.daily.length / 2 - 1)
|
||||
setDailyForecastGrid(dailyForecastGrid + 1);
|
||||
}}
|
||||
/>
|
||||
<div className='slider-background'>
|
||||
<motion.div
|
||||
initial={false}
|
||||
animate={{ transform: `translateX(${dailyForecastGrid * 10}rem)` }}
|
||||
transition={{ duration: 0.25 }}
|
||||
className='forecast-grid'
|
||||
>
|
||||
{forecast.daily.map(day => (
|
||||
<Card
|
||||
key={day.dt}
|
||||
date={new Date(day.dt * 1000)}
|
||||
time={false}
|
||||
data={day.temp.min + '°C/' + day.temp.max + '°C'}
|
||||
temp={day.temp.max > 25 ? 'hot' : day.temp.max < 20 ? 'cold' : null}
|
||||
icon={day.weather[0].id}
|
||||
description={day.weather[0].description}
|
||||
/>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.img
|
||||
src={RightArrow}
|
||||
alt='Right slider arrow'
|
||||
onTap={() => {
|
||||
if (dailyForecastGrid >= -forecast.daily.length / 2 + 1)
|
||||
setDailyForecastGrid(dailyForecastGrid - 1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Carousel {...carouselSettings}>
|
||||
{forecast.daily.map(day => (
|
||||
<Card
|
||||
key={day.dt}
|
||||
date={new Date(day.dt * 1000)}
|
||||
time={false}
|
||||
data={day.temp.min + '°C/' + day.temp.max + '°C'}
|
||||
temp={day.temp.max > 25 ? 'hot' : day.temp.max < 20 ? 'cold' : null}
|
||||
icon={day.weather[0].id}
|
||||
description={day.weather[0].description}
|
||||
/>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
<div className='hourly-forecast'>
|
||||
<h2>Hourly Forecast</h2>
|
||||
<div className='slider'>
|
||||
<motion.img
|
||||
src={LeftArrow}
|
||||
alt='Left slider arrow'
|
||||
onTap={() => {
|
||||
if (hourlyForecastGrid <= forecast.hourly.length / 2 - 1)
|
||||
setHourlyForecastGrid(hourlyForecastGrid + 1);
|
||||
}}
|
||||
/>
|
||||
<div className='slider-background'>
|
||||
<motion.div
|
||||
initial={false}
|
||||
animate={{ transform: `translateX(${hourlyForecastGrid * 10}rem)` }}
|
||||
transition={{ duration: 0.25 }}
|
||||
className='forecast-grid'
|
||||
>
|
||||
{forecast.hourly.map(hour => (
|
||||
<Card
|
||||
key={hour.dt}
|
||||
date={new Date(hour.dt * 1000)}
|
||||
time={true}
|
||||
data={hour.temp + '°C'}
|
||||
temp={hour.temp > 25 ? 'hot' : hour.temp < 20 ? 'cold' : null}
|
||||
icon={hour.weather[0].id}
|
||||
description={hour.weather[0].description}
|
||||
/>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.img
|
||||
src={RightArrow}
|
||||
alt='Right slider arrow'
|
||||
onTap={() => {
|
||||
if (hourlyForecastGrid >= -forecast.hourly.length / 2 + 1)
|
||||
setHourlyForecastGrid(hourlyForecastGrid - 1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Carousel {...carouselSettings}>
|
||||
{forecast.hourly.map(hour => (
|
||||
<Card
|
||||
key={hour.dt}
|
||||
date={new Date(hour.dt * 1000)}
|
||||
time={true}
|
||||
data={hour.temp + '°C'}
|
||||
temp={hour.temp > 25 ? 'hot' : hour.temp < 20 ? 'cold' : null}
|
||||
icon={hour.weather[0].id}
|
||||
description={hour.weather[0].description}
|
||||
/>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
<div className='wind'>
|
||||
<h2>Wind</h2>
|
||||
|
||||
@@ -17,32 +17,19 @@ export const Wrapper = styled.div`
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.slider {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.slider-background {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.carousel-arrow {
|
||||
background: none;
|
||||
border: none;
|
||||
align-self: center;
|
||||
cursor: pointer;
|
||||
padding: 0 !important;
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.forecast-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 10rem);
|
||||
grid-auto-flow: column;
|
||||
column-gap: 2rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user