Skip to content

Commit

Permalink
added swiper for products and header
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-dc committed Sep 17, 2023
1 parent 2ee98cc commit 5d8e26a
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 26 deletions.
21 changes: 20 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"swiper": "^10.2.0"
},
"devDependencies": {
"@reduxjs/toolkit": "^1.9.5",
Expand Down
Binary file added public/header1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/header2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/header3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/header4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mobile_header1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mobile_header2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ function App() {
<Route path="/" element={(
<>
<Navbar/>
<div className="container pb-[3rem]">
<div className="bg-[#F5F5F5] pb-[3rem]">
<Products/>
</div>
</>
)}/>
<Route path="/products" element={(
<>
<Navbar/>
<div className="container pb-[3rem]">
<div className="bg-[#F5F5F5] pb-[3rem]">
<Products/>
</div>
</>
Expand Down
22 changes: 20 additions & 2 deletions src/components/Cart/Cart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import CartItem from "./CartItem";
import { BsFillCartXFill } from 'react-icons/bs'
import { RiApps2Line } from 'react-icons/ri'
import { AiOutlineCheckCircle } from 'react-icons/ai'
import { useState } from "react";
import { useEffect, useState } from "react";
import { checkout } from "../../features/cart/cartSlice";


function Cart() {
const cartState = useSelector(state => state.cart.value.cart)
const cartTotal = useSelector(state => state.cart.value.total)
const [isMobile, setIsMobile] = useState(false)
const dispatch = useDispatch()

const [isCheckout, setIsCheckout] = useState(false)
Expand All @@ -24,6 +25,23 @@ function Cart() {

return () => clearTimeout(time)
}

useEffect(() => {
function handleResize() {
if (window.innerWidth <= 768) {
setIsMobile(true);
} else {
setIsMobile(false);
}
}

window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return (
<div className="min-h-screen bg-white relative">
<header className="sticky top-[-1px] z-[50]">
Expand All @@ -36,7 +54,7 @@ function Cart() {
</nav>
</header>
<div className="bg-white p-[1rem] lg:p-[2rem] pb-[8rem]">
<img src="/banner.jpg" alt="" className="rounded-lg lg:rounded-2xl object-cover w-full"/>
<img src={`${isMobile ? "/mobile_header2.jpg" : "/banner.jpg"}`} alt="" className="rounded-lg lg:rounded-2xl object-cover w-full h-[7rem] lg:h-fit"/>
{cartState.length > 0 ? <div className="p-[0.5rem] lg:p-[1.5rem] mt-[1.5rem]">
<h2 className="text-[1.5rem] lg:text-[1.8rem] font-semibold text-gray-400">Shopping Cart</h2>
<table className="w-full mt-[1rem]">
Expand Down
8 changes: 5 additions & 3 deletions src/components/Navbar/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ function Navbar() {
}, [searchInput])

return (
<header className="sticky top-[-1px] z-[50]">
<header className="sticky top-[-1px] lg:top-[0px] z-[50]">
<nav className="flex justify-between px-[1.2rem] items-center lg:px-[3rem] py-[1.4rem] bg-[#0f1111]">
<a href="/"><img src="/logo.png" alt="" className="w-[5rem] lg:w-[7rem]"/></a>
<div className="flex rounded-md justify-between overflow-hidden bg-white w-[11rem] lg:w-[30rem]">
<input type="text" placeholder="Search a product." className="px-[0.7rem] text-[0.8rem] lg:text-[1rem] py-[3px] lg:px-[1rem] pr-[5rem] outline-none" value={searchInput} onChange={(e) => setSearchInput(e.target.value)}/>
<div className="flex rounded-md justify-between overflow-hidden bg-white w-[9rem] lg:w-[30rem]">
<input type="text" placeholder="Search a product." className="px-[0.7rem] text-[0.8rem] lg:text-[1rem] py-[3px] lg:px-[1rem] pr-[5rem] outline-none" value={searchInput} onChange={(e) =>
setSearchInput(e.target.value)
}/>
<button className="hidden lg:flex bg-[#febd69] text-[1.6rem] px-[0.7rem] py-[5px] active:scale-[0.95]" onClick={() => dispatch(search(searchInput))}><AiOutlineSearch /></button>
</div>
<div className='flex gap-[0.8rem] items-center'>
Expand Down
14 changes: 13 additions & 1 deletion src/components/ProductDetails/ProductDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ import { addItem, remove } from '../../features/cart/cartSlice';
import { useParams, Link } from 'react-router-dom';
import { TbTruckDelivery } from 'react-icons/tb'
import { LuRotate3D } from 'react-icons/lu'
import ProductSlider from '../ProductSlider/ProductSlider';
import { fetchData } from '../../features/products/productsSlice';

const ProductDetails = () => {
const { id } = useParams()
const dispatch = useDispatch()
const state = useSelector(state => state.productDetails)
const { id } = useParams()
const products = useSelector(state => state.products)
const filteredProducts = products.value.filter(product => product.id !== Number(id))

const cart = useSelector(state => state.cart.value)
const cartState = cart.cart.length
const isFirstMount = useRef(true);

useEffect(() => {
dispatch(fetchData())

if (isFirstMount.current) {
window.scrollTo(0, 0);
Expand Down Expand Up @@ -99,6 +105,12 @@ const ProductDetails = () => {

</div>
</div>

<div className='py-[2rem] px-[1rem] lg:px-0'>
{!products.loading && products.value && products.value.length > 0 && (
<ProductSlider products={filteredProducts} category={"Recommended Products from Philippines"}/>
)}
</div>
</div>

)
Expand Down
97 changes: 97 additions & 0 deletions src/components/ProductSlider/ProductSlider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { useEffect, useState } from 'react'

import { Navigation, Pagination, Scrollbar, A11y, Autoplay } from 'swiper/modules';

import { Swiper, SwiperSlide, useSwiper } from 'swiper/react';

// Import Swiper styles
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/scrollbar';
import './swiper.css';
import { useDispatch } from 'react-redux';
import { setProduct } from '../../features/products/productDetailSlice';
import { Link } from 'react-router-dom';

const ProductSlider = ({products, category}) => {
const [isMobile, setIsMobile] = useState(false)
const dispatch = useDispatch()

useEffect(() => {
function handleResize() {
if (window.innerWidth <= 768) {
setIsMobile(true);
} else {
setIsMobile(false);
}
}

window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return (

<div className='relative py-[2rem] bg-white drop-shadow-2xl container swiper'>
<div className='px-[1rem] lg:px-[2rem] pb-[2rem] flex gap-[0.5rem] lg:gap-[0.8rem] items-center'>
<span className='h-[2.2rem] lg:h-[2rem] w-[5px] bg-[#febd69]'></span>
<h3 className='font-semibold text-[1rem] lg:text-[1.2rem]'>
{category}
</h3>
</div>
<Swiper
// install Swiper modules
modules={[Navigation, Pagination, Scrollbar, A11y, Autoplay]}
spaceBetween={0}
slidesPerView={ isMobile ? 3 : 5}
navigation={{
prevEl: '.swiper-button-prev',
nextEl: '.swiper-button-next',
}}
autoplay={{
delay: 4000,
disableOnInteraction: false,
}}
scrollbar={{ draggable: true }}
className='static'
>
{products.map(({title, id, image, category, price, description, rating: {rate, count}}) => (
<SwiperSlide className='px-[1rem] cursor-pointer' key={id}>
<Link to={`/products/${id}`} onClick={() => dispatch(setProduct({title, id, image, category, price, description, rating: {rate, count}}))}>
<img src={image} alt="" className="w-fit lg:w-fit mx-auto h-[7rem] lg:h-[12rem] mb-[0.5rem]"/>

<div className='flex gap-[0.5rem] lg:gap-[0.7rem] items-center py-[0.5rem]'>
<small className='rounded-sm bg-red-700 py-[2px] lg:py-[4px] px-[6px] lg:px-[8px] text-white text-[0.55rem] lg:text-[0.7rem]'>40% off</small>
<small className='text-red-700 text-[0.6rem] lg:text-[0.8rem] font-semibold'>Deal</small>
</div>
<div>
<p className="text-[0.7rem] lg:text-[1rem] rounded-full font-semibold">${price}</p>
<p className='text-[0.7rem] lg:text-[1rem]'>
<small className='text-gray-400 font-normal'>List Price: </small>
<small className='line-through text-gray-400 font-normal'>${price+200}</small>
</p>
</div>

<h3 className="text-[0.8rem] lg:text-[0.9rem] truncate pr-[1rem]">{description}</h3>
</Link>

</SwiperSlide>
))}

</Swiper>
<div className="hidden lg:flex justify-center items-center absolute top-[40%] lg:left-[1rem] translate-y-[-50%] z-50">
<div className="swiper-button-prev text-gray-500 rounded-md px-[1.5rem] py-[3rem] drop-shadow-md bg-[#f5f5f5de]"></div>
</div>
<div className="hidden lg:flex justify-center items-center absolute top-[40%] translate-y-[-50%] z-50 lg:right-[1rem]">
<div className="swiper-button-next text-gray-500 rounded-md px-[1.5rem] py-[3rem] drop-shadow-md bg-[#f5f5f5de]"></div>
</div>
<div className=".swiper-scrollbar transition-all duration-500"></div>
{/* <div className=".swiper-scrollbar-drag"></div> */}
</div>
)
}

export default ProductSlider
42 changes: 42 additions & 0 deletions src/components/ProductSlider/swiper.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* Change font size for both previous and next buttons */
.swiper-button-prev:after,
.swiper-button-next:after{
font-size: 1.8rem !important;
font-weight: bold !important;
transition: 0.3s !important;
}
.swiper-button-prev,
.swiper-button-next{
display: none;
}
.swiper:hover .swiper-button-prev,
.swiper:hover .swiper-button-next{
display: flex;
}
.swiper-scrollbar{
opacity: 1;
height: 6px !important;
border-radius: 4px;
position: absolute !important;
bottom: 0.8rem !important;
transition: all 0.3s ease !important;
display: none;
}

.swiper-scrollbar-drag {
background-color: gray !important;
opacity: 1;
border-radius: 4px;
width: 50%;
height: 6px !important;
}
.swiper:hover .swiper-scrollbar{
display: flex;
}

@media (max-width: 768px) {
.swiper-button-prev:after,
.swiper-button-next:after{
font-size: 1rem !important; /* Adjust the font size as needed */
}
}
8 changes: 4 additions & 4 deletions src/components/Products/ProductItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ function ProductItem({title, id, image, category, price, description, rating: {r
stars.push(<span key={i} className="text-[#febd69] text-[0.8rem] lg:text-[1rem]"><AiFillStar/></span>)
}
return (
<div className="p-[1rem] lg:p-[2rem] lg:pb-[1rem] bg-white drop-shadow-2xl relative">
<img src={image} alt="" className="w-[7rem] lg:w-[10rem] mx-auto h-[8rem] lg:h-[12rem]"/>
<div className="p-[1rem] pt-[1.5rem] lg:p-[2rem] lg:pt-[2rem] lg:pb-[1rem] bg-white drop-shadow-2xl relative">
<img src={image} alt="" className="w-[6rem] lg:w-[10rem] mx-auto h-[7rem] lg:h-[12rem]"/>
<h3 className="text-[0.8rem] lg:text-[1rem] font-semibold mt-[1rem] truncate">{title}</h3>
<p className="truncate text-[0.7rem] lg:text-[0.8rem]">{description}</p>
<p className="bg-[#0f1111] text-[0.8rem] lg:text-[1rem] text-white absolute top-[1rem] right-[1rem] rounded-full py-[5px] px-[0.7rem] lg:px-[1rem]">${price}</p>
<p className="bg-[#0f1111] text-[0.7rem] lg:text-[1rem] text-white absolute top-[1rem] right-[1rem] rounded-full py-[4px] px-[0.6rem] lg:px-[1rem]">${price}</p>
<div className="flex mt-[0.5rem] lg:mt-[1rem] items-center">
{stars}
<small className="ml-[4px] text-[0.7rem] lg:text-[0.8rem]">{rate}</small>
<small className="ml-[4px] text-gray-400 text-[0.7rem] lg:text-[0.8rem]">({count})</small>
</div>
<div className='flex justify-end mt-[1rem]'>
<Link to={`/products/${id}`} className="text-[#232f3e] font-semibold text-[0.8rem] active:scale-[0.95] hover:underline"
<Link to={`/products/${id}`} className="text-[#232f3e] underline lg:no-underline font-semibold text-[0.7rem] lg:text-[0.8rem] active:scale-[0.95] hover:underline"
onClick={() => dispatch(setProduct({title, id, image, category, price, description, rating: {rate, count}}))}>See more
</Link>
</div>
Expand Down
Loading

0 comments on commit 5d8e26a

Please sign in to comment.