Files
ark-stronghold-protocol/public/index.html
T
2321Robin 438a6b521a feedback7 stats: the local statistics page, ported from PR #323 by @2321Robin as submitted (record store ui/stats.js, viewer screens/stats.js, stats.css, entries on the title / lobby / room screens, 20 tests); golden: unchanged
- public/js/ui/stats.js: one record per finished match in localStorage (sp.pref.stats, envelope {v, records}, at most
  1000, quota shrink of the oldest), content-id dedupe of the lobby's result replay, a MIGRATIONS chain and
  normalizeRecord (defaults for missing fields, unknown fields kept, a newer envelope refused), merge-by-id export /
  import, aggregateStats.
- public/js/screens/stats.js: the viewer (总览 / 策略 / 称号 / 战斗累计 / 最近对局, a row re-views that match's
  settlement), 导出 / 导入 / 清空.
- Applied from the PR's own diff after reading it in full (no network, no new dependency, server untouched); only the
  UI strings of the page are added to the four packs (en from the PR; ja / ko / zh-TW translated for this commit).
- The follow-up commits rework the page (the counting rule for matches left early, storage bounds, the layout).
- Tests: test/ui/stats.test.js 20 / 20; i18n extract 0, check --all --strict clean.
2026-10-08 20:05:09 +08:00

108 lines
6.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<!-- A landscape game: no page zoom (iOS additionally needs the gesture handling of js/ui/device.js), full-bleed behind
notches (viewport-fit=cover; css/devices.css keeps the HUD inside the safe area). -->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
<meta name="theme-color" content="#0c0f0e" />
<meta name="color-scheme" content="dark" />
<meta name="format-detection" content="telephone=no" />
<!-- "Add to Home Screen" (iOS / Android) opens full screen without browser bars -->
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="卫戍协议" />
<meta name="description" content="卫戍协议:盟约 · 网页联机复刻(非官方同人作品)" />
<title>卫戍协议:盟约 · STRONGHOLD PROTOCOL</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24' fill='%230c0f0e'/%3E%3Cpath fill='%234ed8af' d='M5 3h3v2h2V3h4v2h2V3h3v5l-2 2v7l2 2v2H5v-2l2-2v-7L5 8z'/%3E%3C/svg%3E" />
<!-- Web fonts: never render-blocking (LAN/offline play must still start); system fallbacks in theme.css. -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" media="print" onload="this.media='all'"
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700;900&family=Oxanium:wght@400;500;600;700&family=Rajdhani:wght@500;600;700&display=swap" />
<!-- Self-hosted Bender / Novecento (provided by the assets pipeline). -->
<link rel="stylesheet" href="/fonts/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/components.css" />
<link rel="stylesheet" href="/css/screens/title.css" />
<link rel="stylesheet" href="/css/screens/lobby.css" />
<link rel="stylesheet" href="/css/screens/room.css" />
<link rel="stylesheet" href="/css/screens/game.css" />
<link rel="stylesheet" href="/css/screens/game-shop.css" />
<link rel="stylesheet" href="/css/screens/game-panels.css" />
<link rel="stylesheet" href="/css/screens/briefing.css" />
<link rel="stylesheet" href="/css/screens/draft.css" />
<link rel="stylesheet" href="/css/screens/result.css" />
<link rel="stylesheet" href="/css/screens/guide.css" />
<link rel="stylesheet" href="/css/screens/loadout.css" />
<link rel="stylesheet" href="/css/screens/stats.css" />
<link rel="stylesheet" href="/css/emotes.css" />
<link rel="stylesheet" href="/css/devices.css" />
<script type="importmap">
{ "imports": { "preact": "/vendor/preact.module.js", "preact/hooks": "/vendor/hooks.module.js", "htm": "/vendor/htm.module.js" } }
</script>
<link rel="modulepreload" href="/vendor/preact.module.js" />
<link rel="modulepreload" href="/vendor/hooks.module.js" />
<link rel="modulepreload" href="/vendor/htm.module.js" />
<link rel="modulepreload" href="/js/main.js" />
<!-- Battlefield renderer libs (classic scripts, injected by js/render/app.js when a match view mounts): warm the cache
at low priority so entering the match doesn't wait on ~800 KB of script. -->
<link rel="prefetch" href="/vendor/pixi.min.js" as="script" />
<link rel="prefetch" href="/vendor/pixi-spine.js" as="script" />
</head>
<body>
<div id="app"></div>
<div id="boot" class="boot" aria-hidden="true">
<div class="boot__inner">
<div class="boot__hex"></div>
<div class="boot__text">STRONGHOLD PROTOCOL</div>
<div id="boot-err" class="boot__err"></div>
</div>
</div>
<div class="rotate-hint" role="alert">
<div class="rotate-hint__phone"></div>
<div class="rotate-hint__title">请将设备横屏</div>
<div>卫戍协议:盟约 需要横屏显示以获得完整体验</div>
<div class="rotate-hint__micro">ROTATE DEVICE</div>
</div>
<noscript><p style="color:#c3cbc7;text-align:center;padding:40px">需要启用 JavaScript 才能运行本游戏。</p></noscript>
<script>
// Boot diagnostics (plain ES5: runs everywhere). A browser too old for the app says so instead of spinning forever:
// no ES modules (nomodule below), a module graph that cannot load (e.g. import maps: Safari / iOS < 16.4), or no
// boot after 9 s.
window.__spBootFail = function (why) {
var e = document.getElementById('boot-err');
if (!e || e.getAttribute('data-final')) return;
var im = false;
try { im = !!(window.HTMLScriptElement && HTMLScriptElement.supports && HTMLScriptElement.supports('importmap')); } catch (x) { im = false; }
e.textContent = why === 'old' || !im
? '当前浏览器版本过旧,无法运行本游戏。请升级到 iOS / iPadOS 16.4+(Safari 16.4+)、Chrome / Edge 90+ 或 Firefox 108+ 后刷新。'
: '游戏脚本加载失败,请检查网络连接后刷新页面。';
e.setAttribute('data-final', '1');
};
// a module graph that fails to link (bare specifier without import-map support) reports here, not on the <script>
window.addEventListener('error', function (ev) {
var b = document.getElementById('boot');
if (!b || b.classList.contains('is-done')) return;
if (/specifier|resolve|import|module/i.test(String(ev && ev.message))) window.__spBootFail('load');
});
</script>
<script type="module" src="/js/main.js" onerror="window.__spBootFail && window.__spBootFail('load')"></script>
<script nomodule>window.__spBootFail && window.__spBootFail('old');</script>
<script>
// If modules never boot (very old browser / blocked script), explain instead of spinning forever.
setTimeout(function () {
var b = document.getElementById('boot'), e = document.getElementById('boot-err');
if (b && !b.classList.contains('is-done') && e && !e.textContent) e.textContent = '加载时间较长…如长时间无响应,请使用最新版 Chrome / Edge / Safari / Firefox 并刷新页面。';
}, 9000);
</script>
</body>
</html>