Add modal name popup when a Pi-Rat earns a Name

When a Pi-Rat completes their second objective and ranks up, they now
get a blocking modal popup (NameModal.svelte, rendered by Dashboard
across all phases) to claim their Pirate Name, rather than an optional
box buried in their character sheet. Removed the old inline prompt-box
and its handler from CharacterSheet.svelte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 09:05:02 -07:00
parent f40724c9d2
commit 45fefc0c71
4 changed files with 91 additions and 26 deletions

View File

@@ -0,0 +1,88 @@
<script>
import { apiRequest } from '../lib/api';
export let state;
let newNameInput = '';
let error = '';
let submitting = false;
async function submitNewName() {
if (!newNameInput.trim() || submitting) return;
error = '';
submitting = true;
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/set-name`, 'POST', {
new_name: newNameInput.trim()
});
newNameInput = '';
} catch (e) {
error = e.message;
} finally {
submitting = false;
}
}
function onKeydown(e) {
if (e.key === 'Enter') submitNewName();
}
</script>
{#if state.player.needs_name}
<div class="modal-backdrop">
<div class="modal-box glass-panel">
<h3>🏴‍☠️ You Earned a Name!</h3>
<p class="info-text">
You completed your second objective and ranked up. No more going by your smell — what is your new Pirate Name?
</p>
{#if error}
<div class="alert alert-danger">{error}</div>
{/if}
<input
type="text"
bind:value={newNameInput}
class="input-field"
placeholder="Enter your Pirate Name..."
on:keydown={onKeydown}
autofocus
>
<button
class="btn btn-gold btn-full"
on:click={submitNewName}
disabled={!newNameInput.trim() || submitting}
>
Claim Name
</button>
</div>
</div>
{/if}
<style>
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 2000;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: color-mix(in srgb, var(--bg-deep) 70%, transparent);
backdrop-filter: blur(6px);
}
.modal-box {
max-width: 440px;
width: 100%;
padding: 1.75rem;
border: 1px solid var(--edge);
border-radius: var(--radius-md);
box-shadow: var(--shadow-deep);
text-align: center;
}
.modal-box h3 {
margin-top: 0;
}
.modal-box .input-field {
width: 100%;
margin: 0.75rem 0;
}
</style>

View File

@@ -5,7 +5,6 @@
export let state;
let error = '';
let newNameInput = '';
let pvpOpponentId = '';
let pvpCard = '';
@@ -21,19 +20,6 @@
// What the chosen duel card becomes as a temporary Obstacle for the defender
$: pvpCardObstacle = cardObstacleInfo(pvpCard, $obstacleTable);
async function submitNewName() {
if (!newNameInput.trim()) return;
error = '';
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/set-name`, 'POST', {
new_name: newNameInput.trim()
});
newNameInput = '';
} catch(e) {
error = e.message;
}
}
async function createPvp() {
error = '';
try {
@@ -83,17 +69,6 @@
</div>
{/if}
{#if state.player.needs_name}
<div class="prompt-box accent">
<h4>🏴‍☠️ You Earned a Name!</h4>
<p class="info-text" style="margin-bottom: 0.5rem;">You completed your second objective and ranked up! What is your new Pirate Name?</p>
<div class="input-row">
<input type="text" bind:value={newNameInput} class="input-field" placeholder="Enter new name...">
<button class="btn btn-gold" on:click={submitNewName} disabled={!newNameInput.trim()}>Claim Name</button>
</div>
</div>
{/if}
{#if state.player.tax_banned}
<div class="prompt-box danger text-center">
<p class="info-text" style="margin: 0; font-size: 0.9rem;">🚫 You failed a refused Tax — no more Gat/Name Taxes for you this scene.</p>

View File

@@ -16,6 +16,7 @@
import RecruitPhase from '../components/RecruitPhase.svelte';
import GameOverPhase from '../components/GameOverPhase.svelte';
import EventLog from '../components/EventLog.svelte';
import NameModal from '../components/NameModal.svelte';
export let params = {};
let gameId = params.id;
@@ -210,6 +211,7 @@
</div>
<EventLog {state} />
<NameModal {state} />
{:else if !error}
<div class="loading-container">
<p>Loading game state...</p>