[dyad] Refactored image converter - wrote 8 file(s)
This commit is contained in:
187
src/components/image-converter/image-settings.tsx
Normal file
187
src/components/image-converter/image-settings.tsx
Normal 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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user