diff --git a/src/app/(tools)/rounded-border/page.tsx b/src/app/(tools)/rounded-border/page.tsx index 2e58f6d..08246b2 100644 --- a/src/app/(tools)/rounded-border/page.tsx +++ b/src/app/(tools)/rounded-border/page.tsx @@ -1,6 +1,4 @@ import { RoundedTool } from "./rounded-tool"; -import { FileDropzone } from "@/components/shared/file-dropzone"; -import { FileProvider } from "@/components/providers/file-provider"; export const metadata = { title: "Corner Rounder - QuickPic", @@ -8,14 +6,5 @@ export const metadata = { }; export default function RoundedToolPage() { - return ( - - - - - - ); + return ; } diff --git a/src/app/(tools)/rounded-border/rounded-tool.tsx b/src/app/(tools)/rounded-border/rounded-tool.tsx index 9b9747c..83d8eb5 100644 --- a/src/app/(tools)/rounded-border/rounded-tool.tsx +++ b/src/app/(tools)/rounded-border/rounded-tool.tsx @@ -1,14 +1,16 @@ "use client"; import { usePlausible } from "next-plausible"; -import { useMemo, useState, useEffect } from "react"; +import { useMemo, useState } from "react"; import { useLocalStorage } from "@/hooks/use-local-storage"; import React from "react"; import { UploadBox } from "@/components/shared/upload-box"; import { OptionSelector } from "@/components/shared/option-selector"; import { BorderRadiusSelector } from "@/components/border-radius-selector"; -import { useFileState } from "@/lib/file-context"; -import { createFileChangeEvent } from "@/lib/file-utils"; -import { useFileUploader } from "@/hooks/use-file-uploader"; +import { + useFileUploader, + type FileUploaderResult, +} from "@/hooks/use-file-uploader"; +import { FileDropzone } from "@/components/shared/file-dropzone"; type Radius = number; @@ -152,19 +154,9 @@ function SaveAsPngButton({ ); } -export function RoundedTool() { - const { currentFile } = useFileState(); - const { imageContent, imageMetadata, handleFileUpload, cancel } = - useFileUploader(); - - // Add effect to handle files from context - useEffect(() => { - if (currentFile) { - const event = createFileChangeEvent(currentFile); - handleFileUpload(event); - } - }, [currentFile, handleFileUpload]); - +function RoundedToolCore(props: { fileUploaderProps: FileUploaderResult }) { + const { imageContent, imageMetadata, handleFileUploadEvent, cancel } = + props.fileUploaderProps; const [radius, setRadius] = useLocalStorage("roundedTool_radius", 2); const [isCustomRadius, setIsCustomRadius] = useState(false); const [background, setBackground] = useLocalStorage( @@ -188,7 +180,7 @@ export function RoundedTool() { subtitle="Allows pasting images from clipboard" description="Upload Image" accept="image/*" - onChange={handleFileUpload} + onChange={handleFileUploadEvent} /> ); } @@ -249,3 +241,17 @@ export function RoundedTool() { ); } + +export function RoundedTool() { + const fileUploaderProps = useFileUploader(); + + return ( + + + + ); +} diff --git a/src/app/(tools)/square-image/page.tsx b/src/app/(tools)/square-image/page.tsx index d083337..7a695c8 100644 --- a/src/app/(tools)/square-image/page.tsx +++ b/src/app/(tools)/square-image/page.tsx @@ -1,6 +1,4 @@ import { SquareTool } from "./square-tool"; -import { FileDropzone } from "@/components/shared/file-dropzone"; -import { FileProvider } from "@/components/providers/file-provider"; export const metadata = { title: "Square Image Generator - QuickPic", @@ -9,14 +7,5 @@ export const metadata = { }; export default function SquareToolPage() { - return ( - - - - - - ); + return ; } diff --git a/src/app/(tools)/square-image/square-tool.tsx b/src/app/(tools)/square-image/square-tool.tsx index 90431fe..dbccc06 100644 --- a/src/app/(tools)/square-image/square-tool.tsx +++ b/src/app/(tools)/square-image/square-tool.tsx @@ -1,65 +1,58 @@ "use client"; -import React, { - useState, - useEffect, - type ChangeEvent, - useCallback, -} from "react"; import { usePlausible } from "next-plausible"; import { useLocalStorage } from "@/hooks/use-local-storage"; import { UploadBox } from "@/components/shared/upload-box"; import { OptionSelector } from "@/components/shared/option-selector"; -import { useClipboardPaste } from "@/hooks/use-clipboard-paste"; -import { useFileState } from "@/lib/file-context"; +import { FileDropzone } from "@/components/shared/file-dropzone"; +import { + type FileUploaderResult, + useFileUploader, +} from "@/hooks/use-file-uploader"; +import { useEffect, useState } from "react"; + +function SquareToolCore(props: { fileUploaderProps: FileUploaderResult }) { + const { imageContent, imageMetadata, handleFileUploadEvent, cancel } = + props.fileUploaderProps; -export const SquareTool: React.FC = () => { - const { currentFile } = useFileState(); - const [imageFile, setImageFile] = useState(null); const [backgroundColor, setBackgroundColor] = useLocalStorage< "black" | "white" >("squareTool_backgroundColor", "white"); - const [previewUrl, setPreviewUrl] = useState(null); - const [canvasDataUrl, setCanvasDataUrl] = useState(null); - const [imageMetadata, setImageMetadata] = useState<{ - width: number; - height: number; - name: string; - } | null>(null); - const plausible = usePlausible(); - - const processFile = (file: File) => { - setImageFile(file); - setImageMetadata({ width: 0, height: 0, name: file.name }); - }; - - const handleImageUpload = (event: ChangeEvent) => { - const file = event.target.files?.[0]; - if (file) { - processFile(file); - } - }; - - const handleFilePaste = useCallback((file: File) => { - processFile(file); - }, []); + const [squareImageContent, setSquareImageContent] = useState( + null, + ); useEffect(() => { - if (currentFile) { - processFile(currentFile); + if (imageContent && imageMetadata) { + const canvas = document.createElement("canvas"); + const size = Math.max(imageMetadata.width, imageMetadata.height); + canvas.width = size; + canvas.height = size; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + // Fill background + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, size, size); + + // Load and center the image + const img = new Image(); + img.onload = () => { + const x = (size - imageMetadata.width) / 2; + const y = (size - imageMetadata.height) / 2; + ctx.drawImage(img, x, y); + setSquareImageContent(canvas.toDataURL("image/png")); + }; + img.src = imageContent; } - }, [currentFile]); - - useClipboardPaste({ - onPaste: handleFilePaste, - acceptedFileTypes: ["image/*", ".jpg", ".jpeg", ".png", ".webp"], - }); + }, [imageContent, imageMetadata, backgroundColor]); const handleSaveImage = () => { - if (canvasDataUrl && imageMetadata) { + if (squareImageContent && imageMetadata) { const link = document.createElement("a"); - link.href = canvasDataUrl; + link.href = squareImageContent; const originalFileName = imageMetadata.name; const fileNameWithoutExtension = originalFileName.substring(0, originalFileName.lastIndexOf(".")) || @@ -71,66 +64,7 @@ export const SquareTool: React.FC = () => { } }; - useEffect(() => { - if (imageFile) { - const reader = new FileReader(); - reader.onload = () => { - const img = new Image(); - img.onload = () => { - const maxDim = Math.max(img.width, img.height); - setImageMetadata((prevState) => ({ - ...prevState!, - width: img.width, - height: img.height, - })); - - const canvas = document.createElement("canvas"); - canvas.width = maxDim; - canvas.height = maxDim; - const ctx = canvas.getContext("2d"); - if (ctx) { - ctx.fillStyle = backgroundColor; - ctx.fillRect(0, 0, canvas.width, canvas.height); - const x = (maxDim - img.width) / 2; - const y = (maxDim - img.height) / 2; - ctx.drawImage(img, x, y); - const dataUrl = canvas.toDataURL("image/png"); - setCanvasDataUrl(dataUrl); - - // Create a smaller canvas for the preview - const previewCanvas = document.createElement("canvas"); - const previewSize = 200; // Set desired preview size - previewCanvas.width = previewSize; - previewCanvas.height = previewSize; - const previewCtx = previewCanvas.getContext("2d"); - if (previewCtx) { - previewCtx.drawImage( - canvas, - 0, - 0, - canvas.width, - canvas.height, - 0, - 0, - previewSize, - previewSize, - ); - const previewDataUrl = previewCanvas.toDataURL("image/png"); - setPreviewUrl(previewDataUrl); - } - } - }; - if (typeof reader.result === "string") { - img.src = reader.result; - } - }; - reader.readAsDataURL(imageFile); - } else { - setPreviewUrl(null); - setCanvasDataUrl(null); - setImageMetadata(null); - } - }, [imageFile, backgroundColor]); + const plausible = usePlausible(); if (!imageMetadata) { return ( @@ -139,7 +73,7 @@ export const SquareTool: React.FC = () => { subtitle="Allows pasting images from clipboard" description="Upload Image" accept="image/*" - onChange={handleImageUpload} + onChange={handleFileUploadEvent} /> ); } @@ -147,7 +81,9 @@ export const SquareTool: React.FC = () => { return (
- {previewUrl && Preview} + {squareImageContent && ( + Preview + )}

{imageMetadata.name}

@@ -182,12 +118,7 @@ export const SquareTool: React.FC = () => {
); +} + +export const SquareTool: React.FC = () => { + const fileUploaderProps = useFileUploader(); + + return ( + + + + ); };