Skip to content

Commit

Permalink
feat: add new Slider component
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandar-r committed Apr 1, 2024
1 parent 61cbcf8 commit 435dc72
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 234 deletions.
84 changes: 52 additions & 32 deletions src/core/Slider/Slider.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,65 @@
import React, { ReactNode } from "react";
import React from "react";
import Slider from "./component.tsx";
import Icon from "../Icon/component.tsx";

export default {
title: "Components/Slider",
component: Slider,
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
};
const Slide = ({ name }: { name: string }) => (
<div className="relative ">
<div className="relative mx-auto w-full sm:w-[560px] md:w-[784px] lg:w-[960px] bg-white overflow-hidden flex gap-40 rounded-3xl shadow-container-subtle">
<div className="w-full md:w-2/3 flex flex-col gap-24 pr-40 md:pr-0 pt-40 pl-40 pb-40 sm:pb-[120px] md:pb-40">
<h2 className="ui-text-h2 font-medium text-neutral-1000">
“Ably seamlessly absorbs sudden bursts in load during unexpected
client events. The integration was easy and we were live in under a
month.”
</h2>
<div className="flex flex-col sm:flex-row gap-32">
<div className="flex gap-8">
<div className="static self-center sm:absolute sm:-bottom-48 sm:-right-[56px] rounded-full bg-gradient-to-l from-neutral-200 to-50% to-neutral-500 w-[48px] h-[48px] sm:w-[201px] sm:h-[201px] md:w-[257px] md:h-[257px] lg:w-[280px] lg:h-[280px] overflow-hidden flex items-center justify-center sm:border-[16px] border-neutral-200">
{/* <GatsbyImage /> */}
</div>
<div className="sm:py-16">
<p className="ui-text-p1 text-neutral-1300">{name}</p>
<p className="ui-text-p3 text-neutral-800">
Co-Founder & Technical Leader
</p>
</div>
</div>

<div className="w-[80px] h-1 sm:w-1 sm:h-full bg-neutral-500"></div>
<div className="flex items-center gap-4">
{/* <GatsbyImage /> */}
<p className="ui-text-h4 font-bold">Mentimeter</p>
</div>
</div>
<a href="/case-study" className="ui-btn self-start">
Read case study
<Icon
name="icon-gui-arrow-right"
size="1.25rem"
additionalCSS="ml-4"
/>
</a>
</div>
</div>

const Slide = ({ children }: { children: ReactNode }) => (
<div className="h-full p-24 bg-white rounded">
<p className="ui-text-p2 text-center">{children}</p>
<div className="absolute h-256 -z-10 -bottom-48 -left-36 w-1/5 rounded-full blur-xl opacity-50 transform -rotate-45 bg-gradient-to-bl from-bg-glow-green to-bg-glow-teal"></div>
<div className="absolute h-256 -z-10 -top-48 -right-48 w-3/5 rounded-full blur-xl opacity-50 transform rotate-12 bg-gradient-to-br from-bg-glow-green to-bg-glow-teal"></div>
</div>
);

const slides = [
<Slide key="1">
Powers live chat, updates, analytics, and composition for millions of users.
</Slide>,
<Slide key="2">
Powers virtual venues for millions of event attendees around the world.
</Slide>,
<Slide key="3">
Provides 5 million daily users with live financial commentary and stock
tickers.
</Slide>,
<Slide key="4">Monitors live car performance data across the USA.</Slide>,
<Slide key="1" name={"Johan Bengtsson"} />,
<Slide key="2" name={"Mirko Bergman"} />,
<Slide key="3" name={"Stefania Lombardo"} />,
<Slide key="4" name={"Aleksandar Kostadinov"} />,
];

export const SliderOnAllBreakpoints = {
export default {
title: "Components/Slider",
component: Slider,
args: {
slides,
children: slides,
interval: 15000,
},
};

export const SliderOnSmallBreakpointOnly = {
args: {
slides,
classes: `sm:grid-cols-${slides.length / 2} md:grid-cols-${slides.length}`,
mqEnableThreshold: () => !window.matchMedia("(min-width: 48rem)").matches,
},
};
export const Default = {};
12 changes: 7 additions & 5 deletions src/core/Slider/component.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.ui-slider-marker {
font-size: 0.5rem;
top: -1px;

@apply leading-none px-4 relative;
@keyframes fillAnimation {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
107 changes: 0 additions & 107 deletions src/core/Slider/component.js
Original file line number Diff line number Diff line change
@@ -1,107 +0,0 @@
import "./component.css";

import throttle from "lodash.throttle";

import { queryId, queryIdAll } from "../dom-query";

const mdBreakpoint = () => window.matchMedia("(min-width: 48rem)").matches;
const DRAG_BUFFER = 20;

const init = (slidesContainer) => {
const transformContainer = queryId("slider-strip", slidesContainer);
const slides = Array.from(queryIdAll("slider-slide", slidesContainer));
const slideLeftChevron = queryId("slider-previous", slidesContainer);
const slideRightChevron = queryId("slider-next", slidesContainer);
const slideMarkers = Array.from(queryIdAll("slider-marker", slidesContainer));
const sliderControls = queryId("slider-controls", slidesContainer);

sliderControls.classList.replace("hidden", "flex");
const slidesLength = slides.length;

const slidesWidth = slidesContainer.getBoundingClientRect().width;
const { width: slideWidth, left: slideLeftDistance } =
slides[0].getBoundingClientRect();
const { left: slideLeftDistanceSecond } = slides[1].getBoundingClientRect();
const slideGap = slideLeftDistanceSecond - slideLeftDistance - slideWidth;
const adjustment = (slidesWidth - slideWidth) / 2;

let currentIndex = 0;
let touchStartX = 0;

const calculateTransform = (index) =>
index * -slideWidth + adjustment + index * -slideGap;

const updateSlide = (index) =>
(transformContainer.style.transform = `translateX(${calculateTransform(
index
)}px)`);

const updateMarkers = (index) => {
slideMarkers.forEach((marker) =>
marker.classList.remove("text-active-orange")
);
slideMarkers[index].classList.remove("text-cool-black");
slideMarkers[index].classList.add("text-active-orange");
};

const slideLeft = () => {
currentIndex = currentIndex - 1 <= 0 ? 0 : currentIndex - 1;
updateSlide(currentIndex);
updateMarkers(currentIndex);
};

const slideRight = () => {
currentIndex =
currentIndex + 1 >= slidesLength ? currentIndex : currentIndex + 1;
updateSlide(currentIndex);
updateMarkers(currentIndex);
};

updateSlide(0);
updateMarkers(0);

slideLeftChevron.addEventListener("click", slideLeft);

transformContainer.addEventListener("touchstart", (e) => {
touchStartX = e.touches[0]?.clientX;
});

transformContainer.addEventListener("touchend", (e) => {
const distance = e.changedTouches[0]?.clientX - touchStartX;

// Prevent sliding on clicks
if (Math.abs(distance) < DRAG_BUFFER) return;

const direction = distance > 0 ? slideLeft : slideRight;
direction();
});

slideRightChevron.addEventListener("click", slideRight);

return () => {
transformContainer.style.transform = null;
sliderControls.classList.replace("flex", "hidden");
};
};

const Slider = ({ container, mqEnableThreshold }) => {
if (!container) return;

const breakpointCheck = mqEnableThreshold || (() => !mdBreakpoint());

let unmount = () => {};
if (breakpointCheck()) unmount = init(container);

window.addEventListener(
"resize",
throttle(() => {
if (breakpointCheck()) {
unmount = init(container);
} else {
unmount();
}
}, 100)
);
};

export default Slider;
Loading

0 comments on commit 435dc72

Please sign in to comment.