All files / src/components/ui PhotoViewControl.tsx

75% Statements 6/8
100% Branches 4/4
66.66% Functions 2/3
75% Lines 6/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 4954x                               3x 3x   3x         3x             1x                                  
"use client";
 
import { useRef, useState } from "react";
import { ImageViewer, type ViewerPhoto } from "./ImageViewer";
 
/** A gentle "view photo" control overlaid on a card image. Opens the ImageViewer
 *  (zoom + rotate). Rendered as a sibling of the card's stretched <Link> (not a
 *  descendant), so it's valid DOM and its tap doesn't navigate. Opaque backplate +
 *  hairline ring keep it ≥3:1 against light/busy or dark photos in both themes. */
export function PhotoViewControl({
  photo,
  className,
}: {
  photo: ViewerPhoto;
  className?: string;
}) {
  const [open, setOpen] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
 
  const close = () => {
    setOpen(false);
    buttonRef.current?.focus(); // restore focus to the trigger
  };
 
  return (
    <>
      <button
        ref={buttonRef}
        type="button"
        aria-label="View photo"
        aria-haspopup="dialog"
        onClick={() => setOpen(true)}
        className={`inline-flex h-11 w-11 items-center justify-center rounded-full bg-glass-strong backdrop-blur-md text-ink ring-1 ring-hairline shadow-lift transition-colors hover:ring-primary focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-primary ${className ?? ""}`}
      >
        <svg aria-hidden viewBox="0 0 24 24" fill="none" className="h-5 w-5">
          <path
            d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"
            stroke="currentColor"
            strokeWidth="1.8"
            strokeLinecap="round"
            strokeLinejoin="round"
          />
        </svg>
      </button>
      {open && <ImageViewer photo={photo} onClose={close} />}
    </>
  );
}