From: Carl Worth Date: Fri, 6 Mar 2026 13:14:16 +0000 (-0500) Subject: Fix race condition in handling of stuck button X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=12d700d225e070531b53da4913f9403a9d011a6d;p=lmno.games Fix race condition in handling of stuck button Which was causing the button to stay stuck (ha!). The new logic lets the SEE event be the single source of truth. While fixing this, fix the styling of the button to be more clear, specifically making it appear as a button saying "I'm stuck" where it was previously blank which made its use non-obvious. --- diff --git a/letterrip/letterrip.css b/letterrip/letterrip.css index 561ede8..27498ce 100644 --- a/letterrip/letterrip.css +++ b/letterrip/letterrip.css @@ -34,15 +34,19 @@ .controls button { padding: 0.4em 1em; - border: 2px solid #555; border-radius: 4px; - background: transparent; cursor: pointer; font-size: 1em; } -.controls button:hover { - background: #eee; +.controls button.stuck-btn { + background: #f0f0f0; + border: 2px solid #999; + color: #333; +} + +.controls button.stuck-btn:hover { + background: #e0e0e0; } .controls button.stuck-active { @@ -51,26 +55,28 @@ color: white; } -.controls button.complete-btn { - background: #27ae60; - border-color: #27ae60; - color: white; -} - -.controls button.complete-btn:disabled { - background: #95a5a6; - border-color: #95a5a6; - cursor: default; -} - .controls button.join-btn { background: #3498db; - border-color: #3498db; + border: 2px solid #3498db; color: white; font-size: 1.1em; padding: 0.5em 1.5em; } +/* "Letter Rip" button appears inside the rack when all tiles are + placed and all words are valid. */ +.letter-rip-btn { + padding: 0.5em 1.5em; + background: #27ae60; + border: 2px solid #27ae60; + border-radius: 6px; + color: white; + font-size: 1.2em; + font-weight: bold; + cursor: pointer; + margin: auto; +} + /* Tile styling */ .tile { display: inline-flex; diff --git a/letterrip/letterrip.jsx b/letterrip/letterrip.jsx index 17f5cfd..da78d90 100644 --- a/letterrip/letterrip.jsx +++ b/letterrip/letterrip.jsx @@ -241,10 +241,10 @@ function GameInfo(props) { } function PlayerList(props) { - const { player_info, other_players, all_stuck } = props; + const { player_info, other_players, stuck_players } = props; if (!player_info.id) return null; - const stuck_set = new Set(all_stuck); + const stuck_set = new Set(stuck_players); const render_player = (name, key) => ( @@ -317,7 +317,7 @@ class Game extends React.Component { grid: {}, rack: [], stuck: false, - all_stuck: [], + stuck_players: [], bag_remaining: null, game_over: false, winner: null, @@ -375,7 +375,11 @@ class Game extends React.Component { } receive_stuck(data) { - this.setState({ all_stuck: data.stuck }); + const my_name = this.state.player_info.name; + this.setState({ + stuck_players: data.stuck, + stuck: data.stuck.indexOf(my_name) >= 0 + }); } receive_game_over(data) { @@ -401,11 +405,7 @@ class Game extends React.Component { } async toggle_stuck() { - const response = await fetch_post_json("stuck"); - if (response.ok) { - const data = await response.json(); - this.setState({ stuck: data.stuck }); - } + await fetch_post_json("stuck"); } async declare_complete() { @@ -577,7 +577,7 @@ class Game extends React.Component { , + stuck_players={state.stuck_players} />, state.game_over ? (
@@ -596,24 +596,19 @@ class Game extends React.Component { state.joined && !state.game_over ? (
- {state.bag_remaining !== null ? ( - {state.bag_remaining} tiles remaining in bag + {state.bag_remaining} tiles in bag ) : null}
) : null, state.joined ? this.render_board(analysis, invalid_cells, unconnected_cells) : null, - state.joined ? this.render_rack() : null, + state.joined ? this.render_rack(can_complete) : null, state.blank_pending ? ( ); })} - {rack.length === 0 ? Drag tiles here : null} + {can_complete ? ( + + ) : null}
); }