├── src
├── styles.scss
├── Candidates.jsx
├── App.js
├── index.js
├── WaitingRoom.jsx
├── timer.jsx
├── GameOver.jsx
├── Winner.jsx
├── Voting.jsx
├── Ideation.jsx
├── Home.jsx
└── templates.js
├── Procfile
├── .prettierrc.js
├── .babelrc
├── README.md
├── .eslintrc.json
├── index.html
├── LICENSE
├── webpack.config.js
├── package.json
├── .gitignore
└── server
└── server.js
/src/styles.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: node server/server.js
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | arrowParens: 'avoid',
5 | singleQuote: true,
6 | printWidth: 100,
7 | tabWidth: 2,
8 | };
9 |
--------------------------------------------------------------------------------
/src/Candidates.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Candidates({ memes }) {
4 | const images = memes.map(url => {});
5 |
6 | return
hi
;
7 | }
8 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false
7 | }
8 | ],
9 | "@babel/preset-react"
10 | ],
11 | "plugins": [
12 | "react-hot-loader/babel"
13 | ]
14 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Home from './Home';
3 | import io from 'socket.io-client';
4 |
5 | export default function App() {
6 | const socket = io.connect('http://localhost:3001');
7 |
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import { BrowserRouter as Router } from 'react-router-dom';
5 | import './styles.scss';
6 |
7 | const mountNode = document.getElementById('app');
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | mountNode,
13 | );
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MEME HOURS
2 |
3 | Meme Hours is a real-time multiplayer game in which users are prompted to write captions for a randomly given meme template. At the end of each round, users give likes to each meme and the round winner is displayed. At the end of the game, all round winners are displayed.
4 |
5 |
6 | First:
7 | `npm run build`
8 |
9 | Then:
10 | `npm start` for hot module reloading!
11 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {},
3 | "env": {
4 | "es6": true,
5 | "browser": true
6 | },
7 | "parserOptions": {
8 | "ecmaVersion": 2018,
9 | "sourceType": "module",
10 | "ecmaFeatures": {
11 | "jsx": true
12 | }
13 | },
14 | "extends": [
15 | "plugin:prettier/recommended"
16 | ],
17 | "globals": {
18 | "Atomics": "readonly",
19 | "SharedArrayBuffer": "readonly"
20 | },
21 | "plugins": [
22 | "react"
23 | ]
24 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Meme Hours
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/WaitingRoom.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | const Wrapper = styled.main`
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: center;
8 | align-items: center;
9 | text-align: center;
10 | `;
11 |
12 | const Div = styled.div`
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | border: dotted 0.5px;
17 | width: 50%;
18 | padding: 10px;
19 | font-size: 50px;
20 | box-shadow: 9px 9px 40px -12px rgba(0, 0, 0, 0.75);
21 | `;
22 |
23 | export default function WaitingRoom(props) {
24 | return {props.name} is in the room! ;
25 | }
26 |
--------------------------------------------------------------------------------
/src/timer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 |
3 | export default function Timer({ mins, secs, setTimesUp }) {
4 | const [minutes, setMinutes] = useState(mins);
5 | const [seconds, setSeconds] = useState(secs);
6 |
7 | useEffect(() => {
8 | let myInterval = setInterval(() => {
9 | if (seconds > 0) {
10 | setSeconds(seconds => seconds - 1);
11 | }
12 | if (seconds === 0) {
13 | if (minutes === 0) {
14 | clearInterval(myInterval);
15 | setTimesUp(true);
16 | } else {
17 | setMinutes(minutes => minutes - 1);
18 | setSeconds(59);
19 | }
20 | }
21 | }, 1000);
22 | return () => {
23 | clearInterval(myInterval);
24 | };
25 | });
26 |
27 | return (
28 |
29 | {minutes === 0 && seconds == 0 ? null : (
30 |
31 | Time Remaining: {minutes}: {seconds < 10 ? `0${seconds}` : seconds}
32 |
33 | )}
34 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 squirtle-squared
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/GameOver.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Switch, Route, Link, useHistory } from 'react-router-dom';
3 |
4 | export default function GameOver({ socket, setRound, winners, setWinners, self }) {
5 | const history = useHistory();
6 | const handleClick = e => {
7 | e.preventDefault();
8 | socket.emit('reset');
9 | };
10 |
11 | useEffect(() => {
12 | socket.emit('getWinners');
13 | socket.on('getWinners', memes => {
14 | setWinners(memes);
15 | });
16 | socket.on('reset', () => {
17 | setRound(1);
18 | history.push('/');
19 | });
20 | }, []);
21 | return (
22 |
23 | {winners.length &&
24 | winners.map((meme, i) => (
25 |
26 |
27 |
Round: {meme.round}
28 |
Creator: {meme.name}
29 |
Points: {meme.likes}
30 |
31 |
32 |
33 | ))}
34 | {self.isHost &&
Restart Meme Hours }
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: ['react-hot-loader/patch', './src/index.js'],
5 | output: {
6 | path: path.resolve(__dirname, 'dist'),
7 | filename: 'bundle.js',
8 | publicPath: '/',
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.(js|jsx)$/,
14 | use: 'babel-loader',
15 | exclude: /node_modules/,
16 | },
17 | {
18 | test: /\.css$/,
19 | use: ['style-loader', 'css-loader'],
20 | },
21 | {
22 | test: /\.scss$/,
23 | use: ['style-loader', 'css-loader', 'sass-loader'],
24 | },
25 | {
26 | test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
27 | include: [path.resolve(__dirname + '/src')],
28 | loader: 'url-loader?limit=50000&name=[name].[ext]',
29 | },
30 | ],
31 | },
32 | resolve: {
33 | extensions: ['.js', '.jsx'],
34 | alias: {
35 | 'react-dom': '@hot-loader/react-dom',
36 | },
37 | },
38 | devServer: {
39 | host: 'localhost',
40 | port: 8080,
41 | contentBase: path.resolve(__dirname, 'dist'),
42 | historyApiFallback: true,
43 | headers: { 'Access-Control-Allow-Origin': '*' },
44 | proxy: {
45 | '/': {
46 | target: 'http://localhost:3001/',
47 | secure: false,
48 | },
49 | },
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "memehours",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server/server.js",
6 | "engines": {
7 | "node": "^12"
8 | },
9 | "scripts": {
10 | "clean": "rm -rf dist",
11 | "build": "webpack -p --mode=production && cp index.html dist/index.html",
12 | "start": "webpack-dev-server --open --hot & nodemon server/server.js",
13 | "test": "echo \"Error: no test specified\" && exit 1",
14 | "start-server": "node server/server.js",
15 | "build-all": "rm -rf dist && npm i && npm run build",
16 | "heroku-postbuild": "npm run build-all"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/heatherfriedman/MemeHours.git"
21 | },
22 | "author": "Heather Friedman, Will Hack, Kadir Gundogdu, Rebecca Miller",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/heatherfriedman/MemeHours/issues"
26 | },
27 | "homepage": "https://github.com/heatherfriedman/MemeHours#readme",
28 | "dependencies": {
29 | "express": "^4.17.1",
30 | "react": "^16.13.1",
31 | "react-dom": "^16.13.1",
32 | "react-hook-form": "^6.8.6",
33 | "react-hot-loader": "^4.13.0",
34 | "react-router-dom": "^5.2.0",
35 | "socket.io": "^2.3.0",
36 | "socket.io-client": "^2.3.0",
37 | "styled-components": "^5.2.0",
38 | "stylis": "^4.0.3"
39 | },
40 | "devDependencies": {
41 | "@babel/core": "^7.11.6",
42 | "@babel/preset-env": "^7.11.5",
43 | "@babel/preset-react": "^7.10.4",
44 | "@hot-loader/react-dom": "^17.0.0-rc.2",
45 | "babel-loader": "^8.1.0",
46 | "css-loader": "^4.3.0",
47 | "eslint": "^7.10.0",
48 | "eslint-config-prettier": "^6.12.0",
49 | "eslint-plugin-prettier": "^3.1.4",
50 | "eslint-plugin-react": "^7.21.2",
51 | "file-loader": "^6.1.0",
52 | "node-sass": "^4.14.1",
53 | "prettier": "^2.1.2",
54 | "sass-loader": "^10.0.2",
55 | "style-loader": "^1.2.1",
56 | "url-loader": "^4.1.0",
57 | "webpack": "^4.44.2",
58 | "webpack-cli": "^3.3.12",
59 | "webpack-dev-server": "^3.11.0"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 | package-lock.json
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # DS_STORE
104 | .DS_Store
105 |
106 | # TernJS port file
107 | .tern-port
108 |
109 | # Dist file
110 | dist
111 |
112 | # Package-lock.json
113 | package-lock.json
--------------------------------------------------------------------------------
/src/Winner.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Switch, Route, useHistory } from 'react-router-dom';
3 | import Timer from './Timer.jsx';
4 |
5 | export default function Winner({
6 | socket,
7 | setSubmitClicked,
8 | setIdeationTimesUp,
9 | setAllSubmitted,
10 | round,
11 | setRound,
12 | winner,
13 | setWinner,
14 | winners,
15 | setWinners,
16 | }) {
17 | const history = useHistory();
18 | const [timesUp, setTimesUp] = useState(false);
19 |
20 | useEffect(() => {
21 | socket.emit('getCandidates');
22 | socket.on('memeCandidates', candidates => {
23 | let max = -1;
24 | let winningMeme;
25 | for (let candidate of candidates) {
26 | if (candidate.likes > max) {
27 | max = candidate.likes;
28 | winningMeme = candidate;
29 | }
30 | }
31 | socket.emit('roundWinner', winningMeme);
32 | });
33 | }, []);
34 |
35 | useEffect(() => {
36 | if (timesUp) {
37 | socket.emit('newRound', round + 1);
38 | if (round + 1 === 3) {
39 | socket.emit('gameOver');
40 | } else {
41 | socket.emit('ideate');
42 | }
43 | }
44 | // socket.emit('newRound', round + 1);
45 | }, [timesUp]);
46 |
47 | // useEffect(() => {
48 | // socket.emit('roundWinner', winner);
49 | // }, [winner]);
50 |
51 | useEffect(() => {
52 | socket.on('roundWinner', meme => {
53 | setWinner(meme);
54 | });
55 | socket.on('roundWinners', roundWinners => {
56 | setWinners(roundWinners);
57 | });
58 | socket.on('newRound', round => {
59 | setSubmitClicked(false);
60 | setIdeationTimesUp(false);
61 | setAllSubmitted(false);
62 | setRound(round);
63 | });
64 | socket.on('ideate', () => {
65 | history.push('/ideation');
66 | });
67 | socket.on('gameOver', () => {
68 | history.push('/gameOver');
69 | });
70 | }, []);
71 |
72 | return (
73 |
74 |
75 |
The Winning Meme of Round {round}
76 | {winner && (
77 |
78 |
Creator: {winner.name}
79 |
Points: {winner.likes}
80 |
81 |
82 | )}
83 | {!winner && (
84 |
85 |
Nobody submitted a meme!
86 |
87 |
88 | )}
89 |
90 | );
91 | }
92 |
--------------------------------------------------------------------------------
/src/Voting.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { useHistory } from 'react-router-dom';
3 | import Candidates from './Candidates';
4 | import Timer from './Timer.jsx';
5 |
6 | export default function Voting({ socket, self }) {
7 | const [candidates, setCandidates] = useState([]);
8 | const history = useHistory();
9 | const [likes, setLikes] = useState([]);
10 | const [timesUp, setTimesUp] = useState(false);
11 | const handleClick = (e, i) => {
12 | e.preventDefault();
13 | const newCandidates = [...candidates];
14 | if (likes[i] < 10 || !likes[i]) {
15 | newCandidates[i].likes += 1;
16 | if (!likes[i]) {
17 | const newLikes = [...likes];
18 | newLikes[i] = 1;
19 | setLikes(newLikes);
20 | } else {
21 | const newLikes = [...likes];
22 | newLikes[i]++;
23 | setLikes(newLikes);
24 | }
25 | socket.emit('updateCandidates', newCandidates);
26 | }
27 | };
28 | const handleDislike = (e, i) => {
29 | e.preventDefault();
30 | const dislikedCandidates = [...candidates];
31 | if (likes[i] > 0) {
32 | dislikedCandidates[i].likes -= 1;
33 | const updatedLikes = [...likes];
34 | updatedLikes[i]--;
35 | setLikes(updatedLikes);
36 | }
37 | socket.emit('updateCandidates', dislikedCandidates);
38 | };
39 |
40 | let memes;
41 |
42 | //another timer to track voting - 1 min
43 | //same conditional rendering as ideation
44 | useEffect(() => {
45 | socket.emit('getCandidates');
46 | socket.on('memeCandidates', memes => {
47 | setCandidates(memes);
48 | });
49 | socket.on('updateCandidates', memes => {
50 | setCandidates(memes);
51 | });
52 | }, []);
53 |
54 | useEffect(() => {
55 | if (timesUp) history.push('/winner');
56 | }, [timesUp]);
57 |
58 | return (
59 |
60 |
61 | {candidates.length &&
62 | candidates.map((meme, i) => (
63 |
64 |
Meme {i + 1}
65 | {self.id !== meme.id && (
66 |
67 | handleClick(e, i)}>Like
68 | {likes[i] > 0 && handleDislike(e, i)}>Unlike }
69 | {likes[i] > 0 && You have liked this meme {likes[i]} times }
70 |
71 | )}
72 | {self.id === meme.id &&
Your meme
}
73 |
74 |
75 |
76 |
77 | ))}
78 | {!candidates.length && (
79 |
80 |
Nobody submitted a meme!
81 |
82 |
83 | )}
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const socketIO = require('socket.io');
4 | const path = require('path');
5 |
6 | const port = process.env.PORT || 3001;
7 |
8 | app.use(express.static(path.join(__dirname, '../dist')));
9 | app.get('*', (_request, response) =>
10 | response.sendFile(path.resolve(`${__dirname}/../dist/index.html`)),
11 | );
12 | const server = app.listen(port, () => console.log(`server listening on ${port}.`));
13 | const io = socketIO(server);
14 |
15 | const players = [];
16 | let submissions = [];
17 | let roundWinners = [];
18 | let round;
19 |
20 | io.on('connection', socket => {
21 | console.log('new client connected');
22 | socket.on('newPlayer', playerName => {
23 | const playerObject = {
24 | name: playerName,
25 | id: socket.id,
26 | isHost: players.length < 1,
27 | };
28 | players.push(playerObject);
29 | io.emit('updatePlayers', players);
30 | socket.emit('getSelf', playerObject);
31 | });
32 | socket.on('ideate', () => {
33 | io.emit('ideate');
34 | io.emit('randomNumber', Math.floor(Math.random() * 100));
35 | });
36 |
37 | // socket.on('randomNumber', () => {
38 | // io.emit('randomNumber', Math.floor(Math.random() * 100));
39 | // });
40 |
41 | socket.on('submitImage', ([name, id, memeUrl, round]) => {
42 | // console.log(name, memeUrl);
43 | // once submissions line 16 length === players length move on
44 | submissions.push({ name, id, memeUrl, likes: 0, round });
45 | // console.log(submissions);
46 | if (submissions.length === players.length) io.emit('voting');
47 | });
48 |
49 | socket.on('getCandidates', () => {
50 | socket.emit('memeCandidates', submissions);
51 | });
52 | socket.on('updateCandidates', memes => {
53 | submissions = memes;
54 | io.emit('updateCandidates', memes);
55 | });
56 |
57 | socket.on('roundWinner', meme => {
58 | if (meme) {
59 | if (meme.name) {
60 | let isInList = false;
61 | for (let winner of roundWinners) {
62 | if (meme.memeUrl === winner.memeUrl) isInList = true;
63 | }
64 | if (!isInList) {
65 | roundWinners.push(meme);
66 | io.emit('roundWinner', meme);
67 | io.emit('roundWinners', roundWinners);
68 | }
69 | }
70 | }
71 | });
72 |
73 | socket.on('newRound', newRound => {
74 | round = newRound;
75 | submissions = [];
76 | io.emit('newRound', round);
77 | });
78 | socket.on('getWinners', () => {
79 | socket.emit('getWinners', roundWinners);
80 | });
81 | socket.on('gameOver', () => {
82 | round = 1;
83 | io.emit('gameOver');
84 | });
85 | socket.on('reset', () => {
86 | roundWinners = [];
87 | round = 1;
88 | io.emit('reset');
89 | });
90 |
91 | socket.on('disconnect', sckt => {
92 | // removal from users array
93 | for (let i = 0; i < players.length; i++) {
94 | if (players[i].id === socket.id) {
95 | players.splice(i, 1);
96 | break;
97 | }
98 | }
99 | if (players.length) players[0].isHost = true;
100 | io.emit('updatePlayers', players);
101 | console.log('a user disconnected');
102 | // removal from submissions array
103 | for (let i = 0; i < submissions.length; i += 1) {
104 | if (submissions[i].id === socket.id) {
105 | submissions.splice(i, 1);
106 | break;
107 | }
108 | }
109 | if (submissions.length === players.length) io.emit('voting');
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/src/Ideation.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import { useHistory } from 'react-router-dom';
3 | import Timer from './Timer.jsx';
4 | const temps = require('./templates.js');
5 |
6 | export default function Ideation({
7 | socket,
8 | name,
9 | id,
10 | round,
11 | submitClicked,
12 | setSubmitClicked,
13 | ideationTimesUp,
14 | setIdeationTimesUp,
15 | allSubmitted,
16 | setAllSubmitted,
17 | winners,
18 | setWinners,
19 | }) {
20 | const [texts, setTexts] = useState([1, 2, 3, 4, 5, 6, 7]);
21 | const [templates, setTemplates] = useState(temps);
22 | const [currentMeme, setCurrentMeme] = useState(null);
23 | const imgRef = useRef(null);
24 | const history = useHistory();
25 |
26 | const handleChange = e => {
27 | const inputFields = [...texts];
28 | inputFields[e.target.id] = e.target.value;
29 | setTexts(inputFields);
30 | };
31 |
32 | const handleSubmit = e => {
33 | e.preventDefault();
34 | socket.emit('submitImage', [name, id, imgRef.current.src, round]);
35 | setSubmitClicked(true);
36 | };
37 |
38 | const handlePreview = e => {
39 | e.preventDefault();
40 | var myHeaders = new Headers();
41 | // myHeaders.append("Cookie", "__cfduid=d5b06b2df9eda0d63076d8ba50f5642121601326806; iflipsess=dv537v2andm5mkrns95s4se369; claim_key=bz13Qn7QBuqPCCqtTDLZz2Mierh_HXNx");
42 | var formdata = new FormData();
43 | formdata.append('template_id', currentMeme.id);
44 | formdata.append('username', 'memehours');
45 | formdata.append('password', 'csny2020');
46 | for (let i = 0; i < currentMeme.box_count; i++) {
47 | formdata.append(`boxes[${i}][text]`, texts[i]);
48 | }
49 |
50 | var requestOptions = {
51 | method: 'POST',
52 | headers: myHeaders,
53 | body: formdata,
54 | redirect: 'follow',
55 | };
56 |
57 | fetch('https://api.imgflip.com/caption_image', requestOptions)
58 | .then(res => res.json())
59 | .then(res => {
60 | imgRef.current.src = res.data.url;
61 | })
62 | .catch(error => console.log('error', error));
63 | };
64 |
65 | const mockPreview = () => {
66 | var myHeaders = new Headers();
67 | // myHeaders.append("Cookie", "__cfduid=d5b06b2df9eda0d63076d8ba50f5642121601326806; iflipsess=dv537v2andm5mkrns95s4se369; claim_key=bz13Qn7QBuqPCCqtTDLZz2Mierh_HXNx");
68 | var formdata = new FormData();
69 | formdata.append('template_id', currentMeme.id);
70 | formdata.append('username', 'memehours');
71 | formdata.append('password', 'csny2020');
72 | for (let i = 0; i < currentMeme.box_count; i++) {
73 | formdata.append(`boxes[${i}][text]`, texts[i]);
74 | }
75 |
76 | var requestOptions = {
77 | method: 'POST',
78 | headers: myHeaders,
79 | body: formdata,
80 | redirect: 'follow',
81 | };
82 |
83 | fetch('https://api.imgflip.com/caption_image', requestOptions)
84 | .then(res => res.json())
85 | .then(res => {
86 | imgRef.current.src = res.data.url;
87 | })
88 | .catch(error => console.log('error', error));
89 | };
90 |
91 | // const initialFetch = () => {
92 | // var myHeaders = new Headers();
93 | // // myHeaders.append("Cookie", "__cfduid=d5b06b2df9eda0d63076d8ba50f5642121601326806; iflipsess=dv537v2andm5mkrns95s4se369; claim_key=bz13Qn7QBuqPCCqtTDLZz2Mierh_HXNx");
94 | // var formdata = new FormData();
95 | // formdata.append('template_id', currentMeme.id);
96 | // formdata.append('username', 'memehours');
97 | // formdata.append('password', 'csny2020');
98 | // for (let i = 0; i < currentMeme.box_count; i++) {
99 | // formdata.append(`boxes[${i}][text]`, i + 1);
100 | // }
101 | // var requestOptions = {
102 | // method: 'POST',
103 | // headers: myHeaders,
104 | // body: formdata,
105 | // redirect: 'follow',
106 | // };
107 |
108 | // fetch('https://api.imgflip.com/caption_image', requestOptions)
109 | // .then(res => res.json())
110 | // .then(res => {
111 | // imgRef.current.src = res.data.url;
112 | // })
113 | // .catch(error => console.log('error', error));
114 | // };
115 |
116 | useEffect(() => {
117 | if (currentMeme) {
118 | mockPreview();
119 | }
120 | }, [currentMeme]);
121 |
122 | useEffect(() => {
123 | socket.on('randomNumber', num => {
124 | setCurrentMeme(templates[num]);
125 | });
126 | socket.on('voting', () => {
127 | setAllSubmitted(true);
128 | });
129 | setWinners([]);
130 | }, []);
131 |
132 | useEffect(() => {
133 | if (allSubmitted || ideationTimesUp) history.push('/voting');
134 | }, [allSubmitted, ideationTimesUp]);
135 |
136 | const textBoxes = [];
137 | if (currentMeme) {
138 | for (let i = 0; i < currentMeme.box_count; i++) {
139 | textBoxes.push(
140 | ,
148 | );
149 | }
150 | }
151 | return (
152 |
153 |
HELLO MEME HOURS!!!
154 |
Round {round}
155 |
156 | {currentMeme && (
157 |
158 |
{currentMeme.name}
159 |
160 |
161 |
162 |
163 | )}
164 | {!ideationTimesUp && !submitClicked && (
165 |
166 | {textBoxes}
167 | Preview
168 | Submit
169 |
170 | )}
171 | {!ideationTimesUp && submitClicked && (
172 |
173 |
174 | You have successfully submitted your meme! Please wait for others to submit or the time
175 | to run out to continue!
176 |
177 |
178 | )}
179 |
180 | );
181 | }
182 |
--------------------------------------------------------------------------------
/src/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Switch, Route, useHistory } from 'react-router-dom';
3 | import styled from 'styled-components';
4 | import Ideation from './Ideation';
5 | import WaitingRoom from './WaitingRoom';
6 | import Voting from './Voting';
7 | import Winner from './Winner';
8 | import GameOver from './GameOver';
9 |
10 | const Wrapper = styled.main`
11 | display: flex;
12 | flex-direction: column;
13 | justify-content: center;
14 | align-items: center;
15 | text-align: center;
16 | `;
17 |
18 | const Title = styled.h1`
19 | font-size: 60px;
20 | text-align: center;
21 | color: black;
22 | `;
23 |
24 | const SmallerText = styled.div`
25 | font-size: 30px;
26 | `;
27 |
28 | const FormStyled = styled.form`
29 | display: flex;
30 | flex-direction: column;
31 | align-items: center;
32 | border: dotted 0.5px;
33 | width: 50%;
34 | padding: 10px;
35 | font-size: 50px;
36 | box-shadow: 9px 9px 40px -12px rgba(0, 0, 0, 0.75);
37 | `;
38 |
39 | const StyledInput = styled.input`
40 | padding: 20px;
41 | margin: 10px;
42 | width: 75%;
43 | border: dotted;
44 | outline: none;
45 | font-size: 30px;
46 | `;
47 |
48 | const StyledInputButton = styled.input`
49 | border: solid 1px;
50 | padding: 10px;
51 | margin: 10px;
52 | background-color: inherit;
53 | font-size: 30px;
54 | border-radius: 10px;
55 |
56 | &:hover {
57 | background-color: lightblue;
58 | cursor: pointer;
59 | }
60 | `;
61 |
62 | const Div = styled.div`
63 | display: flex;
64 | flex-direction: column;
65 | align-items: center;
66 | border: dotted 0.5px;
67 | width: 50%;
68 | padding: 10px;
69 | font-size: 50px;
70 | box-shadow: 9px 9px 40px -12px rgba(0, 0, 0, 0.75);
71 | `;
72 |
73 | const Button = styled.button`
74 | border: solid 1px;
75 | padding: 10px;
76 | margin: 10px;
77 | background-color: inherit;
78 | font-size: 30px;
79 | border-radius: 10px;
80 |
81 | &:hover {
82 | background-color: lightblue;
83 | cursor: pointer;
84 | }
85 | `;
86 |
87 | export default function Home({ socket }) {
88 | const [name, setName] = useState('');
89 | const [newName, setNewName] = useState('start');
90 | const [players, setPlayers] = useState([]);
91 | const [isClicked, setIsClicked] = useState(false);
92 | const [submitClicked, setSubmitClicked] = useState(false);
93 | const [ideationTimesUp, setIdeationTimesUp] = useState(false);
94 | const [allSubmitted, setAllSubmitted] = useState(false);
95 | const [winners, setWinners] = useState([]);
96 | const [winner, setWinner] = useState({});
97 | const [self, setSelf] = useState({});
98 | const [round, setRound] = useState(1);
99 | const [winningMemes, setWinningMemes] = useState([]);
100 | const history = useHistory();
101 |
102 | // when submitted, player's name is pushed into player's array to be stored in state
103 | const handleSubmit = e => {
104 | e.preventDefault();
105 | if (!name) {
106 | setNewName('');
107 | }
108 | if (name) {
109 | setNewName(name);
110 | socket.emit('newPlayer', name);
111 | setIsClicked(true);
112 | }
113 | };
114 |
115 | // logic for what happens when start game is clicked
116 | const handleClick = e => {
117 | e.preventDefault();
118 | socket.emit('ideate');
119 | };
120 |
121 | useEffect(() => {
122 | socket.on('updatePlayers', newPlayers => {
123 | setPlayers(newPlayers);
124 | });
125 | socket.on('getSelf', newSelf => {
126 | setSelf(newSelf);
127 | });
128 | socket.on('ideate', () => {
129 | history.push('/ideation');
130 | });
131 | }, [players]);
132 |
133 | return (
134 |
135 |
136 |
137 | Meme Hours
138 | {!isClicked && (
139 |
140 |
141 | Name
142 | {
148 | setName(e.target.value);
149 | }}
150 | >
151 |
152 | {/* if correct is false, show this message */}
153 | {!newName && Please enter a name
}
154 | {/* if unique is false, show this message */}
155 | {/* {!unique && Someone else has that name, please pick a new one!
} */}
156 |
157 |
158 | )}
159 | {/* when you submit, you render the waiting room from all the current players in state */}
160 | {isClicked && (
161 |
162 | {players.map((player, index) => (
163 |
164 | ))}
165 | {players.length} player(s) are ready to play!
166 | {self.isHost ? (
167 | Start Game
168 | ) : (
169 | Waiting for the host to start game...
170 | )}
171 |
172 | )}
173 |
174 |
175 |
176 |
190 |
191 |
192 |
193 |
194 |
195 |
207 |
208 |
209 |
216 |
217 |
218 | );
219 | }
220 |
--------------------------------------------------------------------------------
/src/templates.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | id: '181913649',
4 | name: 'Drake Hotline Bling',
5 | url: 'https://i.imgflip.com/30b1gx.jpg',
6 | width: 1200,
7 | height: 1200,
8 | box_count: 2,
9 | },
10 | {
11 | id: '112126428',
12 | name: 'Distracted Boyfriend',
13 | url: 'https://i.imgflip.com/1ur9b0.jpg',
14 | width: 1200,
15 | height: 800,
16 | box_count: 3,
17 | },
18 | {
19 | id: '87743020',
20 | name: 'Two Buttons',
21 | url: 'https://i.imgflip.com/1g8my4.jpg',
22 | width: 600,
23 | height: 908,
24 | box_count: 2,
25 | },
26 | {
27 | id: '129242436',
28 | name: 'Change My Mind',
29 | url: 'https://i.imgflip.com/24y43o.jpg',
30 | width: 482,
31 | height: 361,
32 | box_count: 2,
33 | },
34 | {
35 | id: '131087935',
36 | name: 'Running Away Balloon',
37 | url: 'https://i.imgflip.com/261o3j.jpg',
38 | width: 761,
39 | height: 1024,
40 | box_count: 5,
41 | },
42 | {
43 | id: '217743513',
44 | name: 'UNO Draw 25 Cards',
45 | url: 'https://i.imgflip.com/3lmzyx.jpg',
46 | width: 500,
47 | height: 494,
48 | box_count: 2,
49 | },
50 | {
51 | id: '124822590',
52 | name: 'Left Exit 12 Off Ramp',
53 | url: 'https://i.imgflip.com/22bdq6.jpg',
54 | width: 804,
55 | height: 767,
56 | box_count: 3,
57 | },
58 | {
59 | id: '102156234',
60 | name: 'Mocking Spongebob',
61 | url: 'https://i.imgflip.com/1otk96.jpg',
62 | width: 502,
63 | height: 353,
64 | box_count: 2,
65 | },
66 | {
67 | id: '438680',
68 | name: 'Batman Slapping Robin',
69 | url: 'https://i.imgflip.com/9ehk.jpg',
70 | width: 400,
71 | height: 387,
72 | box_count: 2,
73 | },
74 | {
75 | id: '93895088',
76 | name: 'Expanding Brain',
77 | url: 'https://i.imgflip.com/1jwhww.jpg',
78 | width: 857,
79 | height: 1202,
80 | box_count: 4,
81 | },
82 | {
83 | id: '188390779',
84 | name: 'Woman Yelling At Cat',
85 | url: 'https://i.imgflip.com/345v97.jpg',
86 | width: 680,
87 | height: 438,
88 | box_count: 2,
89 | },
90 | {
91 | id: '222403160',
92 | name: 'Bernie I Am Once Again Asking For Your Support',
93 | url: 'https://i.imgflip.com/3oevdk.jpg',
94 | width: 750,
95 | height: 750,
96 | box_count: 2,
97 | },
98 | {
99 | id: '148909805',
100 | name: 'Monkey Puppet',
101 | url: 'https://i.imgflip.com/2gnnjh.jpg',
102 | width: 923,
103 | height: 768,
104 | box_count: 2,
105 | },
106 | {
107 | id: '1035805',
108 | name: 'Boardroom Meeting Suggestion',
109 | url: 'https://i.imgflip.com/m78d.jpg',
110 | width: 500,
111 | height: 649,
112 | box_count: 4,
113 | },
114 | {
115 | id: '119139145',
116 | name: 'Blank Nut Button',
117 | url: 'https://i.imgflip.com/1yxkcp.jpg',
118 | width: 600,
119 | height: 446,
120 | box_count: 2,
121 | },
122 | {
123 | id: '4087833',
124 | name: 'Waiting Skeleton',
125 | url: 'https://i.imgflip.com/2fm6x.jpg',
126 | width: 298,
127 | height: 403,
128 | box_count: 2,
129 | },
130 | {
131 | id: '226297822',
132 | name: 'Panik Kalm Panik',
133 | url: 'https://i.imgflip.com/3qqcim.png',
134 | width: 640,
135 | height: 881,
136 | box_count: 3,
137 | },
138 | {
139 | id: '100777631',
140 | name: 'Is This A Pigeon',
141 | url: 'https://i.imgflip.com/1o00in.jpg',
142 | width: 1587,
143 | height: 1425,
144 | box_count: 3,
145 | },
146 | {
147 | id: '97984',
148 | name: 'Disaster Girl',
149 | url: 'https://i.imgflip.com/23ls.jpg',
150 | width: 500,
151 | height: 375,
152 | box_count: 2,
153 | },
154 | {
155 | id: '91538330',
156 | name: 'X, X Everywhere',
157 | url: 'https://i.imgflip.com/1ihzfe.jpg',
158 | width: 2118,
159 | height: 1440,
160 | box_count: 2,
161 | },
162 | {
163 | id: '135256802',
164 | name: 'Epic Handshake',
165 | url: 'https://i.imgflip.com/28j0te.jpg',
166 | width: 900,
167 | height: 645,
168 | box_count: 3,
169 | },
170 | {
171 | id: '80707627',
172 | name: 'Sad Pablo Escobar',
173 | url: 'https://i.imgflip.com/1c1uej.jpg',
174 | width: 720,
175 | height: 709,
176 | box_count: 3,
177 | },
178 | {
179 | id: '178591752',
180 | name: 'Tuxedo Winnie The Pooh',
181 | url: 'https://i.imgflip.com/2ybua0.png',
182 | width: 800,
183 | height: 582,
184 | box_count: 2,
185 | },
186 | {
187 | id: '114585149',
188 | name: 'Inhaling Seagull',
189 | url: 'https://i.imgflip.com/1w7ygt.jpg',
190 | width: 1269,
191 | height: 2825,
192 | box_count: 4,
193 | },
194 | {
195 | id: '155067746',
196 | name: 'Surprised Pikachu',
197 | url: 'https://i.imgflip.com/2kbn1e.jpg',
198 | width: 1893,
199 | height: 1893,
200 | box_count: 3,
201 | },
202 | {
203 | id: '123999232',
204 | name: 'The Scroll Of Truth',
205 | url: 'https://i.imgflip.com/21tqf4.jpg',
206 | width: 1280,
207 | height: 1236,
208 | box_count: 2,
209 | },
210 | {
211 | id: '89370399',
212 | name: 'Roll Safe Think About It',
213 | url: 'https://i.imgflip.com/1h7in3.jpg',
214 | width: 702,
215 | height: 395,
216 | box_count: 2,
217 | },
218 | {
219 | id: '27813981',
220 | name: 'Hide the Pain Harold',
221 | url: 'https://i.imgflip.com/gk5el.jpg',
222 | width: 480,
223 | height: 601,
224 | box_count: 2,
225 | },
226 | {
227 | id: '61579',
228 | name: 'One Does Not Simply',
229 | url: 'https://i.imgflip.com/1bij.jpg',
230 | width: 568,
231 | height: 335,
232 | box_count: 2,
233 | },
234 | {
235 | id: '134797956',
236 | name: 'American Chopper Argument',
237 | url: 'https://i.imgflip.com/2896ro.jpg',
238 | width: 640,
239 | height: 1800,
240 | box_count: 5,
241 | },
242 | {
243 | id: '180190441',
244 | name: "They're The Same Picture",
245 | url: 'https://i.imgflip.com/2za3u1.jpg',
246 | width: 1363,
247 | height: 1524,
248 | box_count: 3,
249 | },
250 | {
251 | id: '135678846',
252 | name: 'Who Killed Hannibal',
253 | url: 'https://i.imgflip.com/28s2gu.jpg',
254 | width: 1280,
255 | height: 1440,
256 | box_count: 3,
257 | },
258 | {
259 | id: '101470',
260 | name: 'Ancient Aliens',
261 | url: 'https://i.imgflip.com/26am.jpg',
262 | width: 500,
263 | height: 437,
264 | box_count: 2,
265 | },
266 | {
267 | id: '175540452',
268 | name: 'Unsettled Tom',
269 | url: 'https://i.imgflip.com/2wifvo.jpg',
270 | width: 680,
271 | height: 550,
272 | box_count: 2,
273 | },
274 | {
275 | id: '91545132',
276 | name: 'Trump Bill Signing',
277 | url: 'https://i.imgflip.com/1ii4oc.jpg',
278 | width: 1866,
279 | height: 1529,
280 | box_count: 2,
281 | },
282 | {
283 | id: '21735',
284 | name: 'The Rock Driving',
285 | url: 'https://i.imgflip.com/grr.jpg',
286 | width: 568,
287 | height: 700,
288 | box_count: 2,
289 | },
290 | {
291 | id: '196652226',
292 | name: 'Spongebob Ight Imma Head Out',
293 | url: 'https://i.imgflip.com/392xtu.jpg',
294 | width: 822,
295 | height: 960,
296 | box_count: 2,
297 | },
298 | {
299 | id: '235589',
300 | name: 'Evil Toddler',
301 | url: 'https://i.imgflip.com/51s5.jpg',
302 | width: 500,
303 | height: 332,
304 | box_count: 2,
305 | },
306 | {
307 | id: '124055727',
308 | name: "Y'all Got Any More Of That",
309 | url: 'https://i.imgflip.com/21uy0f.jpg',
310 | width: 600,
311 | height: 471,
312 | box_count: 2,
313 | },
314 | {
315 | id: '6235864',
316 | name: 'Finding Neverland',
317 | url: 'https://i.imgflip.com/3pnmg.jpg',
318 | width: 423,
319 | height: 600,
320 | box_count: 3,
321 | },
322 | {
323 | id: '61520',
324 | name: 'Futurama Fry',
325 | url: 'https://i.imgflip.com/1bgw.jpg',
326 | width: 552,
327 | height: 414,
328 | box_count: 2,
329 | },
330 | {
331 | id: '28251713',
332 | name: 'Oprah You Get A',
333 | url: 'https://i.imgflip.com/gtj5t.jpg',
334 | width: 620,
335 | height: 465,
336 | box_count: 2,
337 | },
338 | {
339 | id: '161865971',
340 | name: 'Marked Safe From',
341 | url: 'https://i.imgflip.com/2odckz.jpg',
342 | width: 618,
343 | height: 499,
344 | box_count: 2,
345 | },
346 | {
347 | id: '3218037',
348 | name: "This Is Where I'd Put My Trophy If I Had One",
349 | url: 'https://i.imgflip.com/1wz1x.jpg',
350 | width: 300,
351 | height: 418,
352 | box_count: 2,
353 | },
354 | {
355 | id: '132769734',
356 | name: 'Hard To Swallow Pills',
357 | url: 'https://i.imgflip.com/271ps6.jpg',
358 | width: 680,
359 | height: 979,
360 | box_count: 2,
361 | },
362 | {
363 | id: '101288',
364 | name: 'Third World Skeptical Kid',
365 | url: 'https://i.imgflip.com/265k.jpg',
366 | width: 426,
367 | height: 426,
368 | box_count: 2,
369 | },
370 | {
371 | id: '101287',
372 | name: 'Third World Success Kid',
373 | url: 'https://i.imgflip.com/265j.jpg',
374 | width: 500,
375 | height: 500,
376 | box_count: 2,
377 | },
378 | {
379 | id: '61556',
380 | name: 'Grandma Finds The Internet',
381 | url: 'https://i.imgflip.com/1bhw.jpg',
382 | width: 640,
383 | height: 480,
384 | box_count: 2,
385 | },
386 | {
387 | id: '8072285',
388 | name: 'Doge',
389 | url: 'https://i.imgflip.com/4t0m5.jpg',
390 | width: 620,
391 | height: 620,
392 | box_count: 5,
393 | },
394 | {
395 | id: '14371066',
396 | name: 'Star Wars Yoda',
397 | url: 'https://i.imgflip.com/8k0sa.jpg',
398 | width: 620,
399 | height: 714,
400 | box_count: 2,
401 | },
402 | {
403 | id: '55311130',
404 | name: 'This Is Fine',
405 | url: 'https://i.imgflip.com/wxica.jpg',
406 | width: 580,
407 | height: 282,
408 | box_count: 2,
409 | },
410 | {
411 | id: '84341851',
412 | name: 'Evil Kermit',
413 | url: 'https://i.imgflip.com/1e7ql7.jpg',
414 | width: 700,
415 | height: 325,
416 | box_count: 2,
417 | },
418 | {
419 | id: '101511',
420 | name: "Don't You Squidward",
421 | url: 'https://i.imgflip.com/26br.jpg',
422 | width: 500,
423 | height: 333,
424 | box_count: 2,
425 | },
426 | {
427 | id: '61532',
428 | name: 'The Most Interesting Man In The World',
429 | url: 'https://i.imgflip.com/1bh8.jpg',
430 | width: 550,
431 | height: 690,
432 | box_count: 2,
433 | },
434 | {
435 | id: '5496396',
436 | name: 'Leonardo Dicaprio Cheers',
437 | url: 'https://i.imgflip.com/39t1o.jpg',
438 | width: 600,
439 | height: 400,
440 | box_count: 2,
441 | },
442 | {
443 | id: '16464531',
444 | name: "But That's None Of My Business",
445 | url: 'https://i.imgflip.com/9sw43.jpg',
446 | width: 600,
447 | height: 600,
448 | box_count: 2,
449 | },
450 | {
451 | id: '61539',
452 | name: 'First World Problems',
453 | url: 'https://i.imgflip.com/1bhf.jpg',
454 | width: 552,
455 | height: 367,
456 | box_count: 2,
457 | },
458 | {
459 | id: '61527',
460 | name: 'Y U No',
461 | url: 'https://i.imgflip.com/1bh3.jpg',
462 | width: 500,
463 | height: 500,
464 | box_count: 2,
465 | },
466 | {
467 | id: '922147',
468 | name: 'Laughing Men In Suits',
469 | url: 'https://i.imgflip.com/jrj7.jpg',
470 | width: 500,
471 | height: 333,
472 | box_count: 2,
473 | },
474 | {
475 | id: '563423',
476 | name: 'That Would Be Great',
477 | url: 'https://i.imgflip.com/c2qn.jpg',
478 | width: 526,
479 | height: 440,
480 | box_count: 2,
481 | },
482 | {
483 | id: '460541',
484 | name: 'Jack Sparrow Being Chased',
485 | url: 'https://i.imgflip.com/9vct.jpg',
486 | width: 500,
487 | height: 375,
488 | box_count: 2,
489 | },
490 | {
491 | id: '99683372',
492 | name: 'Sleeping Shaq',
493 | url: 'https://i.imgflip.com/1nck6k.jpg',
494 | width: 640,
495 | height: 631,
496 | box_count: 2,
497 | },
498 | {
499 | id: '101910402',
500 | name: 'Who Would Win?',
501 | url: 'https://i.imgflip.com/1ooaki.jpg',
502 | width: 802,
503 | height: 500,
504 | box_count: 2,
505 | },
506 | {
507 | id: '4173692',
508 | name: 'Scared Cat',
509 | url: 'https://i.imgflip.com/2hgfw.jpg',
510 | width: 620,
511 | height: 464,
512 | box_count: 2,
513 | },
514 | {
515 | id: '61546',
516 | name: 'Brace Yourselves X is Coming',
517 | url: 'https://i.imgflip.com/1bhm.jpg',
518 | width: 622,
519 | height: 477,
520 | box_count: 2,
521 | },
522 | {
523 | id: '6531067',
524 | name: 'See Nobody Cares',
525 | url: 'https://i.imgflip.com/3vzej.jpg',
526 | width: 620,
527 | height: 676,
528 | box_count: 2,
529 | },
530 | {
531 | id: '163573',
532 | name: 'Imagination Spongebob',
533 | url: 'https://i.imgflip.com/3i7p.jpg',
534 | width: 500,
535 | height: 366,
536 | box_count: 2,
537 | },
538 | {
539 | id: '285870',
540 | name: 'Squidward',
541 | url: 'https://i.imgflip.com/64ku.jpg',
542 | width: 500,
543 | height: 750,
544 | box_count: 2,
545 | },
546 | {
547 | id: '61582',
548 | name: 'Creepy Condescending Wonka',
549 | url: 'https://i.imgflip.com/1bim.jpg',
550 | width: 550,
551 | height: 545,
552 | box_count: 2,
553 | },
554 | {
555 | id: '157978092',
556 | name: 'Presidential Alert',
557 | url: 'https://i.imgflip.com/2m20oc.jpg',
558 | width: 920,
559 | height: 534,
560 | box_count: 2,
561 | },
562 | {
563 | id: '61585',
564 | name: 'Bad Luck Brian',
565 | url: 'https://i.imgflip.com/1bip.jpg',
566 | width: 475,
567 | height: 562,
568 | box_count: 2,
569 | },
570 | {
571 | id: '109765',
572 | name: "I'll Just Wait Here",
573 | url: 'https://i.imgflip.com/2cp1.jpg',
574 | width: 491,
575 | height: 550,
576 | box_count: 2,
577 | },
578 | {
579 | id: '53764',
580 | name: 'Peter Parker Cry',
581 | url: 'https://i.imgflip.com/15hg.jpg',
582 | width: 400,
583 | height: 992,
584 | box_count: 4,
585 | },
586 | {
587 | id: '170715647',
588 | name: 'Well Yes, But Actually No',
589 | url: 'https://i.imgflip.com/2tn11b.jpg',
590 | width: 1600,
591 | height: 1218,
592 | box_count: 2,
593 | },
594 | {
595 | id: '14230520',
596 | name: 'Black Girl Wat',
597 | url: 'https://i.imgflip.com/8h0c8.jpg',
598 | width: 599,
599 | height: 626,
600 | box_count: 2,
601 | },
602 | {
603 | id: '61544',
604 | name: 'Success Kid',
605 | url: 'https://i.imgflip.com/1bhk.jpg',
606 | width: 500,
607 | height: 500,
608 | box_count: 2,
609 | },
610 | {
611 | id: '40945639',
612 | name: 'Dr Evil Laser',
613 | url: 'https://i.imgflip.com/odluv.jpg',
614 | width: 500,
615 | height: 405,
616 | box_count: 2,
617 | },
618 | {
619 | id: '61533',
620 | name: 'X All The Y',
621 | url: 'https://i.imgflip.com/1bh9.jpg',
622 | width: 500,
623 | height: 355,
624 | box_count: 2,
625 | },
626 | {
627 | id: '28034788',
628 | name: 'Marvel Civil War 1',
629 | url: 'https://i.imgflip.com/govs4.jpg',
630 | width: 423,
631 | height: 734,
632 | box_count: 2,
633 | },
634 | {
635 | id: '405658',
636 | name: 'Grumpy Cat',
637 | url: 'https://i.imgflip.com/8p0a.jpg',
638 | width: 500,
639 | height: 617,
640 | box_count: 2,
641 | },
642 | {
643 | id: '29617627',
644 | name: 'Look At Me',
645 | url: 'https://i.imgflip.com/hmt3v.jpg',
646 | width: 300,
647 | height: 300,
648 | box_count: 2,
649 | },
650 | {
651 | id: '27920',
652 | name: 'Surprised Koala',
653 | url: 'https://i.imgflip.com/ljk.jpg',
654 | width: 500,
655 | height: 667,
656 | box_count: 2,
657 | },
658 | {
659 | id: '1509839',
660 | name: 'Captain Picard Facepalm',
661 | url: 'https://i.imgflip.com/wczz.jpg',
662 | width: 500,
663 | height: 324,
664 | box_count: 2,
665 | },
666 | {
667 | id: '71428573',
668 | name: 'Say it Again, Dexter',
669 | url: 'https://i.imgflip.com/16iyn1.jpg',
670 | width: 698,
671 | height: 900,
672 | box_count: 2,
673 | },
674 | {
675 | id: '21604248',
676 | name: 'Mugatu So Hot Right Now',
677 | url: 'https://i.imgflip.com/cv1y0.jpg',
678 | width: 620,
679 | height: 497,
680 | box_count: 2,
681 | },
682 | {
683 | id: '176908',
684 | name: 'Shut Up And Take My Money Fry',
685 | url: 'https://i.imgflip.com/3si4.jpg',
686 | width: 500,
687 | height: 281,
688 | box_count: 2,
689 | },
690 | {
691 | id: '444501',
692 | name: 'Maury Lie Detector',
693 | url: 'https://i.imgflip.com/9iz9.jpg',
694 | width: 381,
695 | height: 378,
696 | box_count: 2,
697 | },
698 | {
699 | id: '89655',
700 | name: 'Uncle Sam',
701 | url: 'https://i.imgflip.com/1x6f.jpg',
702 | width: 620,
703 | height: 833,
704 | box_count: 2,
705 | },
706 | {
707 | id: '184801100',
708 | name: 'Me And The Boys',
709 | url: 'https://i.imgflip.com/320xfw.jpg',
710 | width: 720,
711 | height: 476,
712 | box_count: 2,
713 | },
714 | {
715 | id: '61580',
716 | name: 'Too Damn High',
717 | url: 'https://i.imgflip.com/1bik.jpg',
718 | width: 420,
719 | height: 316,
720 | box_count: 2,
721 | },
722 | {
723 | id: '1367068',
724 | name: 'I Should Buy A Boat Cat',
725 | url: 'https://i.imgflip.com/tau4.jpg',
726 | width: 500,
727 | height: 368,
728 | box_count: 2,
729 | },
730 | {
731 | id: '61581',
732 | name: 'Put It Somewhere Else Patrick',
733 | url: 'https://i.imgflip.com/1bil.jpg',
734 | width: 343,
735 | height: 604,
736 | box_count: 2,
737 | },
738 | {
739 | id: '195389',
740 | name: 'Sparta Leonidas',
741 | url: 'https://i.imgflip.com/46rh.jpg',
742 | width: 500,
743 | height: 264,
744 | box_count: 2,
745 | },
746 | {
747 | id: '101716',
748 | name: 'Yo Dawg Heard You',
749 | url: 'https://i.imgflip.com/26hg.jpg',
750 | width: 500,
751 | height: 323,
752 | box_count: 2,
753 | },
754 | {
755 | id: '142921050',
756 | name: 'Car Salesman Slaps Roof Of Car',
757 | url: 'https://i.imgflip.com/2d3al6.jpg',
758 | width: 800,
759 | height: 450,
760 | box_count: 2,
761 | },
762 | {
763 | id: '1202623',
764 | name: 'Keep Calm And Carry On Red',
765 | url: 'https://i.imgflip.com/pry7.jpg',
766 | width: 500,
767 | height: 704,
768 | box_count: 2,
769 | },
770 | {
771 | id: '259680',
772 | name: 'Am I The Only One Around Here',
773 | url: 'https://i.imgflip.com/5kdc.jpg',
774 | width: 500,
775 | height: 348,
776 | box_count: 2,
777 | },
778 | {
779 | id: '100947',
780 | name: 'Matrix Morpheus',
781 | url: 'https://i.imgflip.com/25w3.jpg',
782 | width: 500,
783 | height: 303,
784 | box_count: 2,
785 | },
786 | {
787 | id: '61516',
788 | name: 'Philosoraptor',
789 | url: 'https://i.imgflip.com/1bgs.jpg',
790 | width: 500,
791 | height: 500,
792 | box_count: 2,
793 | },
794 | {
795 | id: '9440985',
796 | name: 'Face You Make Robert Downey Jr',
797 | url: 'https://i.imgflip.com/5mcpl.jpg',
798 | width: 460,
799 | height: 523,
800 | box_count: 2,
801 | },
802 | ];
803 |
--------------------------------------------------------------------------------