Skip to content

Commit

Permalink
refactor other tools
Browse files Browse the repository at this point in the history
  • Loading branch information
t3dotgg committed Nov 11, 2024
1 parent ae364e4 commit 0c512ba
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 155 deletions.
13 changes: 1 addition & 12 deletions src/app/(tools)/rounded-border/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
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",
description: "Round corners on an image (for free because duh)",
};

export default function RoundedToolPage() {
return (
<FileProvider>
<FileDropzone
acceptedFileTypes={["image/*", ".jpg", ".jpeg", ".png", ".webp"]}
dropText="Drop image file"
>
<RoundedTool />
</FileDropzone>
</FileProvider>
);
return <RoundedTool />;
}
42 changes: 24 additions & 18 deletions src/app/(tools)/rounded-border/rounded-tool.tsx
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<Radius>("roundedTool_radius", 2);
const [isCustomRadius, setIsCustomRadius] = useState(false);
const [background, setBackground] = useLocalStorage<BackgroundOption>(
Expand All @@ -188,7 +180,7 @@ export function RoundedTool() {
subtitle="Allows pasting images from clipboard"
description="Upload Image"
accept="image/*"
onChange={handleFileUpload}
onChange={handleFileUploadEvent}
/>
);
}
Expand Down Expand Up @@ -249,3 +241,17 @@ export function RoundedTool() {
</div>
);
}

export function RoundedTool() {
const fileUploaderProps = useFileUploader();

return (
<FileDropzone
setCurrentFile={fileUploaderProps.handleFileUpload}
acceptedFileTypes={["image/*", ".jpg", ".jpeg", ".png", ".webp"]}
dropText="Drop image file"
>
<RoundedToolCore fileUploaderProps={fileUploaderProps} />
</FileDropzone>
);
}
13 changes: 1 addition & 12 deletions src/app/(tools)/square-image/page.tsx
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -9,14 +7,5 @@ export const metadata = {
};

export default function SquareToolPage() {
return (
<FileProvider>
<FileDropzone
acceptedFileTypes={["image/*", ".jpg", ".jpeg", ".png", ".webp"]}
dropText="Drop image file"
>
<SquareTool />
</FileDropzone>
</FileProvider>
);
return <SquareTool />;
}
171 changes: 58 additions & 113 deletions src/app/(tools)/square-image/square-tool.tsx
Original file line number Diff line number Diff line change
@@ -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<File | null>(null);
const [backgroundColor, setBackgroundColor] = useLocalStorage<
"black" | "white"
>("squareTool_backgroundColor", "white");

const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [canvasDataUrl, setCanvasDataUrl] = useState<string | null>(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<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
processFile(file);
}
};

const handleFilePaste = useCallback((file: File) => {
processFile(file);
}, []);
const [squareImageContent, setSquareImageContent] = useState<string | null>(
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(".")) ||
Expand All @@ -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 (
Expand All @@ -139,15 +73,17 @@ export const SquareTool: React.FC = () => {
subtitle="Allows pasting images from clipboard"
description="Upload Image"
accept="image/*"
onChange={handleImageUpload}
onChange={handleFileUploadEvent}
/>
);
}

return (
<div className="mx-auto flex max-w-2xl flex-col items-center justify-center gap-6 p-6">
<div className="flex w-full flex-col items-center gap-4 rounded-xl p-6">
{previewUrl && <img src={previewUrl} alt="Preview" className="mb-4" />}
{squareImageContent && (
<img src={squareImageContent} alt="Preview" className="mb-4" />
)}
<p className="text-lg font-medium text-white/80">
{imageMetadata.name}
</p>
Expand Down Expand Up @@ -182,12 +118,7 @@ export const SquareTool: React.FC = () => {

<div className="flex gap-3">
<button
onClick={() => {
setImageFile(null);
setPreviewUrl(null);
setCanvasDataUrl(null);
setImageMetadata(null);
}}
onClick={cancel}
className="rounded-lg bg-red-700 px-4 py-2 text-sm font-medium text-white/90 transition-colors hover:bg-red-800"
>
Cancel
Expand All @@ -204,4 +135,18 @@ export const SquareTool: React.FC = () => {
</div>
</div>
);
}

export const SquareTool: React.FC = () => {
const fileUploaderProps = useFileUploader();

return (
<FileDropzone
setCurrentFile={fileUploaderProps.handleFileUpload}
acceptedFileTypes={["image/*", ".jpg", ".jpeg", ".png", ".webp"]}
dropText="Drop image file"
>
<SquareToolCore fileUploaderProps={fileUploaderProps} />
</FileDropzone>
);
};

0 comments on commit 0c512ba

Please sign in to comment.