Skip to content

Commit

Permalink
feat: decode base64 encoded SVG and display it (#104)
Browse files Browse the repository at this point in the history
* [feat] decode base64 encoded SVG and display it

* [feat] generate a SVG from the user text and encode it in base64

---------

Co-authored-by: Rémy Baranx <[email protected]>
  • Loading branch information
remybar and Rémy Baranx committed Feb 16, 2024
1 parent 01c1ad6 commit 402faa8
Showing 1 changed file with 92 additions and 15 deletions.
107 changes: 92 additions & 15 deletions blobby/src/app/components/Inputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,83 @@
import React, { ChangeEvent, useState } from "react";
import CopyToClipboardButton from "./CopyButton";

const BASE64_SVG_MIME = "data:image/svg+xml;base64,";

const Inputs = () => {
const [svg, setSvg] = useState("");
const [text, setText] = useState("");
const [svgText, setSvgText] = useState("");
const [display, setDisplay] = useState("none");
const [svgEncodedData, setSvgEncodedData] = useState("");

const [svgDecodedData, setSvgDecodedData] = useState("");
const [svgDecodingError, setSvgDecodingError] = useState("");

const isBase64 = (s: string) => {
const re = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
return re.test(s);
};

const buildSvgFromText = (userText: string) => {
return `<svg xmlns="http://www.w3.org/2000/svg" width="128px" height="128px">
<circle cx="64" cy="64" r="64" fill="#F37567" />
<text
x="64"
y="64"
font-size="16px"
font-weight="700"
font-family="sans-serif"
text-anchor="middle"
dy=".3em"
fill="white">
${userText}
</text>
</svg>`;
};

const encodeSvg = (userText: string) => {
const svg = buildSvgFromText(userText);
const svgInBase64 = btoa(svg);
setSvgEncodedData(`${BASE64_SVG_MIME}${svgInBase64}`);
};

const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.value.trim() !== "") {
const handleSVGTextChange = (e: ChangeEvent<HTMLInputElement>) => {
const userText = e.target.value;

if (userText.trim() !== "") {
setDisplay("flex");
setSvg(e.target.value);
setSvgText(userText);
encodeSvg(userText);
} else {
setDisplay("none");
setSvgText("");
setSvgEncodedData("");
}
};

const handleBase64SVGChange = (e: ChangeEvent<HTMLInputElement>) => {
const eventData = e.target.value;

if (eventData.length === 0) {
setSvgDecodedData("");
setSvgDecodingError("");
return;
}

if (eventData.startsWith(BASE64_SVG_MIME)) {
const base64Data = eventData.replace(BASE64_SVG_MIME, "");

if (isBase64(base64Data)) {
const decodedData = atob(base64Data);
setSvgDecodedData(decodedData);
setSvgDecodingError("");
} else {
setSvgDecodedData("");
setSvgDecodingError(`Provided data are not base64 encoded`);
}
} else {
setSvgDecodedData("");
setSvgDecodingError(
`Invalid MIME type: does not start with ${BASE64_SVG_MIME}`
);
}
};

Expand All @@ -25,8 +91,7 @@ const Inputs = () => {
</div>
<div
style={{ display }}
className="w-[5px] bg-[#E2E8F0] h-full"
></div>
className="w-[5px] bg-[#E2E8F0] h-full"></div>
</div>
<div className="bg-[#ffffff] p-4 border border-[#e2e8f0] rounded-md w-full">
<h3 className="text-[#1A202C] text-[20px] font-bold">
Expand All @@ -42,14 +107,14 @@ const Inputs = () => {
id="svg"
name="svg"
required
onChange={handleInputChange}
onChange={handleSVGTextChange}
/>
<div
style={{ display }}
className=" text-white bg-[#F37567] p-2 w-[128px] h-[128px] self-center items-center justify-center mt-4 font-bold rounded-full"
>
<span className="text-center">{svg}</span>
</div>
{svgText.length > 0 && (
<div
className="my-4 mx-auto"
dangerouslySetInnerHTML={{ __html: buildSvgFromText(svgText) }}
/>
)}
</div>
</div>
</div>
Expand All @@ -58,7 +123,7 @@ const Inputs = () => {
num={2}
title="💾 Save the SVG as a variable "
description="In your terminal, set the SVG variable: "
value={`export SVG="data:image/svg+xml;base64,CiAgICAgIDxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+CiAgICAgICAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNDAiIGZpbGw9IiNhZDExZjciIC8+CiAgICAgICAgPHRleHQgeD0iNTAiIHk9IjUwIiBmb250LXNpemU9IjEyIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iIGZpbGw9IndoaXRlIj5GbG9yaWFuPC90ZXh0PgogICAgICA8L3N2Zz4KICAgIA=="`}
value={`export SVG="${svgEncodedData || ""}"`}
/>
<SetInputs1
num={3}
Expand Down Expand Up @@ -102,7 +167,19 @@ const Inputs = () => {
id="svg"
name="svg"
required
onChange={handleBase64SVGChange}
/>
{svgDecodingError && (
<div className="mt-1 text-xs text-red-500">
{svgDecodingError}
</div>
)}
{svgDecodedData && (
<div
className="my-4 mx-auto"
dangerouslySetInnerHTML={{ __html: svgDecodedData }}
/>
)}
</div>
</div>
</div>
Expand Down

0 comments on commit 402faa8

Please sign in to comment.