refactor: swap Button ghost/outline semantics, clean up ImageLightbox thumbnail
ghost now means transparent bg (no fill); outline keeps cream bg with subtle border. Remove magnify icon overlay from ImageLightbox thumbnail — hover cursor-zoom-in is sufficient. Close button updated to variant="outline" for cream-on-blue contrast in the dialog.
This commit is contained in:
@@ -439,4 +439,5 @@
|
|||||||
/* Lightbox dialog backdrop */
|
/* Lightbox dialog backdrop */
|
||||||
dialog.lightbox::backdrop {
|
dialog.lightbox::backdrop {
|
||||||
background-color: rgba(4, 28, 243, 0.25);
|
background-color: rgba(4, 28, 243, 0.25);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ describe('Button', () => {
|
|||||||
});
|
});
|
||||||
it('applies outline variant', () => {
|
it('applies outline variant', () => {
|
||||||
render(<Button variant="outline">Go</Button>);
|
render(<Button variant="outline">Go</Button>);
|
||||||
expect(screen.getByRole('button')).toHaveClass('bg-transparent');
|
expect(screen.getByRole('button')).toHaveClass('bg-cream');
|
||||||
});
|
});
|
||||||
it('applies ghost variant', () => {
|
it('applies ghost variant', () => {
|
||||||
render(<Button variant="ghost">Go</Button>);
|
render(<Button variant="ghost">Go</Button>);
|
||||||
expect(screen.getByRole('button')).toHaveClass('bg-cream');
|
expect(screen.getByRole('button')).toHaveClass('bg-transparent');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('sizes', () => {
|
describe('sizes', () => {
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ const VARIANTS = {
|
|||||||
secondary:
|
secondary:
|
||||||
'brutal-border bg-blue text-cream shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-md active:translate-x-0.5 active:translate-y-0.5 active:shadow-brutal-xs',
|
'brutal-border bg-blue text-cream shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-md active:translate-x-0.5 active:translate-y-0.5 active:shadow-brutal-xs',
|
||||||
outline:
|
outline:
|
||||||
'brutal-border bg-transparent text-blue shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-md active:translate-x-0.5 active:translate-y-0.5 active:shadow-brutal-xs',
|
|
||||||
ghost:
|
|
||||||
'brutal-border border-blue/35 bg-cream text-blue hover:border-blue hover:bg-blue/10 active:bg-blue active:text-cream',
|
'brutal-border border-blue/35 bg-cream text-blue hover:border-blue hover:bg-blue/10 active:bg-blue active:text-cream',
|
||||||
|
ghost:
|
||||||
|
'brutal-border bg-transparent text-blue hover:-translate-x-0.5 hover:-translate-y-0.5 active:translate-x-0.5 active:translate-y-0.5',
|
||||||
} as const satisfies Record<ButtonVariant, string>;
|
} as const satisfies Record<ButtonVariant, string>;
|
||||||
|
|
||||||
const SIZES = {
|
const SIZES = {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ describe('ImageLightbox', () => {
|
|||||||
it('clicking inside the dialog (not backdrop) does not close', () => {
|
it('clicking inside the dialog (not backdrop) does not close', () => {
|
||||||
render(<ImageLightbox {...DEFAULT_PROPS} />);
|
render(<ImageLightbox {...DEFAULT_PROPS} />);
|
||||||
const dialog = document.querySelector('dialog') as HTMLDialogElement;
|
const dialog = document.querySelector('dialog') as HTMLDialogElement;
|
||||||
const inner = dialog.querySelector('div') as HTMLDivElement;
|
const inner = dialog.querySelector('img') as HTMLImageElement;
|
||||||
fireEvent.click(inner);
|
fireEvent.click(inner);
|
||||||
expect(HTMLDialogElement.prototype.close).not.toHaveBeenCalled();
|
expect(HTMLDialogElement.prototype.close).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { CloseIcon, MagnifyIcon } from '$shared/assets/icons';
|
import { CloseIcon } from '$shared/assets/icons';
|
||||||
import { cn } from '$shared/lib';
|
import { cn } from '$shared/lib';
|
||||||
import { Button } from '$shared/ui/Button';
|
import { Button } from '$shared/ui/Button';
|
||||||
|
|
||||||
@@ -66,10 +66,6 @@ export function ImageLightbox({ src, alt, className }: Props) {
|
|||||||
className={cn('relative block w-full aspect-video overflow-hidden cursor-zoom-in', className)}
|
className={cn('relative block w-full aspect-video overflow-hidden cursor-zoom-in', className)}
|
||||||
>
|
>
|
||||||
<Image src={src} alt={alt} fill className="object-cover" />
|
<Image src={src} alt={alt} fill className="object-cover" />
|
||||||
{/* Magnify hint — pointer-events-none so clicks pass through to the button */}
|
|
||||||
<span aria-hidden={true} className="absolute bottom-2 right-2 bg-cream text-blue p-1 pointer-events-none">
|
|
||||||
<MagnifyIcon />
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<dialog
|
<dialog
|
||||||
@@ -77,13 +73,18 @@ export function ImageLightbox({ src, alt, className }: Props) {
|
|||||||
aria-label={alt}
|
aria-label={alt}
|
||||||
onClick={handleBackdropClick}
|
onClick={handleBackdropClick}
|
||||||
onKeyUp={handleBackdropKeyUp}
|
onKeyUp={handleBackdropKeyUp}
|
||||||
className="lightbox relative bg-blue brutal-border shadow-brutal-xl p-0 max-w-5xl w-full"
|
className="lightbox fixed inset-0 m-auto relative bg-blue brutal-border p-0 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="relative aspect-video w-full">
|
{/* Native img so the dialog sizes to the image — next/image fill requires a pre-sized container */}
|
||||||
{/* aria-hidden: the dialog element itself carries the accessible label */}
|
{/* aria-hidden: the dialog element itself carries the accessible label */}
|
||||||
<Image src={src} alt={alt} fill className="object-contain" aria-hidden={true} />
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
</div>
|
<img
|
||||||
<Button variant="ghost" size="sm" onClick={close} aria-label="Close image" className="absolute top-3 right-3">
|
src={src}
|
||||||
|
alt={alt}
|
||||||
|
aria-hidden={true}
|
||||||
|
className="block max-w-[calc(100vw-2rem)] max-h-[calc(100vh-2rem)] w-auto h-auto"
|
||||||
|
/>
|
||||||
|
<Button variant="outline" size="sm" onClick={close} aria-label="Close image" className="absolute top-3 right-3">
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|||||||
Reference in New Issue
Block a user