9e9977d5f1
Surface the inactivity-removal countdown the rules promise but the engine never reported. A race within five turns of being auto-removed for inactivity gets a personal warning in its own report; every race within three turns is listed publicly to all participants. - model: Report.PersonalExitWarning + RacesLeavingSoon ([]RaceExitNotice) - fbs: RaceExitNotice table + Report.personal_exit_warning / races_leaving_soon (regenerated Go + TS bindings) - transcoder: encode/decode both fields - engine: ReportExitWarnings fills the recipient's TTL (1..5) and lists other non-extinct races with TTL 1..3, excluding the recipient itself - ui: danger-styled personal banner + "races leaving soon" section (hidden when empty), wired into the report view, EN/RU i18n - docs: rules.txt report-section list, FUNCTIONAL.md 6.4 + RU mirror Voluntary quit and idle timeout share the TTL countdown and are not distinguished, per the agreed scope.
71 lines
2.0 KiB
Svelte
71 lines
2.0 KiB
Svelte
<!--
|
|
Report View — races leaving soon section. Surfaces the public
|
|
`racesLeavingSoon` projection: every other race within three turns of
|
|
being auto-removed for inactivity, with the number of turns each has
|
|
left. This is the public counterpart to the personal exit-warning
|
|
banner the report view renders at the top for the local race.
|
|
|
|
Unlike the other report sections, this one hides entirely when the
|
|
list is empty rather than showing an empty-state line: an absent
|
|
notice is the normal, healthy case for an active game, so a permanent
|
|
"no races leaving" row would be noise. The section's TOC entry stays
|
|
registered; clicking it while the section is hidden is a silent no-op
|
|
through the table-of-contents' existing `getElementById` guard.
|
|
-->
|
|
<script lang="ts">
|
|
import { getContext } from "svelte";
|
|
|
|
import { i18n } from "$lib/i18n/index.svelte";
|
|
import {
|
|
RENDERED_REPORT_CONTEXT_KEY,
|
|
type RenderedReportSource,
|
|
} from "$lib/rendered-report.svelte";
|
|
|
|
const rendered = getContext<RenderedReportSource | undefined>(
|
|
RENDERED_REPORT_CONTEXT_KEY,
|
|
);
|
|
const report = $derived(rendered?.report ?? null);
|
|
const rows = $derived(report?.racesLeavingSoon ?? []);
|
|
</script>
|
|
|
|
{#if rows.length > 0}
|
|
<section
|
|
id="report-race-exit-warnings"
|
|
class="grid-section"
|
|
data-testid="report-section-race-exit-warnings"
|
|
>
|
|
<h2>{i18n.t("game.report.section.race_exit_warnings.title")}</h2>
|
|
|
|
<ul class="notices" data-testid="race-exit-warnings-list">
|
|
{#each rows as r (r.race)}
|
|
<li data-testid="race-exit-warnings-row" data-race={r.race}>
|
|
{i18n.t("game.report.section.race_exit_warnings.notice", {
|
|
race: r.race,
|
|
turns: String(r.turnsLeft),
|
|
})}
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
</section>
|
|
{/if}
|
|
|
|
<style>
|
|
.grid-section h2 {
|
|
margin: 0 0 0.5rem;
|
|
font-size: 1.05rem;
|
|
color: var(--color-text);
|
|
}
|
|
.notices {
|
|
margin: 0;
|
|
padding-left: 1.1rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.3rem;
|
|
font-size: 0.9rem;
|
|
color: var(--color-warning);
|
|
}
|
|
.notices li {
|
|
margin: 0;
|
|
}
|
|
</style>
|