diff --git a/src/app/(tools)/rounded-border/rounded-tool.tsx b/src/app/(tools)/rounded-border/rounded-tool.tsx index 8c85dc4..8b828da 100644 --- a/src/app/(tools)/rounded-border/rounded-tool.tsx +++ b/src/app/(tools)/rounded-border/rounded-tool.tsx @@ -4,6 +4,7 @@ import { useMemo, useState } from "react"; import type { ChangeEvent } from "react"; import { useLocalStorage } from "@/hooks/use-local-storage"; import React from "react"; +import FilenameDisplay from "@/components/file-name-display"; type Radius = 2 | 4 | 8 | 16 | 32 | 64; @@ -71,7 +72,6 @@ function useImageConverter(props: { export const useFileUploader = () => { const [imageContent, setImageContent] = useState(""); - const [imageMetadata, setImageMetadata] = useState<{ width: number; height: number; @@ -99,12 +99,26 @@ export const useFileUploader = () => { } }; + const updateImageMetadata = ( + newMetadata: Partial<{ width: number; height: number; name: string }>, + ) => { + setImageMetadata((prevMetadata) => + prevMetadata ? { ...prevMetadata, ...newMetadata } : null, + ); + }; + const cancel = () => { setImageContent(""); setImageMetadata(null); }; - return { imageContent, imageMetadata, handleFileUpload, cancel }; + return { + imageContent, + imageMetadata, + handleFileUpload, + cancel, + updateImageMetadata, + }; }; interface ImageRendererProps { @@ -186,8 +200,13 @@ function SaveAsPngButton({ } export function RoundedTool() { - const { imageContent, imageMetadata, handleFileUpload, cancel } = - useFileUploader(); + const { + imageContent, + imageMetadata, + updateImageMetadata, + handleFileUpload, + cancel, + } = useFileUploader(); const [radius, setRadius] = useLocalStorage("roundedTool_radius", 2); const [background, setBackground] = useLocalStorage( @@ -195,6 +214,13 @@ export function RoundedTool() { "transparent", ); + function updateFileName(newName: string) { + if (imageMetadata) { + const newMetadata = { ...imageMetadata, name: newName }; + updateImageMetadata(newMetadata); + } + } + if (!imageMetadata) return (
@@ -220,7 +246,10 @@ export function RoundedTool() { radius={radius} background={background} /> -

{imageMetadata.name}

+ updateFileName(newName)} + />

Original size: {imageMetadata.width}px x {imageMetadata.height}px

diff --git a/src/app/(tools)/square-image/square-tool.tsx b/src/app/(tools)/square-image/square-tool.tsx index 07832e0..7083a0c 100644 --- a/src/app/(tools)/square-image/square-tool.tsx +++ b/src/app/(tools)/square-image/square-tool.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect, type ChangeEvent } from "react"; import { usePlausible } from "next-plausible"; import { useLocalStorage } from "@/hooks/use-local-storage"; +import FilenameDisplay from "@/components/file-name-display"; export const SquareTool: React.FC = () => { const [imageFile, setImageFile] = useState(null); @@ -110,6 +111,13 @@ export const SquareTool: React.FC = () => { } }, [imageFile, backgroundColor]); + function updateFileName(newName: string) { + if (imageMetadata) { + const newMetadata = { ...imageMetadata, name: newName }; + setImageMetadata(newMetadata); + } + } + if (!imageMetadata) { return (
@@ -134,7 +142,10 @@ export const SquareTool: React.FC = () => { return (
{previewUrl && Preview} -

{imageMetadata.name}

+ updateFileName(newName)} + />

Original size: {imageMetadata.width}px x {imageMetadata.height}px

diff --git a/src/app/(tools)/svg-to-png/svg-tool.tsx b/src/app/(tools)/svg-to-png/svg-tool.tsx index eb9232c..7c01203 100644 --- a/src/app/(tools)/svg-to-png/svg-tool.tsx +++ b/src/app/(tools)/svg-to-png/svg-tool.tsx @@ -104,15 +104,30 @@ export const useFileUploader = () => { } }; + const updateImageMetadata = ( + newMetadata: Partial<{ width: number; height: number; name: string }>, + ) => { + setImageMetadata((prevMetadata) => + prevMetadata ? { ...prevMetadata, ...newMetadata } : null, + ); + }; + const cancel = () => { setSvgContent(""); setImageMetadata(null); }; - return { svgContent, imageMetadata, handleFileUpload, cancel }; + return { + svgContent, + imageMetadata, + updateImageMetadata, + handleFileUpload, + cancel, + }; }; import React from "react"; +import FilenameDisplay from "@/components/file-name-display"; interface SVGRendererProps { svgContent: string; @@ -173,11 +188,23 @@ function SaveAsPngButton({ } export function SVGTool() { - const { svgContent, imageMetadata, handleFileUpload, cancel } = - useFileUploader(); + const { + svgContent, + imageMetadata, + updateImageMetadata, + handleFileUpload, + cancel, + } = useFileUploader(); const [scale, setScale] = useLocalStorage("svgTool_scale", 1); + function updateFileName(newName: string) { + if (imageMetadata) { + const newMetadata = { ...imageMetadata, name: newName }; + updateImageMetadata(newMetadata); + } + } + if (!imageMetadata) return (
@@ -201,7 +228,10 @@ export function SVGTool() { return (
-

{imageMetadata.name}

+ updateFileName(newName)} + />

Original size: {imageMetadata.width}px x {imageMetadata.height}px

diff --git a/src/components/file-name-display.tsx b/src/components/file-name-display.tsx new file mode 100644 index 0000000..5002eae --- /dev/null +++ b/src/components/file-name-display.tsx @@ -0,0 +1,66 @@ +import { useState } from "react"; + +function FilenameDisplay({ + initialName, + onSave, +}: { + initialName: string; + onSave: (name: string) => void; +}) { + const fileNameWithoutExtension = initialName.replace(/\.[^/.]+$/, ""); + const fileExtension = initialName.split(".").pop() ?? ""; + + const [isEditing, setIsEditing] = useState(false); + const [tempName, setTempName] = useState(fileNameWithoutExtension); + + const handleSave = () => { + const updatedName = `${tempName}.${fileExtension}`; + setIsEditing(false); + onSave(updatedName); + }; + + const handleCancel = () => { + setIsEditing(false); + setTempName(fileNameWithoutExtension); + }; + + return ( +
+ {isEditing ? ( +
+ setTempName(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleSave()} + className="rounded border border-gray-300 px-2 py-1 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" + /> + + +
+ ) : ( +
+ Name: + setIsEditing(true)} + className="underline-dashed underline hover:bg-gray-800" + > + {initialName} + +
+ )} +
+ ); +} + +export default FilenameDisplay;