[dyad] Refactored image converter - wrote 8 file(s)

This commit is contained in:
[dyad]
2026-01-18 12:52:56 +01:00
parent a64ce49523
commit 9ba9b13e21
8 changed files with 1168 additions and 826 deletions

View File

@@ -0,0 +1,187 @@
"use client";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { ObjectPositionControl } from "@/components/object-position-control";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { ArrowRightLeft, HelpCircle } from "lucide-react";
import { useTranslations } from "next-intl";
import { ScaleMode } from "@/hooks/use-image-converter";
interface ImageSettingsProps {
aspectRatio: string;
onAspectRatioChange: (value: string) => void;
width: number | string;
onWidthChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
height: number | string;
onHeightChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onSwapDimensions: () => void;
keepOrientation: boolean;
onKeepOrientationChange: (checked: boolean) => void;
scaleMode: ScaleMode;
onScaleModeChange: (value: ScaleMode) => void;
objectPosition: string;
onObjectPositionChange: (value: string) => void;
}
export function ImageSettings({
aspectRatio,
onAspectRatioChange,
width,
onWidthChange,
height,
onHeightChange,
onSwapDimensions,
keepOrientation,
onKeepOrientationChange,
scaleMode,
onScaleModeChange,
objectPosition,
onObjectPositionChange,
}: ImageSettingsProps) {
const t = useTranslations("ImageConverter");
const aspectRatios = [
{ name: t("customAspectRatio"), value: "custom" },
{ name: t("squareAspectRatio"), value: "1/1" },
{ name: t("standardAspectRatio"), value: "4/3" },
{ name: t("photoAspectRatio"), value: "3/2" },
{ name: t("widescreenAspectRatio"), value: "16/9" },
];
return (
<>
<div className="space-y-4">
<div>
<div className="flex items-center gap-1.5">
<Label htmlFor="aspect-ratio">{t("aspectRatioLabel")}</Label>
<Tooltip>
<TooltipTrigger>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("aspectRatioTooltip")}</p>
</TooltipContent>
</Tooltip>
</div>
<Select value={aspectRatio} onValueChange={onAspectRatioChange}>
<SelectTrigger id="aspect-ratio" className="mt-2">
<SelectValue placeholder={t("aspectRatioLabel")} />
</SelectTrigger>
<SelectContent>
{aspectRatios.map((ratio) => (
<SelectItem key={ratio.value} value={ratio.value}>
{ratio.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex items-end gap-2">
<div className="space-y-2 flex-1">
<div className="flex items-center gap-1.5">
<Label htmlFor="width">{t("widthLabel")}</Label>
<Tooltip>
<TooltipTrigger>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("widthTooltip")}</p>
</TooltipContent>
</Tooltip>
</div>
<Input id="width" type="number" placeholder={t("originalPlaceholder")} value={width} onChange={onWidthChange} />
</div>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" size="icon" onClick={onSwapDimensions} className="shrink-0" aria-label="Swap width and height">
<ArrowRightLeft className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{t("swapDimensionsTooltip")}</p>
</TooltipContent>
</Tooltip>
<div className="space-y-2 flex-1">
<div className="flex items-center gap-1.5">
<Label htmlFor="height">{t("heightLabel")}</Label>
<Tooltip>
<TooltipTrigger>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("heightTooltip")}</p>
</TooltipContent>
</Tooltip>
</div>
<Input id="height" type="number" placeholder={t("originalPlaceholder")} value={height} onChange={onHeightChange} />
</div>
</div>
<div className="flex items-center space-x-2 pt-2">
<Checkbox id="keep-orientation" checked={keepOrientation} onCheckedChange={(checked) => onKeepOrientationChange(Boolean(checked))} />
<Label htmlFor="keep-orientation" className="cursor-pointer flex items-center gap-1.5">
{t("keepOrientationLabel")}
<Tooltip>
<TooltipTrigger onClick={(e) => e.preventDefault()}>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("keepOrientationTooltip")}</p>
</TooltipContent>
</Tooltip>
</Label>
</div>
</div>
<div className="mt-4 space-y-2">
<div className="flex items-center gap-1.5">
<Label htmlFor="scale-mode">{t("scalingLabel")}</Label>
<Tooltip>
<TooltipTrigger>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("scalingTooltip")}</p>
</TooltipContent>
</Tooltip>
</div>
<Select value={scaleMode} onValueChange={(value: ScaleMode) => onScaleModeChange(value)}>
<SelectTrigger id="scale-mode"><SelectValue placeholder={t("scalingLabel")} /></SelectTrigger>
<SelectContent>
<SelectItem value="fill">{t("scalingFill")}</SelectItem>
<SelectItem value="cover">{t("scalingCover")}</SelectItem>
<SelectItem value="contain">{t("scalingContain")}</SelectItem>
</SelectContent>
</Select>
</div>
{scaleMode !== 'fill' && (
<div className="mt-4 space-y-2">
<div className="flex items-center gap-1.5">
<Label>{t("positionLabel")}</Label>
<Tooltip>
<TooltipTrigger>
<HelpCircle className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
<p>{t("positionTooltip")}</p>
</TooltipContent>
</Tooltip>
</div>
<ObjectPositionControl value={objectPosition} onChange={onObjectPositionChange} />
</div>
)}
</>
);
}