Skip to content

Commit

Permalink
mid changes for html to img
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavyagor12 committed Jun 30, 2024
1 parent 7bc8318 commit 9b04dee
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ReactNode } from "react";
import { NextResponse } from "next/server";
import { NextRequest, NextResponse } from "next/server";
import fs from "fs";
import { NextApiRequest } from "next";
import path from "path";
import { html } from "satori-html";
import satori from "satori/wasm";
Expand All @@ -25,8 +24,11 @@ const createImageFromHtml = async (HTML: string) => {
return svg;
};

export default async function POST(req: NextApiRequest) {
const { HTML } = req.body;
const svg = await createImageFromHtml(HTML);
export async function POST(req: NextRequest) {
const payload = await req.json();
const { html } = payload;
console.log(html);
const svg = await createImageFromHtml(html);
console.log(svg);
return new NextResponse(svg, { headers: { "Content-Type": "image/svg+xml" } });
}
33 changes: 33 additions & 0 deletions packages/nextjs/app/api/imageGeneration/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ImageResponse } from "next/og";
import { NextRequest } from "next/server";
import parse from "html-react-parser";

// export const runtime = 'edge';

export async function POST(req: NextRequest) {
const payload = await req.json();
const { html } = payload;
return new ImageResponse(
(
<div
style={{
fontSize: 40,
color: "black",
background: "white",
width: "100%",
height: "100%",
padding: "50px 200px",
textAlign: "center",
justifyContent: "center",
alignItems: "center",
}}
>
{parse(html)}
</div>
),
{
width: 1200,
height: 630,
},
);
}
2 changes: 1 addition & 1 deletion packages/nextjs/app/dashboard/[productID]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const Product: NextPage = () => {
<div className="col-span-1">
<FrameSidebar />
</div>
<div className="col-span-3 mt-24">
<div className="col-span-3 mt-4">
<FrameRender />
</div>
<div className="col-span-2 ">
Expand Down
46 changes: 30 additions & 16 deletions packages/nextjs/components/ButtonEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useEffect, useState } from "react";
import InputField from "./InputField";
import { FrameButtonMetadata } from "@coinbase/onchainkit";
import { IconButton, MenuItem, Select } from "@mui/material";
import { TrashIcon } from "@heroicons/react/24/outline";
import { useProductJourney } from "~~/providers/ProductProvider";
import { getFrameById } from "~~/services/frames";
import { Frame } from "~~/types/commontypes";
import { APP_URL } from "~~/constants";

interface ButtonEditorProps {
button: FrameButtonMetadata;
Expand All @@ -10,6 +15,17 @@ interface ButtonEditorProps {
}

const ButtonEditor = ({ button, onSave, onDelete }: ButtonEditorProps) => {
const { frames: dbFrames } = useProductJourney();
const [frames, setFrames] = useState<Frame[] | undefined>();

useEffect(() => {
if (dbFrames) {
Promise.all(dbFrames.map(frame => getFrameById(frame)))
.then(data => setFrames(data))
.catch(error => console.error("Error fetching frames:", error));
}
}, [dbFrames]);

return (
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2 mt-4">
Expand All @@ -30,29 +46,27 @@ const ButtonEditor = ({ button, onSave, onDelete }: ButtonEditorProps) => {
<Select
id="buttonAction"
value={button.action}
onChange={e => onSave({ ...button, action: e.target.value as string })}
onChange={e => onSave({ ...button, action: e.target.value as FrameButtonMetadata["action"] })}
variant="outlined"
>
<MenuItem value="tx">Transaction</MenuItem>
<MenuItem value="post">Post</MenuItem>
<MenuItem value="link">Link</MenuItem>
<MenuItem value="post_redirect">Post Redirect</MenuItem>
</Select>
<InputField
id="buttonTarget"
label="Edit Button Target"
value={button.target || ""}
onChange={target => onSave({ ...button, target })}
placeholder="Button Target"
/>
{button.action === "tx" && (
<InputField
id="buttonPostUrl"
label="Edit Button Post URL"
value={button.postUrl || ""}
onChange={postUrl => onSave({ ...button, postUrl })}
placeholder="Button Post URL"
/>
{button.action === "post" && (
<Select
id="post"
value={button.target}
onChange={e => onSave({ ...button, target: `${APP_URL}`+e.target.value as FrameButtonMetadata["target"] })}
variant="outlined"
>
{frames?.map((frame, index) => (
<MenuItem key={index} value={frame._id}>
{frame.name}
</MenuItem>
))}
</Select>
)}
</div>
);
Expand Down
88 changes: 70 additions & 18 deletions packages/nextjs/components/FrameEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import ButtonList from "./ButtonsList";
import InputField from "./InputField";
import { MenuItem, Select } from "@mui/material";
Expand All @@ -7,6 +7,53 @@ import { useProductJourney } from "~~/providers/ProductProvider";
const FrameEditor = () => {
const { currentFrame, setCurrentFrame } = useProductJourney();
const [imageUrlOption, setImageUrlOption] = useState("url");
const [htmlInput, setHtmlInput] = useState("");
const [imageUrl, setImageUrl] = useState(currentFrame?.image?.src || "");

const getImageResponse = async (html: string) => {
const response = await fetch(`/api/imageGeneration`, {
body: JSON.stringify({ html }),
headers: {
"Content-Type": "application/json",
},
method: "POST",
});
const data = await response.json();
return data;
};

const handleImageUrlChange = (value: string) => {
setImageUrl(value);
if (!currentFrame) return;
setCurrentFrame({
...currentFrame,
image: {
// @ts-ignore
...currentFrame?.image,
src: value,
aspectRatio: "1:1",
},
});
};

const handleHtmlToImage = async () => {
const result = await getImageResponse(htmlInput);
setImageUrl(result);
if (!currentFrame) return;
setCurrentFrame({
...currentFrame,
image: {
// @ts-ignore
...currentFrame.image,
src: result,
aspectRatio: "1:1",
},
});
};
useEffect(() => {
// @ts-ignore
setImageUrl(currentFrame?.image?.src || "");
}, [currentFrame]);
if (!currentFrame) return null;
return (
<div className="bg-white flex flex-col gap-4 p-4">
Expand All @@ -24,23 +71,28 @@ const FrameEditor = () => {
<MenuItem value="url">URL</MenuItem>
<MenuItem value="html">HTML</MenuItem>
</Select>{" "}
<InputField
id="imageUrl"
label={imageUrlOption === "url" ? "Enter Image URL" : "Enter HTML Code"}
// @ts-ignore
value={currentFrame?.image?.src || ""}
onChange={value => {
setCurrentFrame({
...currentFrame,
image: {
// @ts-ignore
...currentFrame?.image,
src: value,
},
});
}}
placeholder={imageUrlOption === "url" ? "Image URL" : "HTML Code"}
/>
{imageUrlOption === "url" ? (
<InputField
id="imageUrl"
label="Enter Image URL"
value={imageUrl}
onChange={value => handleImageUrlChange(value)}
placeholder="Image URL"
/>
) : (
<div className="flex flex-col gap-2">
<InputField
id="htmlInput"
label="Enter HTML Code"
value={htmlInput}
onChange={value => setHtmlInput(value)}
placeholder="HTML Code"
/>
<button onClick={handleHtmlToImage} className="btn btn-primary">
Convert HTML to Image
</button>
</div>
)}
<InputField
id="additionalInput"
label="Enter Additional Input"
Expand Down
5 changes: 3 additions & 2 deletions packages/nextjs/components/FrameRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ function FrameRender() {
style={{
borderRadius: "4px",
border: "1px solid #ccc",
width: "100%", // Set the width to 100%
height: "40vh", // Maintain aspect ratio
aspectRatio: "1:1",
maxHeight: "500px",
width: "100%",
}}
/>
{currentFrame.input?.text && (
Expand Down
11 changes: 7 additions & 4 deletions packages/nextjs/components/FramesSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const thumbnailImageStyle = {
marginLeft: "7px",
maxWidth: "90%",
height: "auto",
maxHeight: "90%",
borderRadius: "5px",
};
const sidebarStyle = {
Expand All @@ -34,19 +35,21 @@ const thumbnailActiveStyle = {
backgroundColor: "#c0c0c0",
};
function FrameSidebar() {
const { frames: dbFrames, frame, setFrame, setCurrentFrame, createFrame } = useProductJourney();
const { productQuery, frame, setFrame, setCurrentFrame, createFrame } = useProductJourney();
const [frames, setFrames] = useState<Frame[] | undefined>(undefined);
const [currentFrameId, setCurrentFrameId] = useState<string>(frame?._id as string);
useEffect(() => {
if (dbFrames) {
Promise.all(dbFrames.map(frame => getFrameById(frame)))
if (productQuery.data) {
Promise.all(productQuery.data.frames.map(frame => getFrameById(frame)))
.then(data => setFrames(data))
.catch(error => console.error("Error fetching frames:", error));
}
}, [dbFrames]);
}, [productQuery.data]);

useEffect(() => {
setCurrentFrameId(frame?._id as string);
}, [frame]);

const onCreate = async () => {
await createFrame.mutateAsync({
name: "Frame",
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
"blo": "^1.0.1",
"burner-connector": "^0.0.8",
"daisyui": "4.5.0",
"html-react-parser": "^5.1.10",
"mongoose": "^8.2.4",
"next": "^14.0.4",
"next-themes": "^0.2.1",
"nprogress": "^0.2.0",
"permissionless": "^0.1.30",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.0",
Expand Down
26 changes: 21 additions & 5 deletions packages/nextjs/providers/ProductProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ interface IProductJourney {
frame: Frame | null;
setFrame: (frame: Frame) => void;
journey: Journey | null;
frames: string[] | undefined;
setCurrentFrame: (frame: FrameMetadataType) => void;
currentFrame: FrameMetadataType | null;
createFrame: UseMutationResult<Frame, Error, Omit<Frame, "_id">>;
saveFrame: UseMutationResult<Frame, Error, Frame>;
deleteFrame: UseMutationResult<Frame, Error, string>;
htmlToImage: UseMutationResult<{ image: string }, Error, { html: string }>;
frames: string[] | undefined;
}

const ProductJourney = createContext<IProductJourney | null>(null);
Expand Down Expand Up @@ -92,7 +93,6 @@ const useProduct = () => {
return data;
},
onSettled: data => {
console.log(data);
journey?.frames.push(data._id);
updateProduct.mutateAsync(journey as Journey);
setFrame(data);
Expand Down Expand Up @@ -145,11 +145,26 @@ const useProduct = () => {
setCurrentFrame(null);
},
});

const htmlToImage = useMutation({
mutationFn: async (html: string) => {
const response = await fetch(`/api/htmlToImage`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ html }),
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
return data;
},
});
const frames = useMemo(() => {
if (!journey) return;
return journey?.frames;
}, [journey]);

return {
productID,
productQuery,
Expand All @@ -159,10 +174,11 @@ const useProduct = () => {
currentFrame,
setCurrentFrame,
journey,
frames,
createFrame,
saveFrame,
deleteFrame,
htmlToImage,
frames,
};
};

Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2502,6 +2502,7 @@ __metadata:
prettier: ^2.8.4
qrcode.react: ^3.1.0
react: ^18.2.0
react-apexcharts: ^1.4.1
react-copy-to-clipboard: ^5.1.0
react-dom: ^18.2.0
react-hot-toast: ^2.4.0
Expand Down

0 comments on commit 9b04dee

Please sign in to comment.