From 0c0ee849a630f125a8f08c10ee71dfdbc6b7c7ce Mon Sep 17 00:00:00 2001 From: schererleander Date: Fri, 27 Jun 2025 00:42:58 +0200 Subject: chore --- src/components/Card.tsx | 82 +++++++++++++++++++++++++++++ src/components/CardLink.tsx | 82 ----------------------------- src/components/Gallery.tsx | 100 ++++++++++++++++++++++++++++++++++++ src/components/ImageGalleryGrid.tsx | 100 ------------------------------------ 4 files changed, 182 insertions(+), 182 deletions(-) create mode 100644 src/components/Card.tsx delete mode 100644 src/components/CardLink.tsx create mode 100644 src/components/Gallery.tsx delete mode 100644 src/components/ImageGalleryGrid.tsx (limited to 'src/components') diff --git a/src/components/Card.tsx b/src/components/Card.tsx new file mode 100644 index 0000000..e71cf33 --- /dev/null +++ b/src/components/Card.tsx @@ -0,0 +1,82 @@ +import { useRef, useState } from "react"; + +function Icon() { + return ; +} + +interface Props { + title: string; + body: string; + href?: string; + imgSrc?: string; +} + +export default function CardLink({ title, body, href, imgSrc }: Props) { + const divRef = useRef(null); + const [position, setPosition] = useState({ x: 0, y: 0 }); + const [opacity, setOpacity] = useState(0); + + const handleMouseMove: React.MouseEventHandler = (e) => { + if (!divRef.current) return; + const rect = divRef.current.getBoundingClientRect(); + setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top }); + }; + + const handleMouseEnter = () => setOpacity(0.6); + const handleMouseLeave = () => setOpacity(0); + + return ( +
window.open(href, "_blank", "noopener,noreferrer"), + role: "link", + tabIndex: 0, + })} + > + {/* Spotlight overlay - light */} +
+ + {/* Spotlight overlay - dark mode */} +
+ + {/* Content */} + {imgSrc && ( + {title} + )} +
+

{title}

+

{body}

+
+ {href && } +
+ ); +} diff --git a/src/components/CardLink.tsx b/src/components/CardLink.tsx deleted file mode 100644 index e71cf33..0000000 --- a/src/components/CardLink.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { useRef, useState } from "react"; - -function Icon() { - return ; -} - -interface Props { - title: string; - body: string; - href?: string; - imgSrc?: string; -} - -export default function CardLink({ title, body, href, imgSrc }: Props) { - const divRef = useRef(null); - const [position, setPosition] = useState({ x: 0, y: 0 }); - const [opacity, setOpacity] = useState(0); - - const handleMouseMove: React.MouseEventHandler = (e) => { - if (!divRef.current) return; - const rect = divRef.current.getBoundingClientRect(); - setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top }); - }; - - const handleMouseEnter = () => setOpacity(0.6); - const handleMouseLeave = () => setOpacity(0); - - return ( -
window.open(href, "_blank", "noopener,noreferrer"), - role: "link", - tabIndex: 0, - })} - > - {/* Spotlight overlay - light */} -
- - {/* Spotlight overlay - dark mode */} -
- - {/* Content */} - {imgSrc && ( - {title} - )} -
-

{title}

-

{body}

-
- {href && } -
- ); -} diff --git a/src/components/Gallery.tsx b/src/components/Gallery.tsx new file mode 100644 index 0000000..ffcf0e1 --- /dev/null +++ b/src/components/Gallery.tsx @@ -0,0 +1,100 @@ +import React, { useState, useEffect } from 'react'; + +interface ImageItems { + images: Array<{ + src: string; + alt?: string; + id?: string | number; + }>; +} + +export default function Gallery({ images }: ImageItems) { + const [selectedIndex, setSelectedIndex] = useState(null); + const closeModal = () => setSelectedIndex(null); + const prev = (e?: React.MouseEvent) => { + e?.stopPropagation(); + setSelectedIndex((i) => (i !== null && i > 0 ? i - 1 : i)); + }; + const next = (e?: React.MouseEvent) => { + e?.stopPropagation(); + setSelectedIndex((i) => (i !== null && i < images.length - 1 ? i + 1 : i)); + }; + + useEffect(() => { + function handleKeyDown(event: KeyboardEvent) { + if (selectedIndex === null) return; + if (event.key === 'ArrowLeft') { + prev(); + } else if (event.key === 'ArrowRight') { + next(); + } + } + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [selectedIndex, images.length]); + + return ( + <> +
+ {images.map((image, idx) => ( + + ))} +
+ + {/* Overlay */} + {selectedIndex !== null && ( +
+ {/* Prev arrow */} + + + {images[selectedIndex].alt + + {/* Next arrow */} + + +
+ )} + + ); +} diff --git a/src/components/ImageGalleryGrid.tsx b/src/components/ImageGalleryGrid.tsx deleted file mode 100644 index 0b657cf..0000000 --- a/src/components/ImageGalleryGrid.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useState, useEffect } from 'react'; - -interface ImageItems { - images: Array<{ - src: string; - alt?: string; - id?: string | number; - }>; -} - -export default function ImageGalleryGrid({ images }: ImageItems) { - const [selectedIndex, setSelectedIndex] = useState(null); - const closeModal = () => setSelectedIndex(null); - const prev = (e?: React.MouseEvent) => { - e?.stopPropagation(); - setSelectedIndex((i) => (i !== null && i > 0 ? i - 1 : i)); - }; - const next = (e?: React.MouseEvent) => { - e?.stopPropagation(); - setSelectedIndex((i) => (i !== null && i < images.length - 1 ? i + 1 : i)); - }; - - useEffect(() => { - function handleKeyDown(event: KeyboardEvent) { - if (selectedIndex === null) return; - if (event.key === 'ArrowLeft') { - prev(); - } else if (event.key === 'ArrowRight') { - next(); - } - } - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [selectedIndex, images.length]); - - return ( - <> -
- {images.map((image, idx) => ( - - ))} -
- - {/* Overlay */} - {selectedIndex !== null && ( -
- {/* Prev arrow */} - - - {images[selectedIndex].alt - - {/* Next arrow */} - - -
- )} - - ); -} -- cgit v1.3.1