Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/gametile.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ const { Game, Path, Image } = Astro.props;
const altText = `${Game} unblocked - play online free`;
---

<a href={Path} data-astro-prefetch class="m-5 inline-block text-center no-underline">
<a href={Path} data-astro-prefetch class="m-5 inline-block max-w-full text-center no-underline">
<img
src={Image}
alt={altText}
width="300"
height="200"
loading="lazy"
decoding="async"
class="h-[200px] w-[300px] rounded-xl transition-transform duration-300 hover:scale-105 hover:shadow-lg active:scale-95 transform"
class="aspect-[3/2] h-auto w-full max-w-[300px] rounded-xl transition-transform duration-300 hover:scale-105 hover:shadow-lg active:scale-95 transform"
/>
<p class="text-gray-800 transition-colors hover:text-black">{Game}</p>
</a>
16 changes: 13 additions & 3 deletions src/layout/layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const homeDescription = "Play free unblocked games on your school Chromebook - H
const gameDescription = isHome
? homeDescription
: seo?.description ||
`Play ${Game} unblocked on your school Chromebook. No Flash plugin or download needed - runs directly in your browser. Fully working 2026 version of this classic game.`;
(Game
? `Play ${Game} unblocked on your school Chromebook. No Flash plugin or download needed - runs directly in your browser. Fully working 2026 version of this classic game.`
: pageTitle || homeDescription);

// Image & other SEO fields — ponytail: webp covers beat SVG for og:image validators
const gameImage = isHome
Expand All @@ -43,8 +45,16 @@ const gameYear = seo?.year || "";
// URL
const pageUrl = slug ? `${siteUrl}/games/${slug}` : siteUrl;

// More Games cross-linking — curated list of popular games
const moreGames = defaultGames.slice(0, MORE_GAMES_COUNT).filter((s) => s !== slug); // exclude current game
// More Games cross-linking — same genre first, then fill from popular
// ponytail: two passes over defaultGames, no new data structures
const moreGames = (() => {
if (!slug || !seo) return defaultGames.slice(0, MORE_GAMES_COUNT);
const rest = defaultGames.filter((s) => s !== slug);
return [
...rest.filter((s) => gamesMap[s].genre === seo.genre),
...rest.filter((s) => gamesMap[s].genre !== seo.genre),
].slice(0, MORE_GAMES_COUNT);
})();
---

<html lang="en">
Expand Down
14 changes: 14 additions & 0 deletions src/pages/404.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
import Layout from "../layout/layout.astro";
const pageTitle = "Page Not Found - Superfun Games";
---

<Layout pageTitle={pageTitle}>
<div class="mx-auto max-w-[600px] p-6 text-center">
<h1 class="text-2xl font-bold mb-2">Game not found</h1>
<p class="mb-4 text-gray-600">
That page doesn't exist. Head back to the homepage to pick a game.
</p>
<a href="/" class="text-blue-600 hover:underline">Back to all games</a>
</div>
</Layout>
2 changes: 1 addition & 1 deletion src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const popularGames = defaultGames.slice(0, POPULAR_COUNT);
</div>

<h2 class="sr-only">All unblocked games</h2>
<div class="grid grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-[10px]">
<div class="grid grid-cols-[repeat(auto-fill,minmax(min(100%,280px),1fr))] gap-[10px]">
{
defaultGames.map((slug) => {
const seo = gamesMap[slug];
Expand Down
Loading