diff --git a/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts b/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts new file mode 100644 index 0000000..b414c44 --- /dev/null +++ b/ui/frontend/src/lib/active-view/table-battles-state.svelte.ts @@ -0,0 +1,34 @@ +// F8-11 battles table — module-level sort rune. +// +// Held outside the component so the user's sort choice survives the +// component being unmounted (row click → battle viewer → back to the +// table). Held in memory only; an F5 reloads the report and the +// defaults take over. + +export type BattlesSortColumn = "planet" | "shots"; + +export type BattlesSortDirection = "asc" | "desc"; + +export interface BattlesTableState { + sortColumn: BattlesSortColumn; + sortDirection: BattlesSortDirection; +} + +const DEFAULT_STATE: BattlesTableState = { + sortColumn: "shots", + sortDirection: "desc", +}; + +export const battlesTableState: BattlesTableState = $state({ + ...DEFAULT_STATE, +}); + +/** + * resetBattlesTableState restores every field to its default value. + * Production code never calls it; the Vitest harness uses it from + * `beforeEach` to keep cases independent (the rune is a module-level + * singleton that otherwise carries state across test boundaries). + */ +export function resetBattlesTableState(): void { + Object.assign(battlesTableState, DEFAULT_STATE); +} diff --git a/ui/frontend/src/lib/active-view/table-battles.svelte b/ui/frontend/src/lib/active-view/table-battles.svelte new file mode 100644 index 0000000..36e70cc --- /dev/null +++ b/ui/frontend/src/lib/active-view/table-battles.svelte @@ -0,0 +1,226 @@ + + + + + + {i18n.t("game.table.battles.title")} + + + {#if !reportLoaded} + + {:else if battles.length === 0} + + {:else} + + + + {#each COLUMNS as column (column)} + + toggleSort(column)} + > + {i18n.t(COLUMN_LABELS[column])} + {#if persistent.sortColumn === column} + + {persistent.sortDirection === "asc" ? "▲" : "▼"} + + {/if} + + + {/each} + + + + {#each sorted as b (b.id)} + openBattle(b)} + > + + {planetLabel(b.planet, planets)} + + + {formatInt(b.shots)} + + + {/each} + + + {/if} + + + diff --git a/ui/frontend/src/lib/active-view/table.svelte b/ui/frontend/src/lib/active-view/table.svelte index fe8a1ba..f862b1a 100644 --- a/ui/frontend/src/lib/active-view/table.svelte +++ b/ui/frontend/src/lib/active-view/table.svelte @@ -14,6 +14,7 @@ e2e specs (`game-shell.spec.ts`, `view-menu`) keep matching. import TableFleets from "./table-fleets.svelte"; import TableSciences from "./table-sciences.svelte"; import TableRaces from "./table-races.svelte"; + import TableBattles from "./table-battles.svelte"; type Props = { entity: string }; let { entity }: Props = $props(); @@ -36,6 +37,8 @@ e2e specs (`game-shell.spec.ts`, `view-menu`) keep matching. {:else if entity === "races"} +{:else if entity === "battles"} + {:else}