.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 {
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;
}
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) => (
<span key={key}>
grid: {},
rack: [],
stuck: false,
- all_stuck: [],
+ stuck_players: [],
bag_remaining: null,
game_over: false,
winner: null,
}
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) {
}
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() {
<PlayerList key="pl"
player_info={state.player_info}
other_players={state.other_players}
- all_stuck={state.all_stuck} />,
+ stuck_players={state.stuck_players} />,
state.game_over ? (
<div key="go" className="game-over-banner">
state.joined && !state.game_over ? (
<div key="ctrl" className="controls">
<button
- className={state.stuck ? "stuck-active" : ""}
+ className={"stuck-btn" + (state.stuck ? " stuck-active" : "")}
onClick={() => this.toggle_stuck()}>
{state.stuck ? "Stuck!" : "I'm Stuck"}
</button>
- <button className="complete-btn"
- disabled={!can_complete}
- onClick={() => this.declare_complete()}>
- Done!
- </button>
{state.bag_remaining !== null ? (
- <span className="bag-count">{state.bag_remaining} tiles remaining in bag</span>
+ <span className="bag-count">{state.bag_remaining} tiles in bag</span>
) : null}
</div>
) : 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 ? (
<BlankTileModal
);
}
- render_rack() {
+ render_rack(can_complete) {
const { rack, tiles, rack_drag_over } = this.state;
let className = "tile-rack";
if (rack_drag_over) className += " drag-over";
onClick={null} />
);
})}
- {rack.length === 0 ? <span style={{color:"#999",padding:"8px"}}>Drag tiles here</span> : null}
+ {can_complete ? (
+ <button className="letter-rip-btn"
+ onClick={() => this.declare_complete()}>
+ Letter Rip
+ </button>
+ ) : null}
</div>
);
}