feat: sitemap remediation, PWA activation, search refinements, Steam Deck UX
Sitemap: - Switch from ISR (revalidate=3600) to force-dynamic for per-request generation - Flatten into single app/sitemap.ts with inlined static entries and DB queries - NULL-safe syncStatus filter: ne(games.syncStatus, 'failed') OR isNull(games.syncStatus) - Structured JSON logging for generated URLs and DB errors - Delete lib/sitemap/* helpers and app/api/revalidate-sitemap route - Add basic vitest coverage for sitemap exports PWA & Offline: - Add @serwist/next service worker (webpack build) with runtime caching - Cache strategies: stale-while-revalidate for game pages, network-first for listings/API, cache-first for Steam CDN images - Offline fallback page (public/offline.html) - Manifest icons: 192px maskable + 512px any - Viewport meta with viewport-fit=cover, user-scalable=no - Apple mobile web app meta tags Search / Filter Refinements: - Multi-genre OR support in listing API (comma-separated genres) - Device-scoped FPS filter (min/max FPS constrained to selected device) - Client-side URL state sync via router.replace for shareable filtered views - Initialize filter state from URL params on mount - Auto-collapse filter panel on saved-filter load - Fix multi-genre saved filter parsing (comma-separated) Steam Deck / Touch / Gamepad UX: - WCAG 2.1 AA touch targets (44x44px) on all filter controls - .gamepad-focus CSS focus ring for controller navigation - useGamepadNavigation hook: D-pad/left-stick roving tabindex, A/B/X/Y actions - Integrate gamepad hook into games page (X=search, Y=toggle filters) Chore: - Bump version to 2026.0.97
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Offline — DeckyVault</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: var(--font-lexend, 'Lexend', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
||||
background-color: #100b14;
|
||||
color: #ebe4f1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.logo {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #eb3779;
|
||||
margin-bottom: 2rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
p {
|
||||
font-size: 0.875rem;
|
||||
color: #ebe4f1aa;
|
||||
max-width: 24rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.back-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: #eb3779;
|
||||
color: #100b14;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.back-btn:hover { background: #d42d6a; }
|
||||
.back-btn:active { background: #b8255c; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo">DeckyVault</div>
|
||||
<h1>You're offline</h1>
|
||||
<p>
|
||||
This page isn't available right now. Check your internet connection and try again.
|
||||
Previously visited game pages may still be available.
|
||||
</p>
|
||||
<button class="back-btn" onclick="history.back()">← Go Back</button>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user