From acaa6b02442dcfacf385382faa2ca8dbc0999e32 Mon Sep 17 00:00:00 2001 From: Nick Burka Date: Wed, 30 Oct 2024 09:53:07 -0400 Subject: [PATCH] Add next/prev links and right/left arrow handling --- src/components/IconTileModal.module.scss | 27 ++++++++++ src/components/IconTileModal.tsx | 68 ++++++++++++++++++++++++ src/components/LandingPage.tsx | 18 ++++--- 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/components/IconTileModal.module.scss b/src/components/IconTileModal.module.scss index a7bf2ed8b..eadab89b3 100644 --- a/src/components/IconTileModal.module.scss +++ b/src/components/IconTileModal.module.scss @@ -111,6 +111,33 @@ margin-top: 2rem; } +.nextPrevLinksWrapper { + position: absolute; + top: 20px; + left: 24px; +} + +.nextPrevLinksWrapper a { + background: none; + border: none; + color: var(--link-color); + font-size: 1.5rem; + font-weight: bold; + padding-right: 0.2rem; + + &:hover { + color: var(--link-color-dark); + cursor: pointer; + } +} + +.nextPrevLinksWrapper span { + padding-right: 0.2rem; + font-size: 1.5rem; + font-weight: bold; + color: #ccc; +} + @media (min-width: 60rem) { .modalWrapper { max-height: none; diff --git a/src/components/IconTileModal.tsx b/src/components/IconTileModal.tsx index 9680b8de8..9bdb6385d 100644 --- a/src/components/IconTileModal.tsx +++ b/src/components/IconTileModal.tsx @@ -1,15 +1,55 @@ import styles from './IconTileModal.module.scss'; import ReactModal from 'react-modal'; +import { useEffect } from 'react'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; import { Icon } from '../lib/icons'; interface IconTileModalProps { icon: Icon; + allIcons: Icon[]; iconType: string; isOpen: boolean; onClose: () => void; } export function IconTileModal(props: IconTileModalProps) { + const router = useRouter(); + + const currentIndex = props.allIcons.map((i) => i.id).indexOf(props.icon.id); + const nextIcon = + currentIndex < props.allIcons.length - 1 + ? props.allIcons[currentIndex + 1] + : null; + + const prevIcon = currentIndex > 0 ? props.allIcons[currentIndex - 1] : null; + + useEffect(() => { + const keyDownHandler = (e) => { + if (e.code === 'ArrowRight') { + if (nextIcon) { + router.replace( + `/icon/${props.iconType}/${nextIcon.category}/${nextIcon.id}`, + { scroll: false } + ); + } + } else if (e.code === 'ArrowLeft') { + if (prevIcon) { + router.replace( + `/icon/${props.iconType}/${prevIcon.category}/${prevIcon.id}`, + { scroll: false } + ); + } + } + }; + document.addEventListener('keydown', keyDownHandler); + + // clean up + return () => { + document.removeEventListener('keydown', keyDownHandler); + }; + }); + return (
<> +
+ {prevIcon ? ( + + ◀ + + ) : ( + + )} + {nextIcon ? ( + + ▶ + + ) : ( + + )} +
(undefined); + const router = useRouter(); useMemo(() => { @@ -102,6 +103,14 @@ export default function LandingPage({ return counter + c.icons.length; }, 0); + const flatIcons = categoriesToRender.flatMap((c) => c.icons); + // if searching by keyword, show all icons without categories and sorted A-Z + if (searchKeywordsValue) { + flatIcons.sort((i1, i2) => { + return i1.title < i2.title ? -1 : i1.title > i2.title ? 1 : 0; + }); + } + return (
@@ -184,13 +193,7 @@ export default function LandingPage({
{searchKeywordsValue ? ( i.icons) - .flat() - .sort((i1, i2) => { - // show all icons without categories and sorted A-Z - return i1.title < i2.title ? -1 : i1.title > i2.title ? 1 : 0; - })} + icons={flatIcons} setModalIcon={setModalIcon} style={searchStyleValue} format={searchFormatValue} @@ -214,6 +217,7 @@ export default function LandingPage({ icon={modalIcon.icon} iconType={modalIcon.iconType} isOpen={modalIcon !== undefined} + allIcons={flatIcons} onClose={() => { router.push('/', undefined, { shallow: true,