'use client'; /** * ImageToolbar - Floating toolbar for image controls */ import { useMemo, type ReactNode } from 'react'; import { ZoomIn, ZoomOut, RotateCw, FlipHorizontal, FlipVertical, Maximize2, Expand } from 'lucide-react'; import { useControls } from 'react-zoom-pan-pinch'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Tooltip, TooltipContent, TooltipTrigger, } from '@djangocfg/ui-core/components'; import { useAppT } from '@djangocfg/i18n'; import { cn } from '@djangocfg/ui-core/lib'; import { ZOOM_PRESETS } from '../utils'; import type { ImageToolbarProps } from '../types'; // ============================================================================= // COMPONENT // ============================================================================= // The toolbar floats over the image, whose brightness is unknown and // unrelated to the host theme. A theme-bound `bg-background` surface // would clash with a dark photo (white slab) or a light photo in dark // mode. A fixed dark-glass overlay with light icons stays readable on // any content — the same model the gallery nav arrows and media // players use. const TB_BUTTON = 'inline-flex items-center justify-center rounded-md text-white/90 ' + 'transition-colors hover:bg-white/15 hover:text-white ' + 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 ' + 'disabled:opacity-40 disabled:pointer-events-none'; // Small helper so each icon button shares the same Tooltip wrapper + // accessibility shape (visible tooltip on hover/focus, aria-label for AT). function TbIconButton({ label, onClick, className, children, }: { label: string; onClick: () => void; className?: string; children: ReactNode; }) { return ( {label} ); } export function ImageToolbar({ scale, transform, onRotate, onFlipH, onFlipV, onZoomPreset, onExpand, }: ImageToolbarProps) { const t = useAppT(); const { zoomIn, zoomOut, resetTransform } = useControls(); const labels = useMemo(() => ({ zoomIn: t('tools.image.zoomIn'), zoomOut: t('tools.image.zoomOut'), fitToView: t('tools.image.fitToView'), flipHorizontal: t('tools.image.flipHorizontal'), flipVertical: t('tools.image.flipVertical'), rotate: t('tools.image.rotate'), fullscreen: t('tools.image.fullscreen'), }), [t]); const zoomLabel = useMemo(() => { const percent = Math.round(scale * 100); return `${percent}%`; }, [scale]); return (
{/* Zoom controls */} zoomOut()}> {ZOOM_PRESETS.map((preset) => ( onZoomPreset(preset.value)} className="text-xs justify-center" > {preset.label} ))} zoomIn()}>
{/* Fit to view */} resetTransform()}>
{/* Transform controls */} {transform.rotation !== 0 && ( {transform.rotation}° )} {onExpand && ( <>
)}
); }