Skip to content

Add read-only Game Leaderboard canvas - #193

Open
sanjeevkumarcspl wants to merge 1 commit into
github-samples:mainfrom
sanjeevkumarcspl:sanjeevkumarcspl-game-leaderboard-canvas
Open

sanjeevkumarcspl wants to merge 1 commit into
github-samples:mainfrom
sanjeevkumarcspl:sanjeevkumarcspl-game-leaderboard-canvas

Conversation

@sanjeevkumarcspl

Copy link
Copy Markdown

Description

Adds a project-shared, read-only Game Leaderboard canvas that ranks catalog games by their existing star rating, so prospective backers can compare games.

Related Issue

Closes #158

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🧪 Test update
  • 🔧 Refactor (no functional changes)

Changes Made

  • New canvas extension .github/extensions/game-leaderboard/ (read-only; fixed SELECT, no user SQL), with a genre (category) filter
  • Pure ranking logic in ranking.mjs (+ ranking.d.mts): competition ranking for ties (1, 2, 2, 4), unrated games last with no rank, deterministic ordering
  • UI copy says "star rating" and states ratings are not gameplay scores or live popularity
  • Vitest coverage in src/lib/leaderboard.test.ts
  • README and copilot-instructions.md updated

Testing

Data Layer Changes

  • Ran npm run test:unit - all tests pass
  • Added/updated Vitest tests for data-layer changes
  • Generated a migration (npm run db:generate) for any schema change (N/A, no schema change)

Not run: npm run test:unit and npm run lint could not run in my environment (Node v22.10.0 is below the required >=22.13, so npm skipped the rolldown/Astro native bindings). Please rely on CI for these. Verified locally: npm run typecheck passes, node --check on the extension passes, and a plain-Node run of rankGames gave [A 1, B 2, C 2, D 4, E null]. The canvas UI was not opened manually.

Frontend Changes

  • Ran npm run test:e2e - all tests pass (N/A, no site changes)
  • Added data-testid attributes to interactive elements (N/A)
  • Verified build succeeds (npm run build) (N/A)

Checklist

  • My code follows the project's coding standards
  • I have used explicit TypeScript types for function parameters and return values
  • I have built the UI with Astro components and Tailwind CSS utility classes (N/A, canvas is a standalone panel)
  • I have updated documentation (README, instruction files) if needed
  • My changes are focused on a single concern
  • I have written clear commit messages explaining what and why

Additional Notes

Canvas only, per the approved plan; no public /leaderboard page.

Ranks games by star rating with genre filtering, shared ranks for ties,
and unrated games last. Closes github-samples#158

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 3, 2026 06:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An unavailable database-client dependency blocks startup, the default database path conflicts with documented setup, and out-of-order requests can overwrite the selected genre’s results.

3 open issues
What changed in this PR

Adds a project-shared, read-only Game Leaderboard canvas for comparing catalog star ratings, addressing #158 without adding a public site page.

Changes:

  • Adds a canvas UI and action with genre filtering and local database queries.
  • Implements shared ranks for ties, deterministic ordering, and unrated games listed last.
  • Adds ranking tests and documents setup, structure, and rating semantics.
File Description
src/​lib/​leaderboard.test.ts Tests ranking, ties, filtering, empty results, and input preservation.
README.md Documents the canvas, database setup, and rating semantics.
.github/​extensions/​game-leaderboard/​ranking.mjs Implements filtering and competition ranking.
.github/​extensions/​game-leaderboard/​ranking.d.mts Declares ranking input and output types.
.github/​extensions/​game-leaderboard/​extension.mjs Adds database reads, canvas UI, and lifecycle handlers.
.github/​copilot-instructions.md Documents canvas extensions and ranking test locations.

Review effort: Balanced

import { createServer } from "node:http";
import { fileURLToPath } from "node:url";
import { dirname, join, resolve } from "node:path";
import { createClient } from "@libsql/client";
const PROJECT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");

function databaseUrl() {
return process.env.DATABASE_URL ?? `file:${join(PROJECT_ROOT, ".data", "tailspin.db")}`;
Comment on lines +86 to +105
const load = async () => {
status.textContent = "Loading...";
status.className = "muted";
try {
const response = await fetch("/api/leaderboard?genre=" + encodeURIComponent(genreSelect.value));
const data = await response.json();
if (!response.ok) throw new Error(data.error ?? "Request failed.");
if (genreSelect.options.length === 1) {
genreSelect.insertAdjacentHTML("beforeend", data.genres.map((g) => '<option value="' + escapeHtml(g) + '">' + escapeHtml(g) + "</option>").join(""));
}
if (!data.entries.length) {
result.innerHTML = '<div class="empty-state">No games found. Set up the local database with <code>npm run db:setup</code> or pick another genre.</div>';
} else {
result.innerHTML = '<table><thead><tr><th scope="col">Rank</th><th scope="col">Game</th><th scope="col">Genre</th><th scope="col">Publisher</th><th scope="col">Star rating</th></tr></thead><tbody>' +
data.entries.map((e) => '<tr><td class="rank">' + (e.rank ?? "&ndash;") + "</td><td>" + escapeHtml(e.title) + "</td><td>" + escapeHtml(e.genre ?? "") + "</td><td>" + escapeHtml(e.publisher ?? "") + "</td><td>" +
(e.starRating === null ? '<span class="muted">Unrated</span>' : escapeHtml(e.starRating.toFixed(1))) + "</td></tr>").join("") + "</tbody></table>";
}
status.textContent = data.entries.length + " game(s)";
} catch (error) {
result.innerHTML = "";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add game leaderboard canvas

2 participants