diff --git a/src/app/(tools)/svg-to-png/svg-tool.tsx b/src/app/(tools)/svg-to-png/svg-tool.tsx index 137d778..541e1a5 100644 --- a/src/app/(tools)/svg-to-png/svg-tool.tsx +++ b/src/app/(tools)/svg-to-png/svg-tool.tsx @@ -5,9 +5,12 @@ import { useLocalStorage } from "@/hooks/use-local-storage"; import { UploadBox } from "@/components/shared/upload-box"; import { SVGScaleSelector } from "@/components/svg-scale-selector"; +import { OptionSelector } from "@/components/option-selector"; export type Scale = "custom" | number; +type ResolutionMode = "scale" | "dimensions"; + function scaleSvg(svgContent: string, scale: number) { const parser = new DOMParser(); const svgDoc = parser.parseFromString(svgContent, "image/svg+xml"); @@ -141,15 +144,44 @@ function SVGToolCore(props: { fileUploaderProps: FileUploaderResult }) { const { rawContent, imageMetadata, handleFileUploadEvent, cancel } = props.fileUploaderProps; + const [resolutionMode, setResolutionMode] = useLocalStorage( + "svgTool_resolutionMode", + "scale" + ); const [scale, setScale] = useLocalStorage("svgTool_scale", 1); const [customScale, setCustomScale] = useLocalStorage( "svgTool_customScale", - 1, + 1 + ); + const [customWidth, setCustomWidth] = useLocalStorage( + "svgTool_customWidth", + imageMetadata?.width ?? 0 + ); + const [customHeight, setCustomHeight] = useLocalStorage( + "svgTool_customHeight", + imageMetadata?.height ?? 0 ); // Get the actual numeric scale value const effectiveScale = scale === "custom" ? customScale : scale; + // Calculate dimensions based on mode + const finalDimensions = useMemo(() => { + if (!imageMetadata) return { width: 0, height: 0 }; + + if (resolutionMode === "scale") { + return { + width: imageMetadata.width * effectiveScale, + height: imageMetadata.height * effectiveScale, + }; + } else { + return { + width: customWidth, + height: customHeight, + }; + } + }, [imageMetadata, resolutionMode, effectiveScale, customWidth, customHeight]); + if (!imageMetadata) return ( -

- {imageMetadata.name} -

+

{imageMetadata.name}

{/* Size Information */} @@ -180,24 +210,57 @@ function SVGToolCore(props: { fileUploaderProps: FileUploaderResult }) {
- Scaled + Output - {imageMetadata.width * effectiveScale} ×{" "} - {imageMetadata.height * effectiveScale} + {Math.round(finalDimensions.width)} × {Math.round(finalDimensions.height)}
- {/* Scale Controls */} - + option === "scale" ? "Scale Factor" : "Custom Dimensions" + } /> + {/* Scale Controls */} + {resolutionMode === "scale" ? ( + + ) : ( +
+ Dimensions (px) +
+ setCustomWidth(Math.max(1, parseInt(e.target.value) || 0))} + className="w-24 rounded-lg bg-white/5 px-3 py-1.5 text-sm text-white" + placeholder="Width" + /> + × + setCustomHeight(Math.max(1, parseInt(e.target.value) || 0))} + className="w-24 rounded-lg bg-white/5 px-3 py-1.5 text-sm text-white" + placeholder="Height" + /> +
+
+ )} + {/* Action Buttons */}
diff --git a/src/components/option-selector.tsx b/src/components/option-selector.tsx new file mode 100644 index 0000000..157f617 --- /dev/null +++ b/src/components/option-selector.tsx @@ -0,0 +1,66 @@ +import { useEffect, useRef } from "react"; + +interface OptionSelectorProps { + title: string; + options: T[]; + selected: T; + onChange: (option: T) => void; + formatOption?: (option: T) => string; +} + +export function OptionSelector({ + title, + options, + selected, + onChange, + formatOption = (option) => `${option}`, +}: OptionSelectorProps) { + const containerRef = useRef(null); + const selectedRef = useRef(null); + const highlightRef = useRef(null); + + useEffect(() => { + if (selectedRef.current && highlightRef.current && containerRef.current) { + const container = containerRef.current; + const selected = selectedRef.current; + const highlight = highlightRef.current; + + const containerRect = container.getBoundingClientRect(); + const selectedRect = selected.getBoundingClientRect(); + + highlight.style.left = `${selectedRect.left - containerRect.left}px`; + highlight.style.width = `${selectedRect.width}px`; + } + }, [selected]); + + return ( +
+ {title} +
+
+
+ {options.map((option) => ( + + ))} +
+
+
+ ); +} \ No newline at end of file