Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(synapse-interface): Added /returntomonke pfp generator #2460

Merged
merged 7 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
134 changes: 134 additions & 0 deletions packages/synapse-interface/pages/returntomonke/ImageUploader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import _ from 'lodash'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think lodash used in this file

bigboydiamonds marked this conversation as resolved.
Show resolved Hide resolved
import { useState, useRef, useEffect } from 'react'
import Button from '@tw/Button'

export default function ImageUploader() {
const [uploadedImage, setUploadedImage] = useState(null);
const [processedImage, setProcessedImage] = useState(null);

const fileInput = useRef(null);
const imgRef = useRef(null);

useEffect(() => {
if (uploadedImage) {
applyImageOverlay();
}
}, [uploadedImage]);

function handleFile(file) {
setUploadedImage(file);
}

function handleDragOver(event) {
event.preventDefault();
}

function handleOnDrop(event) {
event.preventDefault();
event.stopPropagation();
handleFile(event.dataTransfer.files[0]);
console.log('File drop was a success');
}

const applyImageOverlay = () => {
const canvas = imgRef.current;
const ctx = canvas.getContext('2d');

// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Load the uploaded image
const img = new Image();
img.src = URL.createObjectURL(uploadedImage);
img.onload = () => {
// Set the canvas size to match the uploaded image
canvas.width = img.width;
Copy link
Collaborator

@bigboydiamonds bigboydiamonds Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently uploading an image that doesn't have equal image width and height will cause for the PFP to distort (see screenshot attached below)

To fix this to always create a square PFP output, we could set the canvas.width and canvas.height equal to each other.

As an example, updated the applyImageOverlay() function to achieve that effect: https://github.com/synapsecns/sanguine/pull/2465/files#diff-1f5949bc4b332bdd1d21bc1fccf989474ccf9b40c36d9b78bbae84a5f7a89b71R44-R50

Given that an uploaded image could differ in height or width, chose to set both canvas.width and canvas.height to whichever was greater, image.width or image.height so that we could always generate a square PFP output image.

Can test out here: https://fe-center-synape-pf.sanguine-fe.pages.dev/returntomonke

synape_Screenshot 2024-04-04 a <img width="78" alt="Screenshot 2024-04-04 at 1 07 05 PM" src="https://github.com/synapsecns/sanguine/assets/57741810/5c70672f-4375-4bba-8cbf-358695540fef"> t 1

canvas.height = img.height;
ctx.drawImage(img, 0, 0);

// Load the overlay image
const overlay = new Image();
overlay.src = './synpfpborder.png';
overlay.onload = () => {
// Draw the overlay image on top of the uploaded image
ctx.drawImage(overlay, 0, 0, canvas.width, canvas.height);

// Convert the canvas to a Blob and update the state
canvas.toBlob((blob) => {
setProcessedImage(blob);
}, 'image/jpeg');
};
};
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the image processing logic to gracefully handle cases where image loading fails.

img.onload = () => {
+ img.onerror = (error) => {
+   console.error('Error loading image:', error);
+   // Handle the error appropriately
+ };
  // Set the canvas size to match the uploaded image
  canvas.width = img.width;
  canvas.height = img.height;
  ctx.drawImage(img, 0, 0);
  // Load the overlay image
  const overlay = new Image();
  overlay.src = './synpfpborder.png';
  overlay.onload = () => {
    // Draw the overlay image on top of the uploaded image
    ctx.drawImage(overlay, 0, 0, canvas.width, canvas.height);
    // Convert the canvas to a Blob and update the state
    canvas.toBlob((blob) => {
      setProcessedImage(blob);
    }, 'image/jpeg');
  };
+ overlay.onerror = (error) => {
+   console.error('Error loading overlay image:', error);
+   // Handle the error appropriately
+ };
};

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const applyImageOverlay = () => {
const canvas = imgRef.current;
const ctx = canvas.getContext('2d');
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Load the uploaded image
const img = new Image();
img.src = URL.createObjectURL(uploadedImage);
img.onload = () => {
// Set the canvas size to match the uploaded image
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Load the overlay image
const overlay = new Image();
overlay.src = './synpfpborder.png';
overlay.onload = () => {
// Draw the overlay image on top of the uploaded image
ctx.drawImage(overlay, 0, 0, canvas.width, canvas.height);
// Convert the canvas to a Blob and update the state
canvas.toBlob((blob) => {
setProcessedImage(blob);
}, 'image/jpeg');
};
};
};
const applyImageOverlay = () => {
const canvas = imgRef.current;
const ctx = canvas.getContext('2d');
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Load the uploaded image
const img = new Image();
img.src = URL.createObjectURL(uploadedImage);
img.onload = () => {
img.onerror = (error) => {
console.error('Error loading image:', error);
// Handle the error appropriately
};
// Set the canvas size to match the uploaded image
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Load the overlay image
const overlay = new Image();
overlay.src = './synpfpborder.png';
overlay.onload = () => {
// Draw the overlay image on top of the uploaded image
ctx.drawImage(overlay, 0, 0, canvas.width, canvas.height);
// Convert the canvas to a Blob and update the state
canvas.toBlob((blob) => {
setProcessedImage(blob);
}, 'image/jpeg');
};
overlay.onerror = (error) => {
console.error('Error loading overlay image:', error);
// Handle the error appropriately
};
};
};


return (
<div>
<div
className={`
flex ${processedImage ? '' : 'h-[200px]'} w-full rounded-xl cursor-pointer
border-dashed border-4 border-white border-opacity-50 mb-2
text-white text-opacity-50 hover:text-opacity-100
hover:border-white
transform transition-all duration-200
`}
style={{
backgroundRepeat: 'no-repeat',
backgroundSize: 100,
backgroundPosition: 'center',
}}
onDragOver={handleDragOver}
onDrop={handleOnDrop}
onClick={() => fileInput.current.click()}
>
<p className="p-3 m-auto text-lg text-center center">
{!processedImage && (
<>
Click to Upload or
<br />
Drag and drop image here...
</>
)}
{processedImage && <>Select different image?</>}
</p>
<input
type="file"
accept="image/*"
ref={fileInput}
hidden
onChange={(e) => handleFile(e.target.files[0])}
/>
</div>
{processedImage && (
<img src={URL.createObjectURL(processedImage)} alt="preview" />
)}
<canvas ref={imgRef} style={{ display: 'none' }} />
{uploadedImage && (
<Button
className={`
w-full rounded-xl my-2 px-4 py-3 tracking-wide
text-white text-opacity-100
hover:opacity-80 disabled:opacity-100 disabled:text-[#88818C]
disabled:from-bgLight disabled:to-bgLight
bg-gradient-to-r from-[#CF52FE] to-[#AC8FFF]
`}
onClick={() => {
downloadBase64File(
URL.createObjectURL(processedImage),
`synape_${uploadedImage.name?.split('.')[0] ?? 'random'}.jpg`
);
}}
>
Download
</Button>
)}
</div>
);
}

function downloadBase64File(dataStr, fileName) {
const downloadLink = document.createElement('a');
downloadLink.href = dataStr;
downloadLink.download = fileName;
downloadLink.click();
console.log('evolving into a synape');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Card from '@tw/Card'

import ImageUploader from './ImageUploader'

export default function PfpGeneratorCard() {
return (
<Card
title={
<>
Choose Synapse
</>
}
divider={false}
className="rounded-xl min-w-[380px]"
titleClassName="text-center text-white text-opacity-50 font-normal py-2"
>
<ImageUploader />
</Card>
)
}
55 changes: 55 additions & 0 deletions packages/synapse-interface/pages/returntomonke/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Grid from '@tw/Grid'
import { useRouter } from 'next/router'
import { useEffect, useMemo, useState } from 'react'
import { useAccount, useNetwork } from 'wagmi'
import { DEFAULT_FROM_CHAIN } from '@/constants/swap'
import { LandingPageWrapper } from '@layouts/LandingPageWrapper'
import StandardPageContainer from '@layouts/StandardPageContainer'

import PfpGeneratorCard from './PfpGeneratorCard'

const ReturnToMonkePage = () => {
const { address: currentAddress } = useAccount()
const { chain } = useNetwork()
const [connectedChainId, setConnectedChainId] = useState(0)
const [address, setAddress] = useState(undefined)

const router = useRouter()

useEffect(() => {
setConnectedChainId(chain?.id ?? DEFAULT_FROM_CHAIN)
}, [chain])

useEffect(() => {
setAddress(currentAddress)
}, [currentAddress])
return (
<LandingPageWrapper>
<StandardPageContainer
connectedChainId={connectedChainId}
address={address}
>
<div className="flex justify-between">
<div>
<div className="text-2xl text-white">
Generate Synaptic Profile Picture
</div>
</div>
</div>
<div className="py-6">
<Grid
cols={{ xs: 1 }}
gap={6}
className="justify-center px-2 py-16 sm:px-6 md:px-8"
>
<div className="pb-3 place-self-center">
<PfpGeneratorCard />
</div>
</Grid>
</div>
</StandardPageContainer>
</LandingPageWrapper>
)
}

export default ReturnToMonkePage
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading