Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions src/app/(tools)/rounded-border/rounded-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -71,7 +72,6 @@ function useImageConverter(props: {

export const useFileUploader = () => {
const [imageContent, setImageContent] = useState<string>("");

const [imageMetadata, setImageMetadata] = useState<{
width: number;
height: number;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -186,15 +200,27 @@ function SaveAsPngButton({
}

export function RoundedTool() {
const { imageContent, imageMetadata, handleFileUpload, cancel } =
useFileUploader();
const {
imageContent,
imageMetadata,
updateImageMetadata,
handleFileUpload,
cancel,
} = useFileUploader();

const [radius, setRadius] = useLocalStorage<Radius>("roundedTool_radius", 2);
const [background, setBackground] = useLocalStorage<BackgroundOption>(
"roundedTool_background",
"transparent",
);

function updateFileName(newName: string) {
if (imageMetadata) {
const newMetadata = { ...imageMetadata, name: newName };
updateImageMetadata(newMetadata);
}
}

if (!imageMetadata)
return (
<div className="flex flex-col gap-4 p-4">
Expand All @@ -220,7 +246,10 @@ export function RoundedTool() {
radius={radius}
background={background}
/>
<p>{imageMetadata.name}</p>
<FilenameDisplay
initialName={imageMetadata.name}
onSave={(newName) => updateFileName(newName)}
/>
<p>
Original size: {imageMetadata.width}px x {imageMetadata.height}px
</p>
Expand Down
13 changes: 12 additions & 1 deletion src/app/(tools)/square-image/square-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<File | null>(null);
Expand Down Expand Up @@ -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 (
<div className="flex flex-col gap-4 p-4">
Expand All @@ -134,7 +142,10 @@ export const SquareTool: React.FC = () => {
return (
<div className="flex flex-col items-center justify-center gap-4 p-4 text-2xl">
{previewUrl && <img src={previewUrl} alt="Preview" className="mb-4" />}
<p>{imageMetadata.name}</p>
<FilenameDisplay
initialName={imageMetadata.name}
onSave={(newName) => updateFileName(newName)}
/>
<p>
Original size: {imageMetadata.width}px x {imageMetadata.height}px
</p>
Expand Down
38 changes: 34 additions & 4 deletions src/app/(tools)/svg-to-png/svg-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Scale>("svgTool_scale", 1);

function updateFileName(newName: string) {
if (imageMetadata) {
const newMetadata = { ...imageMetadata, name: newName };
updateImageMetadata(newMetadata);
}
}

if (!imageMetadata)
return (
<div className="flex flex-col gap-4 p-4">
Expand All @@ -201,7 +228,10 @@ export function SVGTool() {
return (
<div className="flex flex-col items-center justify-center gap-4 p-4 text-2xl">
<SVGRenderer svgContent={svgContent} />
<p>{imageMetadata.name}</p>
<FilenameDisplay
initialName={imageMetadata.name}
onSave={(newName) => updateFileName(newName)}
/>
<p>
Original size: {imageMetadata.width}px x {imageMetadata.height}px
</p>
Expand Down
66 changes: 66 additions & 0 deletions src/components/file-name-display.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex items-center space-x-2">
{isEditing ? (
<div className="flex items-center space-x-2">
<input
type="text"
value={tempName}
onChange={(e) => 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"
/>
<button
onClick={handleSave}
className="rounded bg-blue-500 px-2 py-1 text-sm font-medium text-white hover:bg-blue-600"
>
Save
</button>
<button
onClick={handleCancel}
className="rounded bg-gray-200 px-2 py-1 text-sm font-medium text-gray-600 hover:bg-gray-300"
>
Cancel
</button>
</div>
) : (
<div className="flex cursor-pointer items-center space-x-1 rounded px-2 py-1">
<span>Name: </span>
<span
onClick={() => setIsEditing(true)}
className="underline-dashed underline hover:bg-gray-800"
>
{initialName}
</span>
</div>
)}
</div>
);
}

export default FilenameDisplay;