Declutter the challenge panel and obstacle titles (v4)
Per playtest feedback: - Drop the per-challenge 'Plays:' line — redundant with the card column and the event log (also removes the now-unused chPlays const). - Drop the 'Attempted by … drag a card … assist' how-to paragraph; players know the basics, and the challenge header already names who's challenged. - Replace the 'Red/Black Obstacle · match to draw' tag with the original card in the title (e.g. '5♣ — Loitering Mermaid'), and color the title by suit. The left border already marks color; the dead .obstacle-color-tag CSS is removed. Suit glyphs in the title use plain text symbols (not SUIT_EMOJI) so they take the theme-aware suit color and stay readable on the dark panel. Verified in light and dark. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -241,43 +241,6 @@
|
|||||||
box-shadow: 0 0 0 2px var(--danger);
|
box-shadow: 0 0 0 2px var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obstacle color (red/black) — fixed by the original card; matching it draws back */
|
|
||||||
.obstacle-color-tag {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.35rem;
|
|
||||||
margin-bottom: 0.4rem;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
font-weight: 700;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.03em;
|
|
||||||
padding: 0.12rem 0.5rem;
|
|
||||||
border-radius: 999px;
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
.obstacle-color-tag::before {
|
|
||||||
content: '';
|
|
||||||
width: 0.6rem;
|
|
||||||
height: 0.6rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.obstacle-color-tag.red {
|
|
||||||
color: var(--suit-red);
|
|
||||||
background: color-mix(in srgb, var(--suit-red) 14%, transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.obstacle-color-tag.red::before { background: var(--suit-red); }
|
|
||||||
|
|
||||||
.obstacle-color-tag.black {
|
|
||||||
color: var(--suit-black);
|
|
||||||
background: color-mix(in srgb, var(--suit-black) 14%, transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.obstacle-color-tag.black::before { background: var(--suit-black); }
|
|
||||||
|
|
||||||
.suit-badge {
|
.suit-badge {
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
@@ -298,6 +261,13 @@
|
|||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The title and its "K♦" card-code prefix take the Obstacle's fixed suit color
|
||||||
|
(red border on the left already marks color, so the old tag is gone). */
|
||||||
|
.suit-h .obstacle-details h4, .suit-d .obstacle-details h4 { color: var(--suit-red); }
|
||||||
|
.suit-c .obstacle-details h4, .suit-s .obstacle-details h4 { color: var(--suit-black); }
|
||||||
|
|
||||||
|
.obs-card-code { opacity: 0.8; }
|
||||||
|
|
||||||
.obstacle-details .in-challenge-tag {
|
.obstacle-details .in-challenge-tag {
|
||||||
color: var(--deep);
|
color: var(--deep);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|||||||
@@ -95,7 +95,6 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each openChallenges as ch}
|
{#each openChallenges as ch}
|
||||||
{@const chPlays = JSON.parse(ch.plays || '[]')}
|
|
||||||
{@const chObstacleIds = JSON.parse(ch.obstacle_ids || '[]')}
|
{@const chObstacleIds = JSON.parse(ch.obstacle_ids || '[]')}
|
||||||
<div class="challenge-item">
|
<div class="challenge-item">
|
||||||
<div class="challenge-head">
|
<div class="challenge-head">
|
||||||
@@ -127,10 +126,6 @@
|
|||||||
Temporary Obstacle: <strong use:tooltip={{ html: cardTooltipHtml(ch.temp_card, $obstacleTable) }}>{getCardDisplay(ch.temp_card)}</strong> — {playerName(ch.acting_player_id)} must answer it!
|
Temporary Obstacle: <strong use:tooltip={{ html: cardTooltipHtml(ch.temp_card, $obstacleTable) }}>{getCardDisplay(ch.temp_card)}</strong> — {playerName(ch.acting_player_id)} must answer it!
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p class="info-text" style="margin: 0.5rem 0 0 0;">
|
|
||||||
Attempted by <strong>{playerName(ch.acting_player_id)}</strong>{ch.acting_player_id !== ch.target_player_id ? ` (took it over via ${ch.tax_type === 'gat' ? 'Gat' : 'Name'} Tax)` : ''}.
|
|
||||||
Drag a card onto an Obstacle below to play it. Other Pi-Rats may assist (assistants don't draw back).
|
|
||||||
</p>
|
|
||||||
<div class="challenge-obstacles">
|
<div class="challenge-obstacles">
|
||||||
{#each chObstacleIds as oid}
|
{#each chObstacleIds as oid}
|
||||||
{@const obs = state.obstacles.find(o => o.id === oid)}
|
{@const obs = state.obstacles.find(o => o.id === oid)}
|
||||||
@@ -142,12 +137,6 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if chPlays.length > 0}
|
|
||||||
<p class="info-text" style="margin: 0.5rem 0 0 0; font-size: 0.85rem;">
|
|
||||||
Plays: {chPlays.map(p => `${p.player_name}: ${getCardDisplay(p.card)} ${p.success ? '✔' : '✘'}`).join(' · ')}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Tax: pending request aimed at me -->
|
<!-- Tax: pending request aimed at me -->
|
||||||
{#if ch.tax_state === 'requested'}
|
{#if ch.tax_state === 'requested'}
|
||||||
{#if myTaxRequest && myTaxRequest.id === ch.id}
|
{#if myTaxRequest && myTaxRequest.id === ch.id}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { apiRequest } from '../../lib/api';
|
import { apiRequest } from '../../lib/api';
|
||||||
import { isJoker } from '../../lib/cards';
|
import { isJoker, cardValue } from '../../lib/cards';
|
||||||
import { tooltip } from '../../lib/tooltip';
|
import { tooltip } from '../../lib/tooltip';
|
||||||
import Card from '../Card.svelte';
|
import Card from '../Card.svelte';
|
||||||
|
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
export let obs;
|
export let obs;
|
||||||
export let embedded = false; // rendered inside the Challenge panel — skip the "in challenge" flag
|
export let embedded = false; // rendered inside the Challenge panel — skip the "in challenge" flag
|
||||||
|
|
||||||
const COLOR_HINT = "An Obstacle's color is fixed by its original card and never changes, no matter what's played on it. "
|
// Plain (text-presentation) suit glyphs so they inherit the title's suit color,
|
||||||
+ 'Beat the difficulty with a card of any suit to pass — but play a card of the matching color (red/black) '
|
// unlike SUIT_EMOJI which renders as fixed-color emoji.
|
||||||
+ 'to also draw one back into your hand.';
|
const SUIT_CHAR = { C: '♣', S: '♠', H: '♥', D: '♦' };
|
||||||
const VALUE_HINT = 'The number to beat. Set by the most recent card played on the column — or the original card '
|
const VALUE_HINT = 'The number to beat. Set by the most recent card played on the column — or the original card '
|
||||||
+ 'until one is played. (Color stays fixed to the original.)';
|
+ 'until one is played. (Color stays fixed to the original.)';
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
$: success_count = column_cards.filter(c => c.success).length;
|
$: success_count = column_cards.filter(c => c.success).length;
|
||||||
$: is_completed = success_count >= state.players.length;
|
$: is_completed = success_count >= state.players.length;
|
||||||
$: in_challenge = openChallenges.some(c => JSON.parse(c.obstacle_ids || '[]').includes(obs.id));
|
$: in_challenge = openChallenges.some(c => JSON.parse(c.obstacle_ids || '[]').includes(obs.id));
|
||||||
$: is_red = ['H', 'D'].includes(obs.suit);
|
$: cardCodeLabel = `${cardValue(obs.original_card)}${SUIT_CHAR[obs.suit] || ''}`;
|
||||||
$: is_face_active = ['J', 'Q', 'K'].includes(active_card_code.slice(0, -1));
|
$: is_face_active = ['J', 'Q', 'K'].includes(active_card_code.slice(0, -1));
|
||||||
|
|
||||||
// A face-card Obstacle is worth the challenged Rat's Rank. When this Obstacle is
|
// A face-card Obstacle is worth the challenged Rat's Rank. When this Obstacle is
|
||||||
@@ -82,10 +82,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="obstacle-details">
|
<div class="obstacle-details">
|
||||||
<h4>{obs.title} {#if in_challenge && !embedded}<span class="in-challenge-tag">⚔️ In Challenge</span>{/if}</h4>
|
<h4><span class="obs-card-code">{cardCodeLabel}</span> — {obs.title} {#if in_challenge && !embedded}<span class="in-challenge-tag">⚔️ In Challenge</span>{/if}</h4>
|
||||||
<span class="obstacle-color-tag {is_red ? 'red' : 'black'}" use:tooltip={COLOR_HINT}>
|
|
||||||
{is_red ? 'Red' : 'Black'} obstacle · match to draw
|
|
||||||
</span>
|
|
||||||
<p class="desc">{obs.description}</p>
|
<p class="desc">{obs.description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,17 @@
|
|||||||
// - 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 = 3;
|
export const VERSION = 4;
|
||||||
|
|
||||||
// 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: 4,
|
||||||
|
date: '2026-06-15',
|
||||||
|
changes: [
|
||||||
|
'Tidied the Challenge panel: dropped the redundant “Plays” list and the how-to-play blurb. Each Obstacle now leads with its card (e.g. “K♦”) in the title, colored by suit.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
version: 3,
|
version: 3,
|
||||||
date: '2026-06-15',
|
date: '2026-06-15',
|
||||||
|
|||||||
Reference in New Issue
Block a user