From 53c8c6ba09301563293750e1010ca1ac8dd05590 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 7 Jun 2020 11:56:35 -0700 Subject: [PATCH] Initial framework for an Empathy game This starts with the generic code, (grabbed from Scribe), for displaying the game INFO, (with a button for copying the link), and the list of players that are in the game. It also provides a form for submitting a category, but that is still inert for now. --- empathy/.gitignore | 1 + empathy/Makefile | 12 +++ empathy/empathy.css | 1 + empathy/empathy.jsx | 217 ++++++++++++++++++++++++++++++++++++++++++++ empathy/index.html | 36 ++++++++ 5 files changed, 267 insertions(+) create mode 100644 empathy/.gitignore create mode 100644 empathy/Makefile create mode 100644 empathy/empathy.css create mode 100644 empathy/empathy.jsx create mode 100644 empathy/index.html diff --git a/empathy/.gitignore b/empathy/.gitignore new file mode 100644 index 0000000..053da87 --- /dev/null +++ b/empathy/.gitignore @@ -0,0 +1 @@ +empathy.js diff --git a/empathy/Makefile b/empathy/Makefile new file mode 100644 index 0000000..9f07401 --- /dev/null +++ b/empathy/Makefile @@ -0,0 +1,12 @@ +# Defer all targets up to the upper-level +# +# This requires two recipes. The first to cover the case of no +# explicit target specifed (so when invoked as "make" we call "make" +# at the upper-level) and then a .DEFAULT recipe to pass any explicit +# target up as well, (so that an invocation of "make foo" results in a +# call to "make foo" above. +all: + $(MAKE) -C .. + +.DEFAULT: + $(MAKE) -C .. $@ diff --git a/empathy/empathy.css b/empathy/empathy.css new file mode 100644 index 0000000..e8a317e --- /dev/null +++ b/empathy/empathy.css @@ -0,0 +1 @@ +/* Nothing to see here yet. */ diff --git a/empathy/empathy.jsx b/empathy/empathy.jsx new file mode 100644 index 0000000..9ebe9f3 --- /dev/null +++ b/empathy/empathy.jsx @@ -0,0 +1,217 @@ +function undisplay(element) { + element.style.display="none"; +} + +function add_message(severity, message) { + message = `
+× +${message} +
`; + const message_area = document.getElementById('message-area'); + message_area.insertAdjacentHTML('beforeend', message); +} + +/********************************************************* + * Handling server-sent event stream * + *********************************************************/ + +const events = new EventSource("events"); + +events.onerror = function(event) { + if (event.target.readyState === EventSource.CLOSED) { + setTimeout(() => { + add_message("danger", "Connection to server lost."); + }, 1000); + } +}; + +events.addEventListener("game-info", event => { + const info = JSON.parse(event.data); + + window.game.set_game_info(info); +}); + +events.addEventListener("player-info", event => { + const info = JSON.parse(event.data); + + window.game.set_player_info(info); +}); + +events.addEventListener("player-enter", event => { + const info = JSON.parse(event.data); + + window.game.set_other_player_info(info); +}); + +events.addEventListener("player-update", event => { + const info = JSON.parse(event.data); + + if (info.id === window.game.state.player_info.id) + window.game.set_player_info(info); + else + window.game.set_other_player_info(info); +}); + +/********************************************************* + * Game and supporting classes * + *********************************************************/ + +function copy_to_clipboard(id) +{ + const tmp = document.createElement("input"); + tmp.setAttribute("value", document.getElementById(id).innerHTML); + document.body.appendChild(tmp); + tmp.select(); + document.execCommand("copy"); + document.body.removeChild(tmp); +} + +function GameInfo(props) { + if (! props.id) + return null; + + return ( +
+ {props.id} + {" "} + Share this link to invite friends:{" "} + {props.url} + {" "} + +
+ ); +} + +function PlayerInfo(props) { + if (! props.player.id) + return null; + + return ( +
+ Players: + {props.player.name} + {props.other_players.map(other => ( + + {", "} + {other.name} + + ))} +
+ ); +} + +function fetch_method_json(method, api = '', data = {}) { + const response = fetch(api, { + method: method, + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + return response; +} + +function fetch_post_json(api = '', data = {}) { + return fetch_method_json('POST', api, data); +} + +async function fetch_put_json(api = '', data = {}) { + return fetch_method_json('PUT', api, data); +} + +function CategoryRequest(props) { + return ( +
+

Submit a Category

+

+ Suggest a category to play with your friends. Don't forget to + include the number of items for each person to submit. +

+ +
+
+ + +
+ +
+ +
+ +
+
+ ); +} + +class Game extends React.Component { + constructor(props) { + super(props); + this.state = { + game_info: {}, + player_info: {}, + other_players: [], + }; + } + + set_game_info(info) { + this.setState({ + game_info: info + }); + } + + set_player_info(info) { + this.setState({ + player_info: info + }); + } + + set_other_player_info(info) { + const other_players_copy = [...this.state.other_players]; + const idx = other_players_copy.findIndex(o => o.id === info.id); + if (idx >= 0) { + other_players_copy[idx] = info; + } else { + other_players_copy.push(info); + } + this.setState({ + other_players: other_players_copy + }); + } + + render() { + const state = this.state; + + return [ + , + , +

, + + ]; + } +} + +ReactDOM.render( window.game = me} + />, document.getElementById("empathy")); diff --git a/empathy/index.html b/empathy/index.html new file mode 100644 index 0000000..d250dc8 --- /dev/null +++ b/empathy/index.html @@ -0,0 +1,36 @@ + + + + + + + The Game of Empires + + + + + + + + +
+ +

The Game of Empathy

+ +

+ You don't need to be right, you just need to agree with your + friends. +

+ +
+
+ +
+ +
+ +
+ + -- 2.43.0