Skip to content

Commit

Permalink
fix: Re-Implementation for t3dotgg#23
Browse files Browse the repository at this point in the history
  • Loading branch information
philipbrembeck committed Nov 10, 2024
1 parent 94289d3 commit 74c3167
Show file tree
Hide file tree
Showing 4 changed files with 387 additions and 312 deletions.
225 changes: 110 additions & 115 deletions src/app/(tools)/rounded-border/rounded-tool.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"use client";
import { usePlausible } from "next-plausible";
import { useMemo, useState } from "react";
import type { ChangeEvent } from "react";
import { useLocalStorage } from "@/hooks/use-local-storage";
import React from "react";
import { useFileUpload } from "@/app/hooks/useFileUpload";

type Radius = 2 | 4 | 8 | 16 | 32 | 64;

type BackgroundOption = "white" | "black" | "transparent";

function useImageConverter(props: {
Expand Down Expand Up @@ -69,44 +68,6 @@ function useImageConverter(props: {
};
}

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

const [imageMetadata, setImageMetadata] = useState<{
width: number;
height: number;
name: string;
} | null>(null);

const handleFileUpload = (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result as string;
const img = new Image();
img.onload = () => {
setImageMetadata({
width: img.width,
height: img.height,
name: file.name,
});
setImageContent(content);
};
img.src = content;
};
reader.readAsDataURL(file);
}
};

const cancel = () => {
setImageContent("");
setImageMetadata(null);
};

return { imageContent, imageMetadata, handleFileUpload, cancel };
};

interface ImageRendererProps {
imageContent: string;
radius: Radius;
Expand Down Expand Up @@ -186,90 +147,124 @@ function SaveAsPngButton({
}

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

const [imageContent, setImageContent] = useState<string>("");
const [imageMetadata, setImageMetadata] = useState<{
width: number;
height: number;
name: string;
} | null>(null);
const [radius, setRadius] = useLocalStorage<Radius>("roundedTool_radius", 2);
const [background, setBackground] = useLocalStorage<BackgroundOption>(
"roundedTool_background",
"transparent",
);

if (!imageMetadata)
return (
const processImage = (file: File) => {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result as string;
const img = new Image();
img.onload = () => {
setImageMetadata({
width: img.width,
height: img.height,
name: file.name,
});
setImageContent(content);
};
img.src = content;
};
reader.readAsDataURL(file);
};

const { handleFileUpload } = useFileUpload({
onFileProcess: processImage,
acceptedTypes: "image/*"
});

const handleCancel = () => {
setImageContent("");
setImageMetadata(null);
};

return (
<>
<div className="flex flex-col gap-4 p-4">
<p className="text-center">Round the corners of any image</p>
<div className="flex justify-center">
<label className="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white shadow-md transition-colors duration-200 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-75">
<span>Upload Image</span>
<input
type="file"
onChange={handleFileUpload}
accept="image/*"
className="hidden"
{!imageMetadata ? (
<>
<div className="flex justify-center">
<label className="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white shadow-md transition-colors duration-200 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-75">
<span>Upload Image</span>
<input
type="file"
onChange={handleFileUpload}
accept="image/*"
className="hidden"
/>
</label>
</div>
</>
) : (
<div className="flex flex-col items-center justify-center gap-4 text-2xl">
<ImageRenderer
imageContent={imageContent}
radius={radius}
background={background}
/>
</label>
</div>
</div>
);

return (
<div className="flex flex-col items-center justify-center gap-4 p-4 text-2xl">
<ImageRenderer
imageContent={imageContent}
radius={radius}
background={background}
/>
<p>{imageMetadata.name}</p>
<p>
Original size: {imageMetadata.width}px x {imageMetadata.height}px
</p>
<div className="flex gap-2">
{([2, 4, 8, 16, 32, 64] as Radius[]).map((value) => (
<button
key={value}
onClick={() => setRadius(value)}
className={`rounded-md px-3 py-1 text-sm font-medium transition-colors ${
radius === value
? "bg-green-600 text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300"
}`}
>
{value}px
</button>
))}
</div>
<div className="flex gap-2">
{(["white", "black", "transparent"] as BackgroundOption[]).map(
(option) => (
<button
key={option}
onClick={() => setBackground(option)}
className={`rounded-md px-3 py-1 text-sm font-medium transition-colors ${
background === option
? "bg-purple-600 text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300"
}`}
>
{option.charAt(0).toUpperCase() + option.slice(1)}
</button>
),
<p>{imageMetadata.name}</p>
<p>
Original size: {imageMetadata.width}px x {imageMetadata.height}px
</p>
<div className="flex gap-2">
{([2, 4, 8, 16, 32, 64] as Radius[]).map((value) => (
<button
key={value}
onClick={() => setRadius(value)}
className={`rounded-md px-3 py-1 text-sm font-medium transition-colors ${
radius === value
? "bg-green-600 text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300"
}`}
>
{value}px
</button>
))}
</div>
<div className="flex gap-2">
{(["white", "black", "transparent"] as BackgroundOption[]).map(
(option) => (
<button
key={option}
onClick={() => setBackground(option)}
className={`rounded-md px-3 py-1 text-sm font-medium transition-colors ${
background === option
? "bg-purple-600 text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300"
}`}
>
{option.charAt(0).toUpperCase() + option.slice(1)}
</button>
),
)}
</div>
<div className="flex gap-2">
<SaveAsPngButton
imageContent={imageContent}
radius={radius}
background={background}
imageMetadata={imageMetadata}
/>
<button
onClick={handleCancel}
className="rounded-md bg-red-700 px-3 py-1 text-sm font-medium text-white transition-colors hover:bg-red-800"
>
Cancel
</button>
</div>
</div>
)}
</div>
<div className="flex gap-2">
<SaveAsPngButton
imageContent={imageContent}
radius={radius}
background={background}
imageMetadata={imageMetadata}
/>
<button
onClick={cancel}
className="rounded-md bg-red-700 px-3 py-1 text-sm font-medium text-white transition-colors hover:bg-red-800"
>
Cancel
</button>
</div>
</div>
</>
);
}
}
Loading

0 comments on commit 74c3167

Please sign in to comment.