Mid-game invite links and a surprise-report slip
The masthead's room code is now a button: one click copies the /join link, which seats newcomers in a waiting room and the gallery once the boards flip. And a 🐞 report opens a two-question slip — what happened, what was expected — that lands in feedback.jsonl beside the rooms with the room code, move number, round, and rules rev attached, so any surprise can be replayed to its exact moment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
a1fdb37c54
commit
553754a596
@@ -1179,6 +1179,23 @@
|
||||
|
||||
/** The preferences slip (client-side taste, saved on this device). */
|
||||
let prefsOpen = $state(false);
|
||||
/** The bug-report slip: what happened vs. what was expected. The room
|
||||
* code and move number ride along server-side, pinning the moment in
|
||||
* the ledger for replay. */
|
||||
let feedbackOpen = $state(false);
|
||||
let fbHappened = $state("");
|
||||
let fbExpected = $state("");
|
||||
let fbSent = $state(false);
|
||||
function submitFeedback() {
|
||||
net.sendFeedback(fbHappened.trim(), fbExpected.trim());
|
||||
fbSent = true;
|
||||
setTimeout(() => {
|
||||
feedbackOpen = false;
|
||||
fbSent = false;
|
||||
fbHappened = "";
|
||||
fbExpected = "";
|
||||
}, 1600);
|
||||
}
|
||||
|
||||
/** First tap of marching the Democratic Monster onto YOURSELF: warn once. */
|
||||
let dmWarnCell = $state<string | null>(null);
|
||||
@@ -1360,7 +1377,10 @@
|
||||
<button class="mast-leave" onclick={() => local.leave()}>set the game aside</button>
|
||||
<button class="mast-leave" onclick={() => local.abandon()}>abandon game</button>
|
||||
{:else if net.roomId}
|
||||
<span class="mast-room">{net.spectating ? "watching" : "room"} <b>{net.roomId}</b></span>
|
||||
<button class="mast-room" title="copy the invite link — friends can join, or watch once it's begun"
|
||||
onclick={copyInvite}>
|
||||
{net.spectating ? "watching" : "room"} <b>{net.roomId}</b>{inviteCopied ? " — link copied!" : ""}
|
||||
</button>
|
||||
{#if net.audience > 0}
|
||||
<span class="mast-audience" title="the Peanut Gallery">👁 {net.audience}</span>
|
||||
{/if}
|
||||
@@ -1368,6 +1388,8 @@
|
||||
<button class="mast-leave" onclick={() => net.requestTransferCode()}>transfer seat</button>
|
||||
{/if}
|
||||
<button class="mast-leave" onclick={() => net.leave()}>{net.spectating ? "leave the gallery" : "leave table"}</button>
|
||||
<button class="mast-leave" title="something behaved unexpectedly? tell the wizards"
|
||||
onclick={() => (feedbackOpen = true)}>🐞 report</button>
|
||||
{/if}
|
||||
<button class="mast-leave" class:mast-help-solo={!net.roomId} onclick={() => { helpTab = "play"; showHelp = true; }}>
|
||||
help & rules
|
||||
@@ -1462,6 +1484,35 @@
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if feedbackOpen && net.roomId}
|
||||
<div class="scrim attack-scrim" role="button" tabindex="-1"
|
||||
onclick={() => (feedbackOpen = false)} onkeydown={() => {}}>
|
||||
<div class="attack-notice prefs-slip" role="dialog" aria-label="report a surprise" tabindex="-1"
|
||||
onclick={(ev) => ev.stopPropagation()} onkeydown={() => {}}>
|
||||
<div class="attack-title">Something unexpected?</div>
|
||||
{#if fbSent}
|
||||
<p class="fb-thanks">Recorded beside the room's ledger — thank you. The wizards will study the moment.</p>
|
||||
{:else}
|
||||
<label class="fb-field">
|
||||
<span>What happened?</span>
|
||||
<textarea bind:value={fbHappened} rows="3" maxlength="2000"
|
||||
placeholder="e.g. my fireball hit but no damage was taken"></textarea>
|
||||
</label>
|
||||
<label class="fb-field">
|
||||
<span>What did you expect?</span>
|
||||
<textarea bind:value={fbExpected} rows="3" maxlength="2000"
|
||||
placeholder="e.g. 5 points of damage"></textarea>
|
||||
</label>
|
||||
<p class="fb-note">The room code and move number ride along automatically.</p>
|
||||
<div class="attack-actions">
|
||||
<button class="stamp primary" disabled={!fbHappened.trim()} onclick={submitFeedback}>Send it</button>
|
||||
<button class="hint-cancel" onclick={() => (feedbackOpen = false)}>never mind</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if prefsOpen}
|
||||
<div class="scrim attack-scrim" role="button" tabindex="-1"
|
||||
onclick={() => (prefsOpen = false)} onkeydown={() => {}}>
|
||||
@@ -2619,8 +2670,33 @@
|
||||
letter-spacing: 0.06em;
|
||||
color: #6b6454;
|
||||
}
|
||||
.mast-room { margin-left: auto; font-size: 0.85rem; color: #a49c86; }
|
||||
.mast-room {
|
||||
margin-left: auto;
|
||||
font-size: 0.85rem;
|
||||
color: #a49c86;
|
||||
background: none;
|
||||
border: none;
|
||||
font-family: inherit;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mast-room b { color: #e9e1cb; letter-spacing: 0.12em; }
|
||||
.fb-field { display: block; margin: 0.5rem 0; }
|
||||
.fb-field span { display: block; margin-bottom: 0.2rem; color: #6b5a41; }
|
||||
.fb-field textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
border: 1px solid #8a7a5e;
|
||||
border-radius: 4px;
|
||||
background: #f3ecd8;
|
||||
color: #43331f;
|
||||
resize: vertical;
|
||||
}
|
||||
.fb-note { font-size: 0.8rem; color: #6b5a41; font-style: italic; }
|
||||
.fb-thanks { color: #43331f; padding: 0.6rem 0; }
|
||||
.mast-audience { font-size: 0.85rem; color: #a49c86; white-space: nowrap; }
|
||||
.mind-read { max-width: min(92vw, 46rem); }
|
||||
.caution-reason { padding: 0.15rem 0; }
|
||||
|
||||
Reference in New Issue
Block a user