diff --git a/src/shared/assets/icons/CloseIcon.tsx b/src/shared/assets/icons/CloseIcon.tsx new file mode 100644 index 0000000..722f9e5 --- /dev/null +++ b/src/shared/assets/icons/CloseIcon.tsx @@ -0,0 +1,30 @@ +type Props = { + /** + * CSS classes on the svg element + */ + className?: string; +}; + +/** + * Close / X icon (Lucide). + */ +export function CloseIcon({ className }: Props) { + return ( + + + + + ); +} diff --git a/src/shared/assets/icons/MagnifyIcon.tsx b/src/shared/assets/icons/MagnifyIcon.tsx new file mode 100644 index 0000000..d6197cc --- /dev/null +++ b/src/shared/assets/icons/MagnifyIcon.tsx @@ -0,0 +1,30 @@ +type Props = { + /** + * CSS classes on the svg element + */ + className?: string; +}; + +/** + * Magnify / search icon (Lucide). + */ +export function MagnifyIcon({ className }: Props) { + return ( + + + + + ); +} diff --git a/src/shared/assets/icons/index.ts b/src/shared/assets/icons/index.ts new file mode 100644 index 0000000..21698bf --- /dev/null +++ b/src/shared/assets/icons/index.ts @@ -0,0 +1,2 @@ +export { CloseIcon } from './CloseIcon'; +export { MagnifyIcon } from './MagnifyIcon'; diff --git a/src/shared/ui/ImageLightbox/ui/ImageLightbox.stories.tsx b/src/shared/ui/ImageLightbox/ui/ImageLightbox.stories.tsx new file mode 100644 index 0000000..8da395c --- /dev/null +++ b/src/shared/ui/ImageLightbox/ui/ImageLightbox.stories.tsx @@ -0,0 +1,25 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { ImageLightbox } from './ImageLightbox'; + +const meta: Meta = { + title: 'Shared/ImageLightbox', + component: ImageLightbox, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + src: 'https://picsum.photos/800/450', + alt: 'Sample project image', + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +}; diff --git a/src/shared/ui/ImageLightbox/ui/ImageLightbox.tsx b/src/shared/ui/ImageLightbox/ui/ImageLightbox.tsx index ba4bff9..bc92aff 100644 --- a/src/shared/ui/ImageLightbox/ui/ImageLightbox.tsx +++ b/src/shared/ui/ImageLightbox/ui/ImageLightbox.tsx @@ -2,7 +2,9 @@ import Image from 'next/image'; import { useRef } from 'react'; +import { CloseIcon, MagnifyIcon } from '$shared/assets/icons'; import { cn } from '$shared/lib'; +import { Button } from '$shared/ui/Button'; type Props = { /** @@ -33,6 +35,11 @@ export function ImageLightbox({ src, alt, className }: Props) { dialogRef.current?.close(); } + /** + * Closes the dialog when the user clicks the backdrop area directly. + * Comparing target to currentTarget distinguishes a click on the + * element itself (the backdrop) from a click on its content children. + */ function handleBackdropClick(e: React.MouseEvent) { if (e.target === e.currentTarget) { close(); @@ -59,6 +66,10 @@ export function ImageLightbox({ src, alt, className }: Props) { className={cn('relative block w-full aspect-video overflow-hidden cursor-zoom-in', className)} > {alt} + {/* Magnify hint — pointer-events-none so clicks pass through to the button */} + + +
{/* aria-hidden: the dialog element itself carries the accessible label */} {alt}
- +
);