diff --git a/web/public/eras/age-of-war-star-league.png b/web/public/eras/age-of-war-star-league.png new file mode 100644 index 0000000000000000000000000000000000000000..d56d2116475c458af888dbd2a60525e67aff8130 GIT binary patch literal 3282 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 Uh^7^c3=9kmp00i_>zopr0Bt&up8x;= literal 0 HcmV?d00001 diff --git a/web/public/eras/clan-invasion.png b/web/public/eras/clan-invasion.png new file mode 100644 index 0000000000000000000000000000000000000000..33a58b18e3310bb31d7f8b869f1fd03fd29e3fbd GIT binary patch literal 4668 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 literal 0 HcmV?d00001 diff --git a/web/public/eras/jihad.png b/web/public/eras/jihad.png new file mode 100644 index 0000000000000000000000000000000000000000..79695825cd015b5f4d82c5a1fe18e5c2e1b66543 GIT binary patch literal 4292 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 C$~q+g literal 0 HcmV?d00001 diff --git a/web/public/eras/succession-wars.png b/web/public/eras/succession-wars.png new file mode 100644 index 0000000000000000000000000000000000000000..a66bec36cb8db4c9cf7f3f802918d3126af03dd8 GIT binary patch literal 4638 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEoGGHryg!b=1gWa&ZmI|3wSyGX1B08-Er`43|OFlE8vr+3ge_tTz<}% zO>!GAOzK!~>e+bg*hZe39n*T=B=Kz9TIaE8$SoYtyOxL?;V#eT8tItwU_~)N~Df0n_4M`gC-EnLf`p{`~yBUT><`Qj_{VF}8@yp7w$lRj0=o=}$h{U}!esWXd_a zTPjzp%(oGP+_N&gGL2>Dt+#4Gn{@J$8%=`P_RR#~P zGrCOmTDm<%YcHDu;{mpWmHD41cYNLa|GU-!%k75@cw(;0uDkv^RcVt%@+3pCmHD5Q zueg6_Zn%5zUY@_WvC!o$zk51zl)7xrdvDpY#pL{a`}$0Yw%wf?cW>X`eWGyA<7qmP zMe2eR-~aYo8FK2}eEa%+Q;N3d-nQ<@P#1ig+H-P7NTXrf;;1)guU)-b`s&7wi0y|M zLm4zRp9cT^`}e-K2$%oL-zT0H#K z|9trH!G_`V6utVKgoK3N*Sr2QT)2OKKHCQdhMfER{(cKuxrLFT=Dz!4wHAl9Va3e~ z6~CWOkN@{!nr?KTbI2;xQXxJ>cR&UnO&A1>!=Ut&px_-lVrXMN|q4S>C zemyE4Z!^32pFl(X7n}F@8FHot^-b|wTHE*7<7`LO-gm$E$@B2?{@t*8^=skXfU?CAF`=em`d|+KJK@#+w;7VufczH zrO?OpEnBxn%F4=i&PbWFuk!P=)7?iO&6_xJV(;I-f8$R)Em~c)^NuisUXIE262bFL z3P1XkG)!iEXps6I{Pj1#i13-h@}Az_wdbA|IXenG*{b5RrCQ45<^4nnJyEAUGfzL= zw>ka%JbSLg6SVn1U(8HyQi^;1N4QJEpQBNMqmA*;I>WNLulCCx*m`PKdr|#rjn(l| zQc|zjFEBsYu|qxcib&74&W@_8s-UAuAG;YQoPWMujH@;7>zRIEZs9L23}IQ1u9o*d zwpf1r*uGW2_VGM$TlzclTxEt=^J9zZZ}0BzKKpskbDoSdd4n_ubf45b9w{G3OovWmDz4ZL_ptd%> z?@SgaFI>#+du+3?Zolr*o|^mrx4quAJ=16LorM}=-PT@9gTkcw&VMf28I#A|5WO|s zqUCI6(EaU<2lmzezSfr5k+t>Loy65m&mNpOaYBc|+TwYT;X<|tF~L?A&m)f)&I^AW zzv60^-t#~4TbEA=Dq;u}U|AHQv+w2ae;f@SUYb+p-?uU`*}`^U)5nCb2WLFk^)6iI zcp+EoA-|)y^<}4NNi3?L|ME0rjpDJ|W0vWfdksk&d#z7V)9)-vY2@lURs=crNH6z)#iP`^RC@;YzY&mY>Hcd zUHfNE-I2mM>bwk#H}5;?we(Zk&X_oUg}}98)3B53TtB0pXcu&0PL=hFWbD5hs4&0rVx^(ue zS#NyQf~Do;{$;!Fn0ake+SysA;a)Q(WMy;xmS3LYqqf$7Ctc{GkEZJMpthGKRcQh& zhd$fzC7k*G*YNbFSxcu(>PQiB4GRvQeEHI)O+AL+R2n>&pOZ)ya%eK##(luN<3)C$ z$Vmg9^&E#kFde($#;{E?&R=bIu~x$_qXdS6`ZKCVN{gw|14+)WLS_a-6hFl3E2Ryq31K9kG-`|=ZSM^fMw^+ngz^TJ)>8Ac-IX1_D z$8&y1l~_LiZzRgR?E046+uMrcE1yn1-F5U)_PpnB88%b|@myu)J-Tsjlslu%J%vA4 zc`Vo*Bpv(?-ghwcT_L-#wPVHZ-M_0QGoI4u+qG`BsvDQ0opQ^LgWvzIW$2shbm#n) z3NtIKU0xguum2C9T-4oWxbp&o-o&o2H!XNFM4g@-HYjNo2tE9s`M}#*pXbhN4FJGSAb)Bi869M_NfsQV|XV0EB&fa=!hQJ}EMb;9@ z{frq!GU{3R`P&z3OghHZ*`YDjYpK!9GaqOAJWDxV_^<5QnVIL;#P7GWI#V)TMafG= zDApw;k&%Se`f#C#$gvpXGw+bJXt<^hix@dCHqW$~-ADf|}*3n^>fA3Fw zp=iLdfZuPjul%1C`oug{O`>g=v+_j+j(4*!Y>=wAx_jWyrG~v>%^TH^-MM!*ZJB%j z`*-j5-TS=9aqEl#RTqVp4ilemwe`t6W9;@v==_^JFMX9kn0>U@&Y+u;`SX3EElJ|dov*VRKhLaM^CX4qaHq4y8<;Sa^pML() zy_#iuUE{8-tKgC;lZxfI6qo#4yXf%6qMb2J1?NMQt(vF#XSe;{x1aw&%;aew9UQw0 zW0QMYm%Y%wv2#YpyIb-cpKc3v9{J9oBAHxgHaj*%Yiiw{Tep7gc)d&S`J4`o`1RN0 zg`HenL=2Cu2wN>``CRq%rZrhxqmp_eU0R+!d$x01u6xj_`zlIR-)^QGN`4UDzc#p& zD`To;vgh^E*=mQk+MAkXU$!WFlykMd|E9f-P0i%@zbl>hY;JCDE@!YPJUh#De!%RS z102&%KUGw85okWKtNy4&>7O(0Kd*#FnC+Jy~0&JTwnl^7Gs>5M*9;?5mFK_u0BU&SI{D zHTS32*4AF1Q+Q1Bzj5`qH>*1}++Ds4Uu2g^u0JUu{o>_IPsR-`0zZEKO7zs6=(oH- zlt+-w>|^JPxZ;I{{7V>om&L8O7jg|0ZzwJ`o!OD`_t)2+4vo2f=QFdiHs#(<+m`FC z#HG&MTz^~OxZ&l37p*Lg1$|S3*c>-ROCD@g;COdcDeXZ6bJDKF!)^YvDi3n5t6kdm zlI=(~{}zS=*L(k`F`h9#mQng|QDVt`v&j~{Dh}@h);pEExNPpsNMvSVJ-ta|rq4VF zm+#lJwyLfSS=DQ3wnW=DOZ`ob*=&Y{r9mr~yx!#~;<|_N%eCtYi$nx%7tLRN#d`C{%OvSO>A(js+{#%FW7dtU1#_hfU<;^5r2;sA?bOPaJ>LFcWXuY2}g zaXGMb^X6jK=P?E6vZXA|K212q5tshv(Qn2lj5}R3QBbhUOo`sy= zbS^71^QY;t8#6my4z0VIHE+r$tLkrWgs;^2cxg%|PfO$pm;QMCvda_0V`Z6-B$Dqk z$f+)}4?gcJFmd_y|}KQUen@p zb1c1sR$h5|GNou^?(OA~)3z#1^)eObYTa03RqJCl*Y3mq$jxb6tLBBTyZ(Bqq;c9A zMu%;=w+;0_q%wSOP28a~)2FVXV_uL@mZW3E_X_vAkpGn~S600>6U^ zdFAV+tF45WL<_L6KVndJ6q=Rb`IOT=bm3K|2?9=ca>ZhJ*tV?dwF>*&=W{@;{c2dV z57U$#)rk^zi;sC|K7GGhWNOD}pTsIbS3%`PE>?5TsZ2hZc6yUf^NF-GGYq+Z8!O)0 zK6$IWq~bQVSQb`6#kqd!xwq~7ymn476e~P8{nobH`Il;~m+kY3{NXQn@ncqBL&rSZ z6+e#GzFif%y01{?d8zY~_h!fDtk&H&#Yjp{?p)Eir5n391!$zS3MlgJ_Y4iKI#)O+ zj3GYwLYQ~wlR55A9nn*>&IIq)zfxacv_kS3bMy6evAZ|Kt$%-UW-h~W4Ys+dZQJHO z5B>D>&#|nnyP`YmL|7WrnPksZT9}w@*%`OKf7Sta4#meWi>99Gkuq4E@I^U|IWJ7B zNUq^|@4xQHKhJm?Cl(YGxVgI@pPDGq$8g}ng@D;+Zd!%EOc=ta?*9Gh=bzQbG6g>0 zh!$aKj9-1VYu@uvk%NNIZFEGqTtm+_B`Po4v6n$%v4)cX%g3KvRrZK&4&J}if1%G# zi(TdK?>);gt4{UzKR?$|K;-xD-}Bi&?7Xq#D1+RiIs8&Avoi}9mWM1ou!!wJy3$AU zrLD#1Dw)|{L_N5yHTQpy*2MX#9=g^kY%AVh-gNWLr*r4douA^hbdys|w{PC+H|J%p zm*%ewTRq$NQIi5ki$IdlE3|}`X2s|y?nfGE<&)YpZQ@vv6d|tJXsmeW;VfK|9R~haxKd=vN zSa!RJL7Tyb>%o1-HH;r*8rVbc-#Kg-vXW2xwymwLd09zG%ma&aQC~msvVHS2F)~S% zh;_^fS(|lgPG+?#A zd^G9fyVBR!V#Qb*&wa=SJ@4pUS?^@*%Qx z)t40GJ$-B6_J?Y&Tk~mp{wfFEg({O}J=Fvn&Mfnty{_(Yulc%fwfA`s3#@9}kTd7; z=4~_E!aUyUPl=1Ww&F_JgwI@7PC0BJJoYg0KKR`J<}?3P&Q_;|PnXTk%X<6v?Oxku z=f5-0khI=kZOK-c&*{QTb z{#MDb`MCAZ%r~2M-tLtsTDIxcPqufTmNVS@yiPb@MSbPoy|vo}9z`Yxs{Omq{@^!* z-O`3m)6Pm`2D=x(|GhoM+`?;caK=L4=wCwhHmnj9DzRNjjwZN?P(E>U(j?mUFc$xl9jJ&%;jTJEm|kOXo*%vFWtEJM&DzP vF6(OXJuOSS7G4Zl>a{l5@A&JY|J>GcbD|Zh9^PVLU|{fc^>bP0l+XkK+yl!( literal 0 HcmV?d00001 diff --git a/web/scripts/trivia.test.mjs b/web/scripts/trivia.test.mjs index 1700ce0..5fce005 100644 --- a/web/scripts/trivia.test.mjs +++ b/web/scripts/trivia.test.mjs @@ -11,9 +11,10 @@ */ import { test } from "node:test"; import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; +import { access, readFile } from "node:fs/promises"; -const { parseCsv, parseTrivia } = await import("../src/content/trivia.ts"); +const { ERA_ICONS, parseCsv, parseTrivia } = + await import("../src/content/trivia.ts"); const csv = await readFile( new URL("../src/content/trivia.csv", import.meta.url), @@ -21,18 +22,16 @@ const csv = await readFile( ); /** The eras the file may use; the badge renders these strings verbatim. */ -const ERAS = new Set([ - "Pre-Star League", - "Age of War", - "Star League", - "Succession Wars", - "Clan Homeworlds", - "Clan Invasion", - "Jihad", - "Dark Age", - "ilClan", - "Real World", -]); +const ERAS = new Set(Object.keys(ERA_ICONS)); + +test("every era icon points at a file that ships", async () => { + for (const [era, icon] of Object.entries(ERA_ICONS)) { + if (icon === null) continue; + await access(new URL(`../public${icon}`, import.meta.url)).catch(() => { + assert.fail(`era "${era}": ${icon} is not in web/public`); + }); + } +}); test("quoted fields, embedded commas and doubled quotes parse", () => { assert.deepEqual(parseCsv('a,"b ""c"", d",e\n'), [["a", 'b "c", d', "e"]]); diff --git a/web/src/content/about.json b/web/src/content/about.json index e27b501..8ac2390 100644 --- a/web/src/content/about.json +++ b/web/src/content/about.json @@ -18,6 +18,15 @@ ", which is available on GitHub under the AGPLv3 license. That project is an actively maintained fork of the last AGPL-licensed version (v20.2.5) of Webswing. However, this project is not affiliated with and does not use the software of Webswing Ltd." ] }, + { + "p": [ + "The era symbols on the match loading screen are Catalyst Game Labs' era icons, sourced from the MegaMek project's ", + { "a": "MekBay", "href": "https://mekbay.com/" }, + ". The trivia shown beside them cites the community-run ", + { "a": "BattleTechWiki", "href": "https://www.sarna.net/" }, + "." + ] + }, { "p": [ "ATproto and the AT Protocol are ", diff --git a/web/src/content/trivia.ts b/web/src/content/trivia.ts index 9644f86..9af5491 100644 --- a/web/src/content/trivia.ts +++ b/web/src/content/trivia.ts @@ -19,6 +19,27 @@ export type Trivia = { source: string; }; +/** + * The badge icon for each era the file may use, or null for the eras that + * have none. The files are Catalyst Game Labs' era symbols, taken from the + * MegaMek project's MekBay (About credits them); one symbol covers everything + * up to the Star League, so three early eras share it. This map is also the + * closed set of eras — the trivia test rejects a row whose era is not a key, + * because a typo here would render straight into the badge. + */ +export const ERA_ICONS: Record = { + "Pre-Star League": "/eras/age-of-war-star-league.png", + "Age of War": "/eras/age-of-war-star-league.png", + "Star League": "/eras/age-of-war-star-league.png", + "Succession Wars": "/eras/succession-wars.png", + "Clan Homeworlds": "/eras/clan-homeworlds.png", + "Clan Invasion": "/eras/clan-invasion.png", + Jihad: "/eras/jihad.png", + "Dark Age": "/eras/republic-dark-age.png", + ilClan: "/eras/ilclan.png", + "Real World": null, +}; + /** Split a CSV document into rows of fields, honouring quotes. */ export function parseCsv(text: string): string[][] { const rows: string[][] = []; diff --git a/web/src/screens/waiting.ts b/web/src/screens/waiting.ts index cfc638a..1b2fbc2 100644 --- a/web/src/screens/waiting.ts +++ b/web/src/screens/waiting.ts @@ -1,14 +1,16 @@ import { matchStatus, matchUrl, type Session } from "../api"; import { footer, pageHead } from "../chrome"; -import { parseTrivia, type Trivia } from "../content/trivia"; +import { ERA_ICONS, parseTrivia, type Trivia } from "../content/trivia"; import triviaCsv from "../content/trivia.csv?raw"; import { el, onTeardown, render } from "../dom"; import { nav } from "../nav"; // Parsed once, at first import. Ten seconds a fact: long enough to read two -// sentences, short enough that a normal wait shows a few. +// sentences, short enough that a normal wait shows a few. The fade must fit +// inside the rotation with room to read what fades in. const TRIVIA: Trivia[] = parseTrivia(triviaCsv); const ROTATE_MS = 10_000; +const FADE_MS = 400; /** A copy of the deck in a fresh random order. */ function shuffled(facts: Trivia[]): Trivia[] { @@ -23,7 +25,14 @@ function shuffled(facts: Trivia[]): Trivia[] { /** Poll until the match answers, then hand the browser to it. */ export function waitingScreen(session: Session, matchId: string): Node[] { const line = el("p", { className: "waiting-line" }); - const era = el("span", { className: "trivia-era" }); + // The icon is decorative next to the era's name; a mask, not an , so + // the glyph takes the text colour on both themes. + const icon = el("span", { + className: "trivia-era-icon", + "aria-hidden": "true", + }); + const eraName = el("span"); + const era = el("span", { className: "trivia-era" }, [icon, eraName]); const source = el("a", { className: "trivia-source", textContent: "Source", @@ -31,24 +40,34 @@ export function waitingScreen(session: Session, matchId: string): Node[] { rel: "noopener noreferrer", }); const meta = el("p", { className: "trivia-meta" }, [era, source]); + const trivia = el("div", { className: "trivia" }, [line, meta]); const status = el("p", { className: "error", role: "alert" }); const show = (fact: Trivia): void => { line.textContent = fact.text; - era.textContent = fact.era; + eraName.textContent = fact.era; source.href = fact.source; + const eraIcon = ERA_ICONS[fact.era]; + icon.hidden = !eraIcon; + if (eraIcon) icon.style.setProperty("--era-icon", `url("${eraIcon}")`); }; const deck = shuffled(TRIVIA); let deckIndex = 0; let lineTimer = 0; + let swapTimer = 0; const first = deck[0]; if (first) { show(first); lineTimer = window.setInterval(() => { - deckIndex = (deckIndex + 1) % deck.length; - const fact = deck[deckIndex]; - if (fact) show(fact); + // Fade out, swap while invisible, fade back in. + trivia.classList.add("trivia-fading"); + swapTimer = window.setTimeout(() => { + deckIndex = (deckIndex + 1) % deck.length; + const fact = deck[deckIndex]; + if (fact) show(fact); + trivia.classList.remove("trivia-fading"); + }, FADE_MS); }, ROTATE_MS); } else { // The deck is bundled, so an empty one is a build problem, not a runtime @@ -58,6 +77,7 @@ export function waitingScreen(session: Session, matchId: string): Node[] { const stop = (): void => { window.clearInterval(lineTimer); + window.clearTimeout(swapTimer); window.clearInterval(pollTimer); }; @@ -73,8 +93,7 @@ export function waitingScreen(session: Session, matchId: string): Node[] { window.location.assign(matchUrl(match.url)); } else if (match.status === "failed" || match.status === "over") { stop(); - line.textContent = ""; - meta.hidden = true; + trivia.hidden = true; status.textContent = "The match could not be started. Try again."; } }) @@ -103,8 +122,7 @@ export function waitingScreen(session: Session, matchId: string): Node[] { pageHead("Starting your match"), el("section", { className: "card waiting" }, [ insignia, - line, - meta, + trivia, status, cancel, ]), diff --git a/web/src/styles.css b/web/src/styles.css index 88bbe7a..484f264 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -1766,6 +1766,19 @@ footer .debug { margin: 0.5rem auto 0; } +/* The rotating fact: the line, then the era and source under it. The fade + lives on this wrapper so the whole block leaves and arrives together. */ +.trivia { + display: flex; + flex-direction: column; + gap: 0.6rem; + transition: opacity 0.4s ease; +} + +.trivia-fading { + opacity: 0; +} + .waiting-line { margin: 0; /* Room for a three-line fact, so a longer one arriving in the rotation does @@ -1775,27 +1788,44 @@ footer .debug { color: var(--muted); } -/* The era chip and source link under each fact. */ .trivia-meta { margin: 0; display: flex; align-items: center; justify-content: center; - gap: 0.6rem; - font-size: 0.8rem; + gap: 1rem; + color: var(--muted); } .trivia-era { - border: 1px solid var(--line); - border-radius: 999px; - padding: 0.1rem 0.6rem; - color: var(--muted); + display: inline-flex; + align-items: center; + gap: 0.45rem; + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.09em; +} + +/* The era symbol, drawn in the text colour: the source images are white + glyphs on alpha, so they are used as a mask rather than shown as-is. */ +.trivia-era-icon { + width: 1.15rem; + height: 1.15rem; + background-color: currentcolor; + mask: var(--era-icon) center / contain no-repeat; } .trivia-source { + font-size: 0.8rem; color: var(--muted); } +@media (prefers-reduced-motion: reduce) { + .trivia { + transition: none; + } +} + @keyframes pulse { 0%, 100% {