diff --git a/src/components/pagination/on-click-base.ts b/src/components/pagination/on-click-base.ts new file mode 100644 index 00000000..ce31c737 --- /dev/null +++ b/src/components/pagination/on-click-base.ts @@ -0,0 +1,26 @@ +export const onSoftNavClick = + (softNavigate: (href: string) => void) => (e: MouseEvent) => { + let link = e.target as HTMLElement; + // Could click on a child element of an anchor + while (link && !(link instanceof HTMLAnchorElement)) { + link = link.parentElement; + } + + if (!link) return; + + if ( + link instanceof HTMLAnchorElement && + link.href && + (!link.target || link.target === "_self") && + link.origin === location.origin && + e.button === 0 && // left click only + !e.metaKey && // open in new tab (mac) + !e.ctrlKey && // open in new tab (windows) + !e.altKey && // download + !e.shiftKey && // open in new window + !e.defaultPrevented + ) { + e.preventDefault(); + softNavigate(link.href); + } + }; diff --git a/src/components/pagination/pagination-popover.tsx b/src/components/pagination/pagination-popover.tsx index c7fc38c8..97f1f09b 100644 --- a/src/components/pagination/pagination-popover.tsx +++ b/src/components/pagination/pagination-popover.tsx @@ -11,7 +11,7 @@ import { } from "@floating-ui/react"; import { useRef, useState } from "preact/hooks"; import { Fragment } from "preact"; -import { createPortal } from "preact/compat"; +import { createPortal, StateUpdater } from "preact/compat"; import mainStyles from "./pagination.module.scss"; import more from "src/icons/more_horiz.svg?raw"; import { PaginationProps } from "components/pagination/types"; @@ -21,14 +21,23 @@ import subtract from "../../icons/subtract.svg?raw"; import add from "../../icons/add.svg?raw"; import { Input } from "components/input/input"; -function PopupContents(props: Pick) { +function PopupContents( + props: Pick & { + setIsOpen: StateUpdater; + } +) { const [count, setCount] = useState(props.page.currentPage); return (
{ e.preventDefault(); - location.href = `/page/${count}`; + if (props.softNavigate) { + props.softNavigate(props.getPageHref(count)); + props.setIsOpen(false); + return; + } + location.href = props.getPageHref(count); }} >
@@ -80,7 +89,7 @@ function PopupContents(props: Pick) { } export function PaginationMenuAndPopover( - props: Pick + props: Pick ) { const [isOpen, setIsOpen] = useState(false); const arrowRef = useRef(null); @@ -90,7 +99,7 @@ export function PaginationMenuAndPopover( placement: "top", onOpenChange: setIsOpen, middleware: [ - offset(32 - (14 / 2)), + offset(32 - 14 / 2), arrow({ element: arrowRef, }), @@ -120,7 +129,7 @@ export function PaginationMenuAndPopover( {...getFloatingProps()} class={style.popup} > - + pageOptionalMin + 3; @@ -22,6 +24,7 @@ function PaginationButton({ selected ? styles.selected : "" }`} href={href} + onClick={softNavigate ? onSoftNavClick(softNavigate) : undefined} aria-label={`Go to page ${pageNum}`} aria-current={selected || undefined} > @@ -35,7 +38,7 @@ function PaginationButton({ * This prevents the pagination menu from rendering on SSR, which throws errors */ function PaginationMenuWrapper( - props: Pick + props: Pick ) { const [shouldRender, setShouldRender] = useState(false); @@ -54,6 +57,7 @@ export const Pagination = ({ class: className = "", id = "post-list-pagination", getPageHref = (pageNum: number) => `${rootURL}${pageNum}`, + softNavigate, }: PaginationProps) => { // if there's only one page, don't render anything if (page.currentPage === 1 && page.lastPage < 2) return <>; @@ -68,7 +72,12 @@ export const Pagination = ({ @@ -81,16 +90,26 @@ export const Pagination = ({ pageNum={pageNum} selected={pageNum === page.currentPage} href={getPageHref(pageNum)} + softNavigate={softNavigate} /> ) : ( - + ); })}
  • void; } export interface PaginationProps { @@ -16,4 +17,5 @@ export interface PaginationProps { id?: string; rootURL?: string; getPageHref?: (pageNum: number) => string; + softNavigate?: (href: string) => void; }