diff --git a/src/components/ItemCard.tsx b/src/components/ItemCard.tsx index 140b69f..0955c7b 100644 --- a/src/components/ItemCard.tsx +++ b/src/components/ItemCard.tsx @@ -1,11 +1,12 @@ import React, {useRef} from "react"; import {useOnClickOutside, useToggle} from "usehooks-ts"; -import {classNames, isHoverable} from "../utils/helpers"; +import {classNames, isHoverable, stopPropagation} from "../utils/helpers"; import DependentImage from "./DependentImage"; import ReactMarkdown from 'react-markdown' import Link from "next/link"; import {LinkIcon, LinkIcons} from "../pages"; +import {useRouter} from "next/router"; type ItemCardProps = { banner: string; @@ -13,11 +14,13 @@ type ItemCardProps = { title: string; description: string; links?: LinkIcon[]; + location: string; } -const ItemCard = ({banner, bannerBlur, title, description, links}: ItemCardProps) => { +const ItemCard = ({banner, bannerBlur, title, description, links, location}: ItemCardProps) => { const itemRef = useRef(null); const [active, toggleActive, setActive] = useToggle() + const router = useRouter(); useOnClickOutside(itemRef, () => { setActive(false); @@ -27,6 +30,9 @@ const ItemCard = ({banner, bannerBlur, title, description, links}: ItemCardProps className={classNames("item", active ? "active" : null)} onClick={() => { if (!isHoverable()) toggleActive(); + else { + router.push(location); + } }}> classNames("object-cover", loaded ? null : "blur-xl")} @@ -34,21 +40,24 @@ const ItemCard = ({banner, bannerBlur, title, description, links}: ItemCardProps alt={`Banner for ${title}`} />
-
+ +
{title}
- {description} +
-
- { (links?.length ?? 0) > 0 ?
-
- {links!.map(({icon, location}) => { - return - {LinkIcons[icon]({})} - - })} -
-
: null} + + {(links?.length ?? 0) > 0 ? +
+
+ {links!.map(({icon, location, newTab}) => + + {LinkIcons[icon]!({})} + )} +
+
: null}
} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 89655e0..cfb2ab2 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -14,19 +14,19 @@ export type Project = { longDescription: string; shortDescription: string; links?: LinkIcon[]; + location: string; } -export type LinkIconType = "github" | "external" | "link"; -export const LinkIcons: Record = { +export const LinkIcons: Record = { github: AiFillGithub, external: RxOpenInNewWindow, link: AiOutlineLink } - export type LinkIcon = { - icon: LinkIconType; + icon: keyof typeof LinkIcons; location: string; + newTab?: boolean; } type ProjectWithBlur = Project & { bannerBlur: string }; @@ -41,6 +41,7 @@ export async function getStaticProps(context: GetStaticPropsContext) { { title: "Phototag", banner: "/phototag.png", + location: "/phototag", longDescription: `Using Google's Vision API and supporting metadata formats on Windows, Phototag makes it easy to quickly add rich, descriptive tags to your photos, saving you time and effort.`, shortDescription: "Effortlessly add rich & descriptive tags to your photos with Phototag.", links: [ @@ -57,13 +58,14 @@ export async function getStaticProps(context: GetStaticPropsContext) { { title: "Paths", banner: "/paths.png", + location: "/paths", shortDescription: "Discover the power of graph traversal algorithms with my interactive application.", longDescription: `Discover the power of graph traversal algorithms with my interactive Unity application! Easily generate and edit graphs, create mazes, and experiment with different algorithm configurations to find the most efficient path.`, links: [ { icon: "github", - location: "https://github.com/Xevion/Paths" + location: "https://github.com/Xevion/Paths", } ] } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index b8d3d70..c992d4d 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -6,6 +6,14 @@ export function classNames(...classes: (string | null | undefined)[]) { return classes.filter(Boolean).join(" "); } +/** + * A handler that simply calls the `stopPropagation` method on an event. + * @param event The event to prevent propagation on. + */ +export const stopPropagation = (event: Event) => { + event.stopPropagation(); +}; + const isClient = (): boolean => { return typeof window !== "undefined"; }