Condense UI labels and align obstacle statistics

This commit is contained in:
2026-09-04 19:12:36 -07:00
parent 52dda12c47
commit 376765dd0f
7 changed files with 61 additions and 26 deletions
+34 -8
View File
@@ -1,13 +1,39 @@
## Features
- [ ] Add a note taking area to store game state between sessions
- [ ] Add an online indicator that displays if a player is connected
- [ ] PvP challenges should linger in the UI after completion so that players can see the result
- [ ] Add hat/gun icons next to player names on the player list to indicate if they're the captain and/or have a gat
- [ ] Replace red/green borders of successful/failed cards with checks and crosses in the upper corner of the card.
## Polish ## Polish
- [x] The character sheet modal popup is narrower than it needs to be on wide screens. I think it could safely be like 90% as wide as the non-modal UI. - [x] Do a pass on condensing overly verbose UI elements. For example, "Current Difficulty" could be replaced by "Difficulty" and "The Obstacle List" could be replaced by "Obstacles"
- [x] Popping out the event log should leave a close button where the "Event Log" open button is, so that you don't have to move your mouse to quickly toggle it. The existing close button can remain. - [ ] Event log button should be the same size and position when expanded and collapsed in all screens
- [x] Use the same vertical UI for the player list in all phases - [x] Align the "Current Difficulty" and "Successes" boxes
- [x] In the admin panel, if a pi-rat doesn't have a name yet, it should show something like 'not chosen yet' rather than the player name - [ ] Don't have dev mode toggling appear in the event log
- [x] In the admin panel, the "Open" and "Copy" buttons should be the same size - [ ] Remove display of current deck size
- [x] Store the player name in local storage and pre-populate it when joining a new game (but don't force it, let the player edit it if they'd prefer a different name) - [ ] Voting status in the between-scenes phase should be visual, not text-based
- [x] If a player tries to rejoin a game that has ended or that they've been kicked from, they should get an error message and it should be removed from the list of re-joinable games - [ ] Players should be able to see who they voted for
- [x] Games should have join codes in addition to join links. Join codes should be a sequence of 5 alphanumeric characters (upper case letters only, no ambiguous letters like 0/O/1/I). Add a panel to the home page for joining a game via code, and display the join code on the admin page - [ ] The "ready" button between scenes is redundant. Allow players to vote, and allow them to change their vote, but once all players have voted, display the result and move on
## Rules
- [ ] Check against rules on correct quantity of of obstacles and obstacle refresh rules
- [ ] Check against the rules on pi-rat hand size and conditions for drawing more cards
- [ ] Assisting other pi-rats should only be available if there are multiple obstacles in the current challenge
- [ ] Checking off personal objectives (gat/name/death) should be handled by group vote rather than adjudication by the deep
- [ ] Double check if PvP obstacles should allow card re-draw
## Unknown - need to clarify what these mean
- [ ] Temporary names
- [ ] Consistent player list order
- [ ] Crew objectives reveal area should be connected to button
## Fixes
- [ ] Make sure that gat descriptions are a) required and b) displayed on the UI
## Words Words Words ## Words Words Words
+11 -6
View File
@@ -236,7 +236,7 @@
padding: 1.25rem; padding: 1.25rem;
background: var(--well); background: var(--well);
display: grid; display: grid;
grid-template-columns: 0.8fr 2fr 1fr 1fr; grid-template-columns: 0.8fr 2fr 2fr;
gap: 1rem; gap: 1rem;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
@@ -335,11 +335,17 @@
color: var(--text-muted); color: var(--text-muted);
} }
.obstacle-value-display { .obstacle-stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
align-self: start; align-self: start;
gap: 0.5rem;
}
.obstacle-value-display {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-start;
align-items: center; align-items: center;
background: color-mix(in srgb, var(--accent) 5%, transparent); background: color-mix(in srgb, var(--accent) 5%, transparent);
border: 1px dashed var(--edge-accent); border: 1px dashed var(--edge-accent);
@@ -348,10 +354,9 @@
} }
.obstacle-successes-display { .obstacle-successes-display {
align-self: start;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-start;
align-items: center; align-items: center;
background: color-mix(in srgb, var(--success) 5%, transparent); background: color-mix(in srgb, var(--success) 5%, transparent);
border: 1px dashed color-mix(in srgb, var(--success) 30%, transparent); border: 1px dashed color-mix(in srgb, var(--success) 30%, transparent);
@@ -361,7 +366,7 @@
.obstacle-successes-display .val-number { .obstacle-successes-display .val-number {
color: var(--success); color: var(--success);
font-size: 1.5rem; font-size: 1.8rem;
} }
.val-label { .val-label {
+2 -2
View File
@@ -41,7 +41,7 @@
e.currentTarget.classList.remove("dragging"); e.currentTarget.classList.remove("dragging");
}} /> }} />
{:else} {:else}
<p class="empty-text text-center">Your hand is empty! (You draw cards when playing cards that match the suit color of the obstacle.)</p> <p class="empty-text text-center">Empty hand. Match an obstacles color to draw cards.</p>
{/each} {/each}
</div> </div>
</div> </div>
@@ -55,7 +55,7 @@
<div class="card glass-panel obstacle-list-card"> <div class="card glass-panel obstacle-list-card">
<div class="card-header"> <div class="card-header">
<h3>🌊 The Obstacle List</h3> <h3>🌊 Obstacles</h3>
<span class="deck-counter">🎴 Deck: {state.game.deck_cards ? JSON.parse(state.game.deck_cards).length : 0} cards left</span> <span class="deck-counter">🎴 Deck: {state.game.deck_cards ? JSON.parse(state.game.deck_cards).length : 0} cards left</span>
</div> </div>
<ObstacleBoard {state} /> <ObstacleBoard {state} />
+5 -5
View File
@@ -170,7 +170,7 @@
</script> </script>
<div class="between-scenes-view text-center"> <div class="between-scenes-view text-center">
<h2>Between Scenes (Scene #{state.game.current_scene_number} Concluded)</h2> <h2>Between Scenes · Scene {state.game.current_scene_number}</h2>
<p class="description">Upkeep and tallying. Nominate a crewmate to Rank Up, redraw hand cards for resting Deep players, and ready up for the next scene.</p> <p class="description">Upkeep and tallying. Nominate a crewmate to Rank Up, redraw hand cards for resting Deep players, and ready up for the next scene.</p>
{#if state.player.is_dead && !state.player.is_ghost && !state.player.needs_reroll} {#if state.player.is_dead && !state.player.is_ghost && !state.player.needs_reroll}
@@ -201,7 +201,7 @@
<div class="between-grid" class:single={state.game.phase !== 'deep_upkeep'}> <div class="between-grid" class:single={state.game.phase !== 'deep_upkeep'}>
<!-- Ranks and Voting Card --> <!-- Ranks and Voting Card -->
<div class="card glass-panel voting-card"> <div class="card glass-panel voting-card">
<h3>1. Pirate Ranking (Voting)</h3> <h3>Rank Up</h3>
<p class="section-desc">Every player (including the Deep) nominates one crewmate who best exemplified pirate qualities in the previous scene. Previous Deep players are ineligible to receive votes.</p> <p class="section-desc">Every player (including the Deep) nominates one crewmate who best exemplified pirate qualities in the previous scene. Previous Deep players are ineligible to receive votes.</p>
{#if state.game.phase === 'deep_upkeep'} {#if state.game.phase === 'deep_upkeep'}
@@ -239,7 +239,7 @@
<!-- Resting Deep Player Card — only the actual hand refresh, during deep_upkeep --> <!-- Resting Deep Player Card — only the actual hand refresh, during deep_upkeep -->
{#if state.game.phase === 'deep_upkeep'} {#if state.game.phase === 'deep_upkeep'}
<div class="card glass-panel deep-rest-card"> <div class="card glass-panel deep-rest-card">
<h3>2. Resting Deep Upkeep</h3> <h3>Refresh Hand</h3>
{#if state.player.role === "deep"} {#if state.player.role === "deep"}
<div class="deep-rest-panel glass-panel"> <div class="deep-rest-panel glass-panel">
@@ -260,7 +260,7 @@
<p class="info-text text-center" style="margin-top: 1rem;">Waiting for the rest of the crew to finish upkeep...</p> <p class="info-text text-center" style="margin-top: 1rem;">Waiting for the rest of the crew to finish upkeep...</p>
{:else} {:else}
<p class="info-text" style="margin-top: 1rem;"> <p class="info-text" style="margin-top: 1rem;">
<strong>Your Hand Size Limit: {maxHandSize} cards.</strong><br/> <strong>Hand Limit: {maxHandSize} cards.</strong><br/>
Drag cards to the "Discard Pile" zone to discard them, or click them to move them. Drag cards to the "Discard Pile" zone to discard them, or click them to move them.
</p> </p>
@@ -307,7 +307,7 @@
{/if} {/if}
<button class="btn btn-primary mt-4 w-full" on:click={confirmRefresh} disabled={confirming || isOverLimit}> <button class="btn btn-primary mt-4 w-full" on:click={confirmRefresh} disabled={confirming || isOverLimit}>
Confirm Hand Refresh Refresh Hand
</button> </button>
{/if} {/if}
</div> </div>
@@ -119,7 +119,7 @@
{/if} {/if}
<div class="sheet-group"> <div class="sheet-group">
<h4>Description:</h4> <h4>Description</h4>
<p><strong>Look:</strong> {target.avatar_look}</p> <p><strong>Look:</strong> {target.avatar_look}</p>
<p><strong>Smell:</strong> {target.avatar_smell}</p> <p><strong>Smell:</strong> {target.avatar_smell}</p>
<p><strong>First Words:</strong> "{target.first_words}"</p> <p><strong>First Words:</strong> "{target.first_words}"</p>
@@ -130,7 +130,7 @@
{#if target.other_like || target.other_hate} {#if target.other_like || target.other_hate}
<div class="sheet-group margin-top"> <div class="sheet-group margin-top">
<h4>What the Crew Thinks:</h4> <h4>Crew Impressions</h4>
{#if target.other_like} {#if target.other_like}
<p><strong>👍 Likes:</strong> "{target.other_like}" <span class="text-muted">{getPlayerName(target.other_like_from_player_id)}</span></p> <p><strong>👍 Likes:</strong> "{target.other_like}" <span class="text-muted">{getPlayerName(target.other_like_from_player_id)}</span></p>
{/if} {/if}
@@ -143,7 +143,7 @@
<!-- Secret techniques are visible only on your own sheet --> <!-- Secret techniques are visible only on your own sheet -->
{#if isSelf} {#if isSelf}
<div class="sheet-group margin-top"> <div class="sheet-group margin-top">
<h4>Assigned Secret Techniques (J/Q/K):</h4> <h4>Secret Techniques</h4>
<ul class="techniques-list-sheet"> <ul class="techniques-list-sheet">
<li><strong>Jack (J):</strong> "{target.tech_jack}"</li> <li><strong>Jack (J):</strong> "{target.tech_jack}"</li>
<li><strong>Queen (Q):</strong> "{target.tech_queen}"</li> <li><strong>Queen (Q):</strong> "{target.tech_queen}"</li>
@@ -86,9 +86,10 @@
<p class="desc">{obs.description}</p> <p class="desc">{obs.description}</p>
</div> </div>
<div class="obstacle-stats">
<!-- Value Display --> <!-- Value Display -->
<div class="obstacle-value-display text-center" use:tooltip={VALUE_HINT}> <div class="obstacle-value-display text-center" use:tooltip={VALUE_HINT}>
<span class="val-label">Current Difficulty</span> <span class="val-label">Difficulty</span>
<span class="val-number"> <span class="val-number">
{#if is_face_active} {#if is_face_active}
{challengedRank !== null ? `${challengedRank} (Rat's Rank)` : "Challenged Rat's Rank"} {challengedRank !== null ? `${challengedRank} (Rat's Rank)` : "Challenged Rat's Rank"}
@@ -104,6 +105,8 @@
<span class="val-number">{success_count} / {state.players.length}</span> <span class="val-number">{success_count} / {state.players.length}</span>
</div> </div>
</div>
{#if is_completed && state.player.role === 'deep'} {#if is_completed && state.player.role === 'deep'}
<div class="clear-obstacle-row text-center"> <div class="clear-obstacle-row text-center">
<button class="btn btn-success btn-full" on:click={clearObstacle}>Clear Obstacle</button> <button class="btn btn-success btn-full" on:click={clearObstacle}>Clear Obstacle</button>
+2 -1
View File
@@ -6,10 +6,11 @@
// - Add a CHANGELOG entry only when a commit changes something players can // - Add a CHANGELOG entry only when a commit changes something players can
// see. Skip refactors, tests, and tooling. Keep wording player-facing. // see. Skip refactors, tests, and tooling. Keep wording player-facing.
export const VERSION = 26; export const VERSION = 27;
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }. // Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
export const CHANGELOG = [ export const CHANGELOG = [
{ version: 27, date: '2026-09-04', changes: ['Shorter labels make the table easier to scan.', 'Difficulty and Successes now line up side by side, including on small screens.'] },
{ {
version: 25, version: 25,
date: '2026-07-10', date: '2026-07-10',