Extract the leaderboard into a generic, backend-agnostic package and add rolling Today/Week/Month/All-Time windows, a web component, and local-first development against the Firestore emulator. Package (leaderboard/): - LeaderBoardService: backend-agnostic core via a storage-adapter seam, with Firebase and Supabase adapters (Supabase client injected, no added dep) - Rolling time windows (last 24h / 7d / 30d) with hover tooltips; top-N by score - <cozy-leaderboard> web component built on web-component-base: compose the UI in HTML, configure the backend once in JS - Every user-facing string is configurable (labels, tooltips, empty/loading/ error messages, anonymous name) so i18n lives in the app; README + CONFIGURATION App (mnswpr.com): - Compose the board declaratively in index.html via <cozy-leaderboard> - Nickname + randomized greeting bar; score submission through the element - Legends: the current all-time leaders frozen into a static /legends page - Firebase config and leaderboard namespace via Vite env vars; emulator-first local dev (VITE_FIRESTORE_EMULATOR) Firebase schema-as-code: - firebase.json, .firebaserc, firestore.rules (public reads, create-only scores, no client updates/deletes, namespace-generalized), empty indexes (rolling windows need none) - prod (mw-*) vs dev/test (mw-test-*) separation by collection namespace - emulator config, seed script, and docs (firebase-leaderboards.md, leaderboard-env-migration.md, AYO.md) Utils/tests: UTC date-bucket helper (retained as metadata) with Vitest coverage. Reviewed-on: git.ayo.run:3000/ Co-authored-by: Ayo <ayo@ayco.io> Co-committed-by: Ayo <ayo@ayco.io>
47 lines
1.3 KiB
HTML
47 lines
1.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
|
|
<meta name="Description" content="Play Minesweeper online for FREE!" />
|
|
<title>Play Minesweeper online for FREE!</title>
|
|
|
|
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
|
<link rel="stylesheet" href="./main.css" />
|
|
<link rel="stylesheet" href="../utils/loading/loading.css" />
|
|
<style>
|
|
:host, :root{
|
|
--mnswpr-transition: 10s ease-in-out;
|
|
}
|
|
|
|
sup {
|
|
a {
|
|
color: white;
|
|
text-decoration-color: orange;
|
|
transition: 500ms ease-in-out;
|
|
|
|
&:hover {
|
|
text-decoration-thickness: 2px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="body-wrapper">
|
|
<div id="greeting"></div>
|
|
<div id="app">
|
|
Please use Chrome or Firefox.
|
|
</div>
|
|
|
|
<cozy-leaderboard category="beginner" title="Best Times" format="time" score-order="asc"></cozy-leaderboard>
|
|
|
|
<div id="legends-link">
|
|
<a href="/legends.html">🏆 Legends</a>
|
|
</div>
|
|
</div>
|
|
<script type="module" src="./main.js"></script>
|
|
</body>
|
|
</html>
|