diff --git a/src/components/Catalogue/cardComponent.jsx b/src/components/Catalogue/cardComponent.jsx
new file mode 100644
index 0000000..53bcd47
--- /dev/null
+++ b/src/components/Catalogue/cardComponent.jsx
@@ -0,0 +1,30 @@
+import { Card, Image, Text, Skeleton } from "@chakra-ui/react";
+
+const CardComponent = ({ imageSrc, itemTitle, itemDescription, isLoading, setIsLoading, isSelected, expanded }) => {
+ return (
+
+
+ setIsLoading(false)}
+ height="180px"
+ width="100%"
+ />
+
+
+
+ {itemTitle}
+
+ {expanded && (
+
+ {itemDescription}
+
+ )}
+
+
+ );
+};
+
+export default CardComponent;
diff --git a/src/components/Catalogue/cardItem.jsx b/src/components/Catalogue/cardItem.jsx
index 71890d8..e66c22c 100644
--- a/src/components/Catalogue/cardItem.jsx
+++ b/src/components/Catalogue/cardItem.jsx
@@ -1,7 +1,7 @@
-// CardItem.jsx
-import { Box, Card, Image, Text } from "@chakra-ui/react";
-import React, { useState, useRef, useEffect } from "react";
+import { Box, useBreakpointValue } from "@chakra-ui/react";
+import { useState, useRef, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
+import CardComponent from "./cardComponent";
const MotionBox = motion.create(Box);
@@ -13,8 +13,12 @@ const images = [
];
const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
+ const isMobile = useBreakpointValue({ base: true, md: false });
+
const [isHovered, setIsHovered] = useState(false);
const [isSelected, setIsSelected] = useState(selectedTitle === itemTitle);
+ const [isLoading, setIsLoading] = useState(true);
+
const cardRef = useRef(null);
const [hoverPos, setHoverPos] = useState({ top: 0, left: 0 });
const scrollContainerRef = useRef(null);
@@ -24,6 +28,12 @@ const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
setIsSelected(selectedTitle === itemTitle);
}, [selectedTitle, itemTitle]);
+ const imageSrc = images[index % images.length];
+
+ useEffect(() => {
+ setIsLoading(true);
+ }, [imageSrc]);
+
const updateHoverPosition = () => {
const rect = cardRef.current?.getBoundingClientRect();
if (rect) {
@@ -47,6 +57,7 @@ const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
};
const handleMouseEnter = () => {
+ if (isMobile) return;
hoverTimeoutRef.current = setTimeout(() => {
updateHoverPosition();
setIsHovered(true);
@@ -59,7 +70,7 @@ const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
};
useEffect(() => {
- if (isHovered) {
+ if (isHovered && !isMobile) {
let node = cardRef.current;
while (node) {
const style = window.getComputedStyle(node);
@@ -78,26 +89,18 @@ const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
window.addEventListener("scroll", updateHoverPosition, true);
window.addEventListener("resize", updateHoverPosition);
if (scrollContainerRef.current) {
- scrollContainerRef.current.addEventListener(
- "scroll",
- updateHoverPosition
- );
+ scrollContainerRef.current.addEventListener("scroll", updateHoverPosition);
}
return () => {
window.removeEventListener("scroll", updateHoverPosition, true);
window.removeEventListener("resize", updateHoverPosition);
if (scrollContainerRef.current) {
- scrollContainerRef.current.removeEventListener(
- "scroll",
- updateHoverPosition
- );
+ scrollContainerRef.current.removeEventListener("scroll", updateHoverPosition);
}
};
}
- }, [isHovered]);
-
- const imageSrc = images[index % images.length];
+ }, [isHovered, isMobile]);
return (
<>
@@ -114,55 +117,53 @@ const CardItem = ({ itemTitle, itemDescription, selectedTitle, index }) => {
borderRadius="md"
boxShadow={isSelected ? "lg" : "md"}
>
-
-
-
- {itemTitle}
-
-
+
-
- {isHovered && (
- setIsHovered(true)}
- borderRadius="md"
- border={isSelected ? "1px solid" : "none"}
- borderColor={isSelected ? "blue.600" : "transparent"}
- boxShadow={
- isSelected
- ? "0 0 15px 2px rgba(66,153,225,0.6)"
- : "2xl"
- }
- >
-
-
-
- {itemTitle}
- {itemDescription}
-
-
-
- )}
-
+ {!isMobile && (
+
+ {isHovered && (
+ setIsHovered(true)}
+ borderRadius="md"
+ border={isSelected ? "1px solid" : "none"}
+ borderColor={isSelected ? "blue.600" : "transparent"}
+ boxShadow={isSelected ? "0 0 15px 2px rgba(66,153,225,0.6)" : "2xl"}
+ >
+
+
+ )}
+
+ )}
>
);
};
diff --git a/src/components/Catalogue/catalogueItemView.jsx b/src/components/Catalogue/catalogueItemView.jsx
index 20f2e9b..399affa 100644
--- a/src/components/Catalogue/catalogueItemView.jsx
+++ b/src/components/Catalogue/catalogueItemView.jsx
@@ -8,25 +8,32 @@ const MotionChevron = motion.create(Box);
const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imageSrc }) => {
const [isNavigating, setIsNavigating] = useState(false);
+ const [direction, setDirection] = useState(0);
+ const [isInitialRender, setIsInitialRender] = useState(true);
+ const [hasRendered, setHasRendered] = useState(false);
const isMobile = useBreakpointValue({ base: true, md: false });
+ const scrollRef = useRef(null);
+ const modalRef = useRef(null);
const currentIndex = items.findIndex((item) => item.title === title);
const prevItem = () => {
- if (currentIndex > 0) {
+ if (!isNavigating && currentIndex > 0) {
+ setDirection(-1);
setIsNavigating(true);
setDialogTitle(items[currentIndex - 1].title);
}
};
const nextItem = () => {
- if (currentIndex < items.length - 1) {
+ if (!isNavigating && currentIndex < items.length - 1) {
+ setDirection(1);
setIsNavigating(true);
setDialogTitle(items[currentIndex + 1].title);
}
};
- // Lock body scroll when modal is open
+ // Prevent background scroll when modal is open
useEffect(() => {
document.body.style.overflow = isOpen ? "hidden" : "";
return () => {
@@ -34,7 +41,7 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag
};
}, [isOpen]);
- // Reset isNavigating after item change animation
+ // Allow new navigation after animation ends
useEffect(() => {
if (isNavigating) {
const timeout = setTimeout(() => setIsNavigating(false), 250);
@@ -42,7 +49,53 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag
}
}, [title]);
- // Responsive values
+ // Reset flags when modal closes
+ useEffect(() => {
+ if (!isOpen) {
+ setHasRendered(false);
+ setDirection(0);
+ setIsInitialRender(true);
+ }
+ }, [isOpen]);
+
+ // Scroll to correct position on mobile when rendered
+ useEffect(() => {
+ if (isMobile && isOpen && hasRendered && scrollRef.current) {
+ scrollRef.current.scrollTo({
+ left: currentIndex * window.innerWidth,
+ behavior: "instant",
+ });
+ }
+ }, [isMobile, isOpen, hasRendered, currentIndex]);
+
+ // Keyboard navigation
+ useEffect(() => {
+ const handleKeyDown = (e) => {
+ if (!isOpen || isNavigating) return;
+ if (e.key === "ArrowLeft" && currentIndex > 0) prevItem();
+ else if (e.key === "ArrowRight" && currentIndex < items.length - 1) nextItem();
+ };
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [isOpen, isNavigating, currentIndex, items]);
+
+ // Focus modal when open
+ useEffect(() => {
+ if (isOpen && modalRef.current) modalRef.current.focus();
+ }, [isOpen]);
+
+ // Local keydown handler
+ const handleKeyDown = (e) => {
+ if (isNavigating) return;
+ if (e.key === "ArrowLeft" && currentIndex > 0) {
+ e.preventDefault();
+ prevItem();
+ } else if (e.key === "ArrowRight" && currentIndex < items.length - 1) {
+ e.preventDefault();
+ nextItem();
+ }
+ };
+
const modalSize = {
width: isMobile ? "100vw" : "80vw",
height: isMobile ? "100vh" : "80vh",
@@ -51,11 +104,17 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag
const chevronPosition = {
left: isMobile ? "10px" : "calc(10vw - 60px)",
right: isMobile ? "10px" : "calc(10vw - 60px)",
- top: isMobile ? "50%" : "50%"
+ top: "50%",
};
const chevronSize = isMobile ? "30px" : "40px";
+ const desktopVariants = {
+ enter: (direction) => ({ x: direction > 0 ? "100%" : "-100%", opacity: 0 }),
+ center: { x: 0, opacity: 1 },
+ exit: (direction) => ({ x: direction > 0 ? "-100%" : "100%", opacity: 0 }),
+ };
+
return (
@@ -78,72 +137,69 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag
onClick={onClose}
/>
- {/* Left Chevron */}
-
- {currentIndex > 0 && (
-
-
-
- )}
-
-
- {/* Right Chevron */}
-
- {currentIndex < items.length - 1 && (
-
-
-
- )}
-
-
- {/* Modal Wrapper */}
+ {/* Desktop chevrons */}
+ {!isMobile && (
+ <>
+ {currentIndex > 0 && (
+
+
+
+ )}
+
+ {currentIndex < items.length - 1 && (
+
+
+
+ )}
+ >
+ )}
+
+ {/* Modal content */}
e.stopPropagation()}
>
-
- {/* Image Section */}
-
-
+ {items.map((item) => (
+
+
+
+
+
+
+
+ {item.title}
+
+
+
+ ))}
+ {!hasRendered && (
+ setHasRendered(true)} />
+ )}
-
- {/* Content Section */}
-
-
-
- {title}
-
- {/* Add your content here */}
+ ) : (
+ // Desktop: sliding animation
+
+
+ {
+ if (isInitialRender) setIsInitialRender(false);
+ }}
+ >
+
+
+
+
+
+
+ {title}
+
+
+
+
-
+ )}
@@ -231,4 +333,4 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag
);
};
-export default CatalogueItemView;
\ No newline at end of file
+export default CatalogueItemView;
diff --git a/src/components/Catalogue/mmSection.jsx b/src/components/Catalogue/mmSection.jsx
index cb6e3a5..d7a40d4 100644
--- a/src/components/Catalogue/mmSection.jsx
+++ b/src/components/Catalogue/mmSection.jsx
@@ -1,9 +1,11 @@
-import { Box, Table, Text, Icon } from "@chakra-ui/react";
+import { Box, Table, Text, useBreakpointValue } from "@chakra-ui/react";
import { useRef, useState, useEffect } from "react";
import CardItem from "./cardItem.jsx";
import ArrowOverlay from "./arrowOverlay.jsx";
const MMSection = ({ onItemClick, selectedTitle }) => {
+ const isMobile = useBreakpointValue({ base: true, md: false });
+
const items = Array.from({ length: 15 }).map((_, idx) => ({
id: idx + 1,
title: `Meeting ${idx + 1}`,
@@ -18,15 +20,7 @@ const MMSection = ({ onItemClick, selectedTitle }) => {
const node = scrollRef.current;
if (!node) return;
setAtStart(node.scrollLeft === 0);
- setAtEnd(
- Math.ceil(node.scrollLeft + node.clientWidth) >= node.scrollWidth
- );
- };
-
- const handleClick = (title) => {
- if (onItemClick) {
- onItemClick(title);
- }
+ setAtEnd(Math.ceil(node.scrollLeft + node.clientWidth) >= node.scrollWidth);
};
useEffect(() => {
@@ -52,25 +46,28 @@ const MMSection = ({ onItemClick, selectedTitle }) => {
});
};
+ const handleClick = (title) => {
+ if (onItemClick) onItemClick(title);
+ };
+
return (
-
+
Meeting Minutes
- scroll("left")} />
- scroll("right")} />
+ {!isMobile && (
+ <>
+ scroll("left")} />
+ scroll("right")} />
+ >
+ )}
-
+
{items.map((item, index) => (
{
- // Added images array as per your request
+ const isMobile = useBreakpointValue({ base: true, md: false });
+
const images = [
"https://images.unsplash.com/photo-1555041469-a586c61ea9bc?auto=format&fit=crop&w=1770&q=80",
"https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&w=1770&q=80",
@@ -14,12 +15,11 @@ const Section = ({ sectionTitle, secLen, selectedTitle, onItemClick }) => {
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=1770&q=80",
];
- // Include imageSrc on each item, cycling images if secLen > images.length
const items = Array.from({ length: secLen }).map((_, idx) => ({
id: idx + 1,
title: `Photo ${idx + 1}`,
description: `Description for photo ${idx + 1}`,
- imageSrc: images[idx % images.length], // added this line
+ imageSrc: images[idx % images.length],
}));
const scrollRef = useRef(null);
@@ -40,9 +40,7 @@ const Section = ({ sectionTitle, secLen, selectedTitle, onItemClick }) => {
const handleCardClick = (title) => {
setDialogTitle(title);
setDialogOpen(true);
- if (onItemClick) {
- onItemClick(title);
- }
+ if (onItemClick) onItemClick(title);
};
useEffect(() => {
@@ -68,36 +66,34 @@ const Section = ({ sectionTitle, secLen, selectedTitle, onItemClick }) => {
});
};
- // Find current item to pass imageSrc to CatalogueItemView
const currentItem = items.find((item) => item.title === dialogTitle);
return (
-
+
{sectionTitle}
- scroll("left")}
- />
- scroll("right")}
- />
+ {!isMobile && (
+ <>
+ scroll("left")}
+ />
+ scroll("right")}
+ />
+ >
+ )}
-
+
{items.map((item, index) => (
{
- handleCardClick(item.title)
- }
+ onClick={() => handleCardClick(item.title)}
>
{
))}
-