Skip to content

Commit

Permalink
carousel improvements (#654)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasondicker authored Mar 28, 2024
1 parent 4a9aeff commit c2f9d94
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 64 deletions.
3 changes: 1 addition & 2 deletions src/web/src/api/services/marketplace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ export const searchStoreItemCategories = async (
);
return data;

// TODO: remove
// return hardcoded data based on the filter.pageNumber
// TODO: hardcoded data based on the filter.pageNumber
// const { pageNumber } = filter;
// const items = Array.from({ length: 4 }, (_, index) => {
// return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,11 @@ export const PrevButton: React.FC<PropType> = (props) => {

return (
<button
className="embla__button embla__button--prev"
//className="-translate-y-1/2x btn absolute right-0 top-1/2 z-10 rounded-full border-0 bg-purple px-3 hover:border-0 hover:bg-purple hover:brightness-110"
className="btn btn-circle btn-sm transform-gpu cursor-pointer border-[1px] border-purple bg-transparent text-black hover:scale-105 hover:bg-gray"
type="button"
{...restProps}
>
<svg className="embla__button__svg" viewBox="0 0 532 532">
<svg className="h-[40%] w-[40%]" viewBox="0 0 532 532">
<path
fill="currentColor"
d="M355.66 11.354c13.793-13.805 36.208-13.805 50.001 0 13.785 13.804 13.785 36.238 0 50.034L201.22 266l204.442 204.61c13.785 13.805 13.785 36.239 0 50.044-13.793 13.796-36.208 13.796-50.002 0a5994246.277 5994246.277 0 0 0-229.332-229.454 35.065 35.065 0 0 1-10.326-25.126c0-9.2 3.393-18.26 10.326-25.2C172.192 194.973 332.731 34.31 355.66 11.354Z"
Expand All @@ -81,28 +80,16 @@ export const PrevButton: React.FC<PropType> = (props) => {
);
};

//<button
// type="button"
// onClick={() => {
// onClickHandler();
// }}
// title={label}
// className="-translate-y-1/2x btn absolute right-0 top-1/2 z-10 rounded-full border-0 bg-purple px-3 hover:border-0 hover:bg-purple hover:brightness-110"
// >
// <IoIosArrowForward className="h-6 w-6 text-white" />
// </button>

export const NextButton: React.FC<PropType> = (props) => {
const { children, ...restProps } = props;

return (
<button
className="embla__button embla__button--next"
//className="-translate-y-1/2x btn absolute right-0 top-1/2 z-10 rounded-full border-0 bg-purple px-3 hover:border-0 hover:bg-purple hover:brightness-110"
className="btn btn-circle btn-sm transform-gpu cursor-pointer border-[1px] border-purple bg-transparent text-black hover:scale-105 hover:bg-gray"
type="button"
{...restProps}
>
<svg className="embla__button__svg" viewBox="0 0 532 532">
<svg className="h-[40%] w-[40%]" viewBox="0 0 532 532">
<path
fill="currentColor"
d="M176.34 520.646c-13.793 13.805-36.208 13.805-50.001 0-13.785-13.804-13.785-36.238 0-50.034L330.78 266 126.34 61.391c-13.785-13.805-13.785-36.239 0-50.044 13.793-13.796 36.208-13.796 50.002 0 22.928 22.947 206.395 206.507 229.332 229.454a35.065 35.065 0 0 1 10.326 25.126c0 9.2-3.393 18.26-10.326 25.2-45.865 45.901-206.404 206.564-229.332 229.52Z"
Expand Down
45 changes: 45 additions & 0 deletions src/web/src/components/Carousel/SelectedSnapDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useCallback, useEffect, useState } from "react";
import type { EmblaCarouselType } from "embla-carousel";

interface IUseSelectedSnapDisplay {
selectedSnap: number;
snapCount: number;
}

export const useSelectedSnapDisplay = (
emblaApi: EmblaCarouselType | undefined,
): IUseSelectedSnapDisplay => {
const [selectedSnap, setSelectedSnap] = useState(0);
const [snapCount, setSnapCount] = useState(0);

const updateScrollSnapState = useCallback((emblaApi: EmblaCarouselType) => {
setSnapCount(emblaApi.scrollSnapList().length);
setSelectedSnap(emblaApi.selectedScrollSnap());
}, []);

useEffect(() => {
if (!emblaApi) return;

updateScrollSnapState(emblaApi);
emblaApi.on("select", updateScrollSnapState);
emblaApi.on("reInit", updateScrollSnapState);
}, [emblaApi, updateScrollSnapState]);

return {
selectedSnap,
snapCount,
};
};

export const SelectedSnapDisplay: React.FC<{
selectedSnap: number;
snapCount: number;
}> = (props) => {
const { selectedSnap, snapCount } = props;

return (
<div className="flex w-24 select-none items-center justify-end font-semibold">
{selectedSnap + 1} / {snapCount}
</div>
);
};
2 changes: 1 addition & 1 deletion src/web/src/components/Marketplace/ItemCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const ItemCardComponent: React.FC<InputProps> = ({
return (
<Link
key={id}
className="relative flex aspect-square h-56 w-full transform-gpu flex-col items-center gap-4 rounded-lg bg-white p-4 shadow-lg transition-transform hover:scale-105 md:w-[340px]"
className="relative flex aspect-square h-56 w-[340px] transform-gpu flex-col items-center gap-4 rounded-lg bg-white p-4 shadow-sm transition-transform hover:scale-[1.01] hover:shadow-md"
href={href ?? "/"}
onClick={onClick2}
onAuxClick={onClick2}
Expand Down
36 changes: 24 additions & 12 deletions src/web/src/components/Marketplace/StoreItemsCarousel2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import type { EngineType } from "embla-carousel/components/Engine";
import type { EmblaCarouselType, EmblaOptionsType } from "embla-carousel";
import useEmblaCarousel from "embla-carousel-react";
import {
NextButton,
PrevButton,
usePrevNextButtons,
} from "./EmblaCarouselArrowButtons";
import type { StoreItemCategorySearchResults } from "~/api/models/marketplace";
import { ItemCardComponent } from "./ItemCard";
import Link from "next/link";
import { PAGE_SIZE_MINIMUM } from "~/lib/constants";
import {
usePrevNextButtons,
PrevButton,
NextButton,
} from "../Carousel/ArrowButtons";
import {
SelectedSnapDisplay,
useSelectedSnapDisplay,
} from "../Carousel/SelectedSnapDisplay";

const OPTIONS: EmblaOptionsType = {
dragFree: true,
Expand All @@ -33,7 +37,9 @@ const StoreItemsCarousel2: React.FC<{
const listenForScrollRef = useRef(true);
const hasMoreToLoadRef = useRef(true);
const [slides, setSlides] = useState(propData.items);
const [hasMoreToLoad, setHasMoreToLoad] = useState(true);
const [hasMoreToLoad, setHasMoreToLoad] = useState(
propData.items.length >= PAGE_SIZE_MINIMUM,
);
const [loadingMore, setLoadingMore] = useState(false);

const [emblaRef, emblaApi] = useEmblaCarousel({
Expand Down Expand Up @@ -78,6 +84,7 @@ const StoreItemsCarousel2: React.FC<{
}
},
});
const { selectedSnap, snapCount } = useSelectedSnapDisplay(emblaApi);

const {
prevBtnDisabled,
Expand All @@ -100,6 +107,7 @@ const StoreItemsCarousel2: React.FC<{
// );
if (emblaApi.slideNodes().length < PAGE_SIZE_MINIMUM) {
loadMore = false;
setHasMoreToLoad(false);
}

if (loadMore) {
Expand All @@ -112,7 +120,6 @@ const StoreItemsCarousel2: React.FC<{
);

loadData(emblaApi.slideNodes().length + 1).then((data) => {
// debugger;
if (data.items.length == 0) {
setHasMoreToLoad(false);
emblaApi.off("scroll", scrollListenerRef.current);
Expand Down Expand Up @@ -176,13 +183,12 @@ const StoreItemsCarousel2: React.FC<{
)} */}
</div>

<div className="embla">
<div className="embla h-60x">
<div className="embla__viewport" ref={emblaRef}>
<div className="embla__container max-3">
{slides?.map((item, index) => (
<div className="embla__slide" key={index}>
<div className="embla__slide__number">
{/* <span>{index + 1}</span> */}
<ItemCardComponent
key={`storeCategoryItem_${id}_${index}`}
id={`storeCategoryItem_${id}_${index}`}
Expand All @@ -209,18 +215,24 @@ const StoreItemsCarousel2: React.FC<{
</div>
</div>

<div className="embla__controls">
<div className="flex gap-2">
{snapCount > 1 && selectedSnap < snapCount && (
<div className="flex place-content-end gap-2">
<SelectedSnapDisplay
selectedSnap={selectedSnap}
snapCount={snapCount}
/>

<PrevButton
onClick={onPrevButtonClick}
disabled={prevBtnDisabled}
/>

<NextButton
onClick={onNextButtonClick}
disabled={nextBtnDisabled}
/>
</div>
</div>
)}
</div>
</>
);
Expand Down
28 changes: 19 additions & 9 deletions src/web/src/components/Opportunity/OpportunitiesCarousel2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import Link from "next/link";
import { PAGE_SIZE_MINIMUM } from "~/lib/constants";
import { OpportunityPublicSmallComponent } from "./OpportunityPublicSmall";
import {
NextButton,
PrevButton,
SelectedSnapDisplay,
useSelectedSnapDisplay,
} from "../Carousel/SelectedSnapDisplay";
import {
usePrevNextButtons,
} from "../Marketplace/EmblaCarouselArrowButtons";
PrevButton,
NextButton,
} from "../Carousel/ArrowButtons";

const OPTIONS: EmblaOptionsType = {
dragFree: true,
Expand Down Expand Up @@ -77,6 +81,7 @@ const OpportunitiesCarousel2: React.FC<{
}
},
});
const { selectedSnap, snapCount } = useSelectedSnapDisplay(emblaApi);

const {
prevBtnDisabled,
Expand Down Expand Up @@ -151,8 +156,8 @@ const OpportunitiesCarousel2: React.FC<{
}, [hasMoreToLoad]);

return (
<>
<div className="mb-4 flex flex-col gap-6">
<div className="mb-4">
<div className="mb-2 flex flex-col gap-6">
<div className="flex flex-row">
<div className="flex flex-grow">
<div className="overflow-hidden text-ellipsis whitespace-nowrap text-xl font-semibold text-black md:max-w-[800px]">
Expand Down Expand Up @@ -200,8 +205,13 @@ const OpportunitiesCarousel2: React.FC<{
</div>
</div>

<div className="embla__controls">
<div className="mt-10 flex gap-2">
{snapCount > 1 && selectedSnap < snapCount && (
<div className="flex place-content-end gap-2">
<SelectedSnapDisplay
selectedSnap={selectedSnap}
snapCount={propData.totalCount ?? snapCount}
/>

<PrevButton
onClick={onPrevButtonClick}
disabled={prevBtnDisabled}
Expand All @@ -211,9 +221,9 @@ const OpportunitiesCarousel2: React.FC<{
disabled={nextBtnDisabled}
/>
</div>
</div>
)}
</div>
</>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const OpportunityPublicSmallComponent: React.FC<InputProps> = ({ data }) => {
return (
<Link
href={`/opportunities/${data.id}`}
className="relative flex aspect-square w-[300px] transform-gpu flex-col gap-1 rounded-lg bg-white p-5 shadow-custom transition-all duration-300 hover:scale-[1.01] hover:shadow-lg md:max-w-[300px]"
className="relative flex aspect-square h-80 w-[300px] transform-gpu flex-col gap-1 rounded-lg bg-white p-5 shadow-sm transition-all duration-300 hover:scale-[1.01] hover:shadow-md"
>
<div className="flex flex-row">
<div className="flex flex-row">
Expand Down
11 changes: 9 additions & 2 deletions src/web/src/pages/marketplace/[country]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { GetStaticPaths, GetStaticProps } from "next";
import { useQueryClient } from "@tanstack/react-query";
import React, { useCallback, type ReactElement, useState } from "react";
import React, { useCallback, type ReactElement, useState, useRef } from "react";
import { type NextPageWithLayout } from "~/pages/_app";
import NoRowsMessage from "~/components/NoRowsMessage";
import {
Expand Down Expand Up @@ -226,6 +226,7 @@ const MarketplaceStoreCategories: NextPageWithLayout<{
const setUserProfile = useSetAtom(userProfileAtom);
const setUserCountrySelection = useSetAtom(userCountrySelectionAtom);
const modalContext = useConfirmationModalContext();
const myRef = useRef<HTMLDivElement>(null);

const onFilterCountry = useCallback(
(value: string) => {
Expand Down Expand Up @@ -692,6 +693,9 @@ const MarketplaceStoreCategories: NextPageWithLayout<{
</div>
</ReactModal>

{/* REFERENCE FOR FILTER POPUP: fix menu z-index issue */}
<div ref={myRef} />

{/* FILTER: COUNTRY */}
<div className="flex flex-row items-center justify-start gap-4">
<div className="text-sm font-semibold text-gray-dark">Filter by:</div>
Expand All @@ -706,9 +710,12 @@ const MarketplaceStoreCategories: NextPageWithLayout<{
(c) => c.value === (country?.toString() ?? COUNTRY_WW),
)}
placeholder="Country"
// fix menu z-index issue
menuPortalTarget={myRef.current}
styles={{ menuPortal: (base) => ({ ...base, zIndex: 9999 }) }}
/>
</div>
<div className=" flex flex-col gap-6 px-2 pb-4 md:p-0 md:pb-0">
<div className="flex flex-col gap-6 px-2 pb-4 md:p-0 md:pb-0">
{data_storeItems.length == 0 && (
<NoRowsMessage title="No items found" />
)}
Expand Down
Loading

0 comments on commit c2f9d94

Please sign in to comment.