aboutsummaryrefslogtreecommitdiffstats
path: root/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview
diff options
context:
space:
mode:
Diffstat (limited to 'public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview')
-rw-r--r--public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/Headline/Headline.js120
-rw-r--r--public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/MemePreview.js61
2 files changed, 181 insertions, 0 deletions
diff --git a/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/Headline/Headline.js b/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/Headline/Headline.js
new file mode 100644
index 0000000..e7ed579
--- /dev/null
+++ b/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/Headline/Headline.js
@@ -0,0 +1,120 @@
+import { useEffect, useRef, useState } from "react";
+import Form from "../../commons/Form";
+import Input from "../../commons/Input";
+
+function Headline({ id, text, fontSize, xPos, yPos, setHeadlines }) {
+ const inputRef = useRef(null);
+ const [isEditing, setIsEditing] = useState(false);
+ useEffect(() => {
+ isEditing && inputRef.current.focus();
+ });
+
+ const [inputValue, setInputValue] = useState(text);
+ useEffect(() => {
+ setInputValue(text);
+ }, [text]);
+
+ const getXPos = () => {
+ let styles = {};
+ switch (xPos) {
+ case "Left":
+ styles = { gridColumn: 1, textAlign: "left" };
+ break;
+ case "Right":
+ styles = { gridColumn: 2, textAlign: "right" };
+ break;
+ case "Center":
+ styles = {
+ gridColumnStart: 1,
+ gridColumnEnd: "span 2",
+ justifySelf: "center",
+ textAlign: "center",
+ };
+ break;
+ default:
+ break;
+ }
+ return styles;
+ };
+
+ const getYPos = () => {
+ let styles = {};
+ switch (yPos) {
+ case "Top":
+ styles = { gridRow: 1 };
+ break;
+ case "Bottom":
+ styles = { gridRow: 3, alignSelf: "end" };
+ break;
+ case "Middle":
+ styles = { gridRow: 2, alignSelf: "center" };
+ break;
+ default:
+ break;
+ }
+ return styles;
+ };
+
+ const styles = {
+ fontSize: fontSize,
+ ...getYPos(),
+ ...getXPos(),
+ };
+
+ const onSubmit = (e) => {
+ e.preventDefault();
+ setIsEditing(false);
+ };
+
+ const updateText = (e) => {
+ setInputValue(e.target.value);
+ };
+
+ useEffect(() => {
+ setHeadlines((previous) => {
+ return previous.map((headline) => {
+ if (headline.id !== id) return headline;
+ return { ...headline, text: inputValue };
+ });
+ });
+ }, [setHeadlines, id, inputValue]);
+
+ useEffect(() => {
+ setHeadlines((previous) => {
+ return previous.map((headline) => {
+ if (headline.id !== id) return headline;
+ return { ...headline, text: inputValue };
+ });
+ });
+ }, [setHeadlines, id, inputValue]);
+
+ const onBlur = () => {
+ setIsEditing(false);
+ };
+
+ return (
+ <>
+ {isEditing ? (
+ <Form onSubmitHandler={onSubmit} styles={styles}>
+ <Input
+ value={inputValue}
+ ref={inputRef}
+ onChangeHandler={updateText}
+ onBlurHandler={onBlur}
+ additionalClasses="meme-preview__headline"
+ />
+ </Form>
+ ) : (
+ <p
+ className="meme-preview__headline"
+ onClick={() => setIsEditing(true)}
+ style={styles}
+ >
+ {inputValue}
+ </p>
+ )}
+ </>
+ );
+}
+
+export default Headline;
diff --git a/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/MemePreview.js b/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/MemePreview.js
new file mode 100644
index 0000000..6577e53
--- /dev/null
+++ b/public/projects/react-small-apps/apps/meme-generator/src/components/MemePreview/MemePreview.js
@@ -0,0 +1,61 @@
+import { useEffect, useState } from "react";
+import Button from "../commons/Button";
+import Headline from "./Headline/Headline";
+
+async function fetchMemes() {
+ const response = await fetch("https://api.imgflip.com/get_memes");
+ const result = await response.json();
+ return await result;
+}
+
+function MemePreview({ headlines, setHeadlines }) {
+ const [memesList, setMemesList] = useState([]);
+ const [isFetched, setIsFetched] = useState(false);
+ useEffect(() => {
+ fetchMemes().then((object) => setMemesList(object.data.memes));
+ setIsFetched(true);
+ return () => setIsFetched(false);
+ }, [setIsFetched]);
+
+ const [selectedMeme, setSelectedMeme] = useState({});
+ useEffect(() => {
+ setSelectedMeme(memesList[5]);
+ }, [memesList]);
+
+ const getRandomMeme = () => {
+ const randomIndex = Math.floor(Math.random() * memesList.length);
+ setSelectedMeme(memesList[randomIndex]);
+ };
+
+ const headlinesList = headlines.map((headline) => (
+ <Headline
+ key={headline.id}
+ id={headline.id}
+ text={headline.text}
+ fontSize={`${headline.fontSize}${headline.fontUnit}`}
+ xPos={headline.xPos}
+ yPos={headline.yPos}
+ setHeadlines={setHeadlines}
+ />
+ ));
+
+ return (
+ <div className="meme-preview">
+ <div className="meme-preview__meme">
+ {isFetched && selectedMeme ? (
+ <img
+ src={selectedMeme.url}
+ alt={selectedMeme.name}
+ className="meme-preview__image"
+ />
+ ) : (
+ "Loading..."
+ )}
+ {headlinesList}
+ </div>
+ <Button body="Random image" modifier="random" onClick={getRandomMeme} />
+ </div>
+ );
+}
+
+export default MemePreview;