From 182083e7c5284b7e373a133dce71eac86cb365f7 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 28 Jun 2020 10:46:00 -0700 Subject: [PATCH] Add animated, bouncing/fading ellipses to indicate activity So that all users can easily see if other players are actively participating in the answering/judging phase or if they have gone totally idle. --- empathy/empathy.css | 47 +++++++++++++++++++++++++++++++++++++ empathy/empathy.jsx | 57 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/empathy/empathy.css b/empathy/empathy.css index 704b54a..9692274 100644 --- a/empathy/empathy.css +++ b/empathy/empathy.css @@ -52,3 +52,50 @@ background-color: var(--accent-color-bright); color: var(--text-fg-on-accent-bright); } + +@keyframes bounce { + 0% { + transform: translateY(0); + animation-timing-function: cubic-bezier(0.333, 0.667, 0.667, 1); + } + 20% { + transform: translateY(-5px); + animation-timing-function: cubic-bezier(0.333, 0, 0,667, 0.333); + } + 40% { + transform: translateY(0); + } + 100% { + transform: translateY(0); + } +} + +.typing span { + font-size: 150%; + line-height: 0; + + display: inline-block; + animation-name: bounce; + animation-duration: 2s; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +.typing span:nth-child(2) { + animation-delay: .2s; +} + +.typing span:nth-child(3) { + animation-delay: .4s; +} + +.typing.active span { + opacity: 1.0; +} + +.typing.idle span { + opacity: 0.0; + transition-property: opacity; + transition-duration: 6s; + transition-delay: 3s; +} diff --git a/empathy/empathy.jsx b/empathy/empathy.jsx index 163b977..143acd9 100644 --- a/empathy/empathy.jsx +++ b/empathy/empathy.jsx @@ -585,9 +585,14 @@ class Ambiguities extends React.PureComponent {
  • - {player} - {this.props.players_judging[player] ? - : null } + {player}{' '} + + {'.'}{'.'}{'.'} +
  • ); })} @@ -760,9 +765,14 @@ class ActivePrompt extends React.PureComponent {
  • - {player} - {this.props.players_answering[player] ? - : null } + {player}{' '} + + {'.'}{'.'}{'.'} +
  • ); })} @@ -954,12 +964,29 @@ class Game extends React.PureComponent { } set_player_answering(player) { + /* Set the player as actively answering now. */ this.setState({ players_answering: { ...this.state.players_answering, [player]: {active: true} } }); + /* And arrange to have them marked idle very shortly. + * + * Note: This timeout is intentionally very, very short. We only + * need it long enough that the browser has latched onto the state + * change to "active" above. We actually use a CSS transition + * delay to control the user-perceptible length of time after + * which an active player appears inactive. + */ + setTimeout(() => { + this.setState({ + players_answering: { + ...this.state.players_answering, + [player]: {active: false} + } + }); + }, 100); } set_answering_idle(value) { @@ -1019,12 +1046,30 @@ class Game extends React.PureComponent { } set_player_judging(player) { + /* Set the player as actively judging now. */ this.setState({ players_judging: { ...this.state.players_judging, [player]: {active: true} } }); + /* And arrange to have them marked idle very shortly. + * + * Note: This timeout is intentionally very, very short. We only + * need it long enough that the browser has latched onto the state + * change to "active" above. We actually use a CSS transition + * delay to control the user-perceptible length of time after + * which an active player appears inactive. + */ + setTimeout(() => { + this.setState({ + players_judging: { + ...this.state.players_judging, + [player]: {active: false} + } + }); + }, 100); + } set_judging_idle(value) { -- 2.43.0