Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions src/components/HeroSection.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
import { LinkButton, Slider } from "./ui";
import { useSliderAutoplay } from "../hooks/useSliderAutoplay";

import { heroJoin, heroCorex, heroUnlock, heroSales } from "../assets/hero";

const slides = [
{
image: heroJoin,
buttonLabel: "Join Us",
href: "/about-corex",
alt: "Join the CoreX community - Premium supplements for serious athletes"
},
{
image: heroCorex,
buttonLabel: "Shop Now",
href: "/products",
alt: "CoreX Nutrition - Science-backed supplements for peak performance"
},
{
image: heroUnlock,
image: heroSales,
buttonLabel: "Shop Now",
href: "/products",
alt: "Unlock your potential with CoreX performance supplements"
alt: "Special offer - CoreX supplements on 40% off sale now"
},
{
image: heroSales,
image: heroUnlock,
buttonLabel: "Shop Now",
href: "/products",
alt: "Special offer - CoreX supplements on 40% off sale now"
}
alt: "Unlock your potential with CoreX performance supplements"
},
{
image: heroJoin,
buttonLabel: "Join Us",
href: "/about-corex",
alt: "Join the CoreX community - Premium supplements for serious athletes"
},
];

function HeroSection() {
const sliderRef = useSliderAutoplay(8000);

return (
<section className="hero-section" aria-label="Hero carousel" id="hero-section">
<Slider
ref={sliderRef}
className="hero-slider"
autoplay
autoplaySpeed={4000}
autoplay={false}
speed={1000}
fade
dots
Expand Down
106 changes: 54 additions & 52 deletions src/components/ui/Slider/Slider.css
Original file line number Diff line number Diff line change
@@ -1,99 +1,101 @@

.slick-dots li button {
position: relative;
border-radius: 50%;
}

.slick-dots li button:focus,
.slick-dots li button:focus-visible {
outline: none;
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3), 0 0 0 4px rgba(255, 255, 255, 0.8);
}

.slick-dots li {
margin: 0 !important;
}

.hero-slider {
--dot-size: 1rem;
--dot-active-inner-size: 0.75rem;
--header-height: 4rem;
--dot-gap: 0.75rem;
--animation-duration: 12s;
--dot-color: white;
--dot-bottom-min: 1rem;
--dot-bottom-max: 4.5rem;

height: auto;
max-height: calc(100vh - var(--header-height));
max-height: calc(100vh - 4rem);
container-type: inline-size;
}

/* Height constraints for slider internals */
.hero-slider .slick-list,
.hero-slider .slick-track {
height: auto;
max-height: calc(100vh - var(--header-height));
}

.hero-slider .slick-track,
.hero-slider .slick-slide,
.hero-slider .slick-slide > div,
.hero-slider .slick-slide > div > div {
width: 100%;
height: auto;
max-height: calc(100vh - var(--header-height));
max-height: calc(100vh - 4rem);
}

.hero-slider .slick-dots {
position: absolute;
bottom: 1.5rem;
inset-block-end: clamp(var(--dot-bottom-min), 5vw, var(--dot-bottom-max));
z-index: 1;
display: flex !important;
gap: var(--dot-gap);
justify-content: center;
width: 100%;
}

@media (min-width: 640px) {
.hero-slider .slick-dots {
bottom: 0.5rem;
}
.hero-slider .slick-dots li {
width: var(--dot-size);
height: var(--dot-size);
aspect-ratio: 1;
border-radius: 50%;
}

.hero-slider .slick-dots li button {
width: var(--dot-size);
height: var(--dot-size);
position: relative;
width: 100%;
height: 100%;
border: none;
background: none;
cursor: pointer;
}

.hero-slider .slick-dots li button:before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: var(--dot-size);
height: var(--dot-size);
inset-block-start: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: white;
background-color: var(--dot-color);
opacity: 1;
transition: all 0.2s ease;
}

.hero-slider .slick-dots li.slick-active button:before {
background-color: transparent !important;
border: 2px solid white;
overflow: hidden;
background-color: transparent;
border: 1px solid white;
}

.hero-slider .slick-dots li.slick-active button:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
inset-block-start: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: white;
animation: dotGrow 5s ease-out forwards;
will-change: width, height;
background-color: var(--dot-color);
transform: scale(0);
animation: simpleGrow var(--animation-duration) cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}

@keyframes dotGrow {
0% {
width: 0;
height: 0;
opacity: 0.8;
}
5% {
opacity: 1;
.hero-slider .slick-dots li button:hover:before {
transform: scale(1.2);
box-shadow: 0 0 10px rgba(255, 255, 255, 0.4);
}

@keyframes simpleGrow {
0% {
transform: scale(0);
}
100% {
width: var(--dot-active-inner-size);
height: var(--dot-active-inner-size);
opacity: 1;
100% {
transform: scale(1);
}
}
17 changes: 17 additions & 0 deletions src/hooks/useSliderAutoplay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useRef } from 'react';

export function useSliderAutoplay(interval = 8000) {
const sliderRef = useRef(null);

useEffect(() => {
const timer = setInterval(() => {
if (sliderRef.current) {
sliderRef.current.slickNext();
}
}, interval);

return () => clearInterval(timer);
}, [interval]);

return sliderRef;
}