Skip to content

Commit

Permalink
Johnny/won/nick/photo carousel 2 (#178)
Browse files Browse the repository at this point in the history
* photo carousel attempt

Co-authored-by: Johnny Tan <[email protected]>
Co-authored-by: Nick Doan <[email protected]>
Co-authored-by: sburchfield33 <[email protected]>

* attempt 2

* ui fixes

---------

Co-authored-by: wkim10 <[email protected]>
Co-authored-by: Johnny Tan <[email protected]>
Co-authored-by: Nick Doan <[email protected]>
Co-authored-by: sburchfield33 <[email protected]>
  • Loading branch information
5 people authored Apr 29, 2024
1 parent 8c9a81d commit 5c6fd77
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 104 deletions.
28 changes: 28 additions & 0 deletions package-lock.json

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

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"react-datepicker": "^6.1.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-loading-skeleton": "^3.4.0",
"react-multi-carousel": "^2.8.5",
"uuidv4": "^6.2.13",
"yarn": "^1.22.19",
"zod": "^3.22.4"
Expand All @@ -46,6 +48,7 @@
"@types/react": "18.0.14",
"@types/react-datepicker": "^6.0.1",
"@types/react-dom": "18.0.5",
"@types/react-image-gallery": "^1.2.4",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"autoprefixer": "^10.4.7",
Expand Down
2 changes: 2 additions & 0 deletions postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module.exports = {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},
Expand Down
2 changes: 1 addition & 1 deletion src/app/public/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const AboutLayout = () => {
};
}, []);
return (
<div className="flex-col justify-center gap-y-4 py-6 sm:flex sm:w-full sm:px-0">
<div className="flex flex-col justify-center gap-y-4 py-6 sm:w-full sm:px-0">
<span className="pt-6 text-center text-4xl font-semibold sm:text-left">
Our Story
</span>
Expand Down
2 changes: 1 addition & 1 deletion src/app/public/team/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const PublicLayout = () => {
<span className="pt-6 text-center text-4xl font-semibold sm:text-left">
Meet TLP
</span>
<p className="mt-7 leading-7">
<p className="mb-4 mt-7 leading-7">
The Legacy Project, Inc. (TLP) connects college students with local
elders in their community with the purpose of building strong
intergenerational relationships and documenting the life histories of
Expand Down
7 changes: 6 additions & 1 deletion src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ const Navbar = () => {
return (
<nav className="fixed top-0 z-20 flex h-[60px] w-full flex-row items-center justify-between border border-dark-tan bg-med-tan px-[30px] py-3 shadow-md shadow-gray-400 sm:px-[50px] md:px-[93px]">
<Link href="/public" onClick={() => setDropdownVisible(false)}>
<Image src={logoicon} alt="Legacy Logo" className="w-[200px]" />
<Image
src={logoicon}
alt="Legacy Logo"
className="w-[200px]"
priority
/>
</Link>

<div className="visible z-10">
Expand Down
166 changes: 65 additions & 101 deletions src/components/PhotoCarousel.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,82 @@
import React, { useState, useEffect, useRef } from "react";
import Image from "next/legacy/image";
"use client";

type PhotoProps = {
filePath: string;
};
import "src/styles/animation.css";
import React from "react";
import NextImage from "next/image";
import "react-loading-skeleton/dist/skeleton.css";
import Skeleton from "react-loading-skeleton";
import "react-multi-carousel/lib/styles.css";
import Carousel from "react-multi-carousel";

interface PhotoCarouselParams {
imagePaths: string[];
}

const PhotoCarousel = ({ imagePaths }: PhotoCarouselParams) => {
const [photos, setPhotos] = useState<PhotoProps[]>([]);
const [activeIndex, setActiveIndex] = useState<number>(0);
const [show, setShow] = useState<number>(1);
const widthRef = useRef<HTMLHeadingElement>(null);

const [elemWidth, setElemWidth] = useState<number>(0);
const Image = ({ path }: { path: string }) => {
const [loaded, setLoaded] = React.useState(false);
const [preloaded, setPreloaded] = React.useState(false);

useEffect(() => {
function handleResize() {
setElemWidth(widthRef.current ? widthRef.current.offsetWidth : 0);
const showVal = widthRef.current
? Math.floor(widthRef.current.offsetWidth / 250)
: 1;
setShow(showVal || 1);
}
window.addEventListener("resize", handleResize);
handleResize();
return () => {
window.removeEventListener("resize", handleResize);
};
React.useEffect(() => {
setTimeout(() => {
setPreloaded(true);
}, 2000);
}, []);

const carouselHeight = elemWidth / show;
const carouselPad = 20;
return (
<div className={"aspect-square h-full w-full"}>
{(!preloaded || !loaded) && <Skeleton className="h-full w-full" />}
<NextImage
className={preloaded && loaded ? "object-cover" : "invisible"}
src={path}
alt="Gallery"
layout="fill"
data-loaded="false"
onLoadingComplete={() => {
setLoaded(true);
}}
/>
</div>
);
};

const nextIndex = () => {
setActiveIndex((prevIndex) => (prevIndex + 1) % photos.length);
};
const PhotoCarousel = ({ imagePaths }: PhotoCarouselParams) => {
const photos = React.useMemo(
() => imagePaths.map((path) => <Image key={path} path={path} />),
[imagePaths]
);

const prevIndex = () => {
setActiveIndex(
(prevIndex) => (prevIndex - 1 + photos.length) % photos.length
);
const responsive = {
superLargeDesktop: {
// the naming can be any, depends on you.
breakpoint: { max: 4000, min: 3000 },
items: 5,
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 4,
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
},
};

useEffect(() => {
setPhotos(
imagePaths.map((path) => ({
filePath: path,
}))
);
}, [imagePaths]);

return (
<div className="flex w-full flex-col place-content-center gap-y-8 py-6">
<div className="relative flex items-center justify-center">
<svg
width="64"
height="64"
viewBox="0 0 64 64"
fill="none"
className="hover:cursor-pointer"
onClick={() => prevIndex()}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M41.0933 44.24L28.8799 32L41.0933 19.76L37.3333 16L21.3333 32L37.3333 48L41.0933 44.24Z"
fill="#000022"
/>
</svg>

<div
className="relative flex w-full flex-row justify-between overflow-hidden ease-in-out"
style={{ height: carouselHeight - carouselPad }}
ref={widthRef}
>
{photos.map((photo, index) => (
<div
key={photo.filePath}
className={
"absolute aspect-square h-full select-none object-cover transition-all"
}
style={{
left:
((index - activeIndex + photos.length) % photos.length) *
(carouselHeight + carouselPad / 2),
}}
>
<Image
className="object-cover"
layout="fill"
src={photo.filePath}
alt={"object cover"}
/>
</div>
))}
</div>
<svg
width="64"
height="64"
viewBox="0 0 64 64"
fill="none"
onClick={() => nextIndex()}
className="hover:cursor-pointer"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M22.9067 19.76L35.1201 32L22.9067 44.24L26.6667 48L42.6667 32L26.6667 16L22.9067 19.76Z"
fill="#000022"
/>
</svg>
</div>
</div>
<Carousel
responsive={responsive}
partialVisbile={false}
sliderClass="gap-x-4"
swipeable={false}
ssr
>
{photos}
{/* @note - We add an empty div because the last image is cut */}
<div />
</Carousel>
);
};

Expand Down
32 changes: 32 additions & 0 deletions src/styles/animation.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.skeleton {
position: relative;
inline-size: 100%;
overflow: hidden;
}

@keyframes shimmer {
from {
transform: "translateX(-100%)";
}
to {
transform: "translateX(100%)";
}
}

&.skeleton {
background: "var(--gray-4)";

&::before {
content: "";
position: absolute;
inset: 0;
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.2) 20%,
rgba(255, 255, 255, 0.5) 60%,
rgba(255, 255, 255, 0)
);
animation: shimmer 2s infinite;
}
}

0 comments on commit 5c6fd77

Please sign in to comment.