diff --git a/.gitignore b/.gitignore index a5b4f4c..39f43f1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ node_modules/ frontend/dist/ frontend/build/ +# Generated files +frontend/public/manifest.json + # Logs *.log npm-debug.log* diff --git a/README.md b/README.md index 6d3f8fd..a7ff006 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ A full-stack web application that helps groups pick games to play from various J ## Features +### Progressive Web App (PWA) +- **Installable**: Add to home screen on mobile and desktop devices +- **Offline Support**: Service worker provides offline functionality +- **Native Experience**: Runs like a native app when installed +- **Auto-updates**: Seamlessly updates to new versions + ### Admin Features - **Game Picker**: Randomly select games with intelligent filters - Filter by player count, drawing games, game length, and family-friendly status @@ -130,6 +136,34 @@ The backend will run on http://localhost:5000 The frontend will run on http://localhost:3000 and proxy API requests to the backend. +## Configuration + +### Branding and Metadata + +All app branding, metadata, and PWA configuration is centralized in `frontend/src/config/branding.js`. Edit this file to customize: + +- **App Name** and **Short Name** - Displayed in UI and when installed as PWA +- **Description** - Shown in search engines and app stores +- **Version** - Current app version +- **Theme Color** - Primary color for browser chrome and PWA theme +- **Keywords** - SEO metadata +- **Author** - Creator/maintainer information +- **Links** - GitHub repo, support contact, etc. + +When you update `branding.js`, the following are automatically synchronized: + +1. **PWA Manifest** (`manifest.json`) - Generated at build time via `generate-manifest.js` +2. **HTML Meta Tags** - Updated via Vite HTML transformation plugin +3. **App UI** - Components import branding directly + +To regenerate the manifest manually: +```bash +cd frontend +npm run generate-manifest +``` + +The manifest is automatically generated during the build process, so you don't need to edit it directly. + ## Project Structure ``` diff --git a/frontend/ICONS.md b/frontend/ICONS.md new file mode 100644 index 0000000..5f0867d --- /dev/null +++ b/frontend/ICONS.md @@ -0,0 +1,93 @@ +# Icon Generation Guide + +## Current Icons + +- ✅ `public/favicon.svg` - Primary icon (SVG format) + +## Missing Icons (Optional but Recommended) + +For optimal PWA support, especially on iOS/Safari, you should generate PNG versions: + +- `public/icon-192.png` - 192x192px PNG +- `public/icon-512.png` - 512x512px PNG + +## How to Generate PNG Icons + +### Option 1: Online Converter (Easiest) + +1. Go to https://realfavicongenerator.net/ or https://favicon.io/ +2. Upload `public/favicon.svg` +3. Generate and download PNG versions +4. Save as `icon-192.png` and `icon-512.png` in `frontend/public/` + +### Option 2: Using ImageMagick (Command Line) + +If you have ImageMagick installed: + +```bash +cd frontend/public + +# Generate 192x192 +convert favicon.svg -resize 192x192 icon-192.png + +# Generate 512x512 +convert favicon.svg -resize 512x512 icon-512.png +``` + +### Option 3: Using Node.js Script + +Install sharp library temporarily: + +```bash +npm install --save-dev sharp +``` + +Create and run this script: + +```javascript +// generate-icons.js +const sharp = require('sharp'); +const fs = require('fs'); + +const sizes = [192, 512]; +const svgBuffer = fs.readFileSync('./public/favicon.svg'); + +sizes.forEach(size => { + sharp(svgBuffer) + .resize(size, size) + .png() + .toFile(`./public/icon-${size}.png`) + .then(() => console.log(`✅ Generated icon-${size}.png`)) + .catch(err => console.error(`❌ Failed to generate icon-${size}.png:`, err)); +}); +``` + +Run it: +```bash +node generate-icons.js +``` + +Then uninstall sharp: +```bash +npm uninstall sharp +``` + +## What Happens Without PNG Icons? + +The app will still work as a PWA! Modern browsers (Chrome, Edge, Firefox) support SVG icons just fine. However: + +- **iOS Safari** may not display the icon correctly on the home screen +- Some older Android devices might show a generic icon +- The manifest references PNG files as fallbacks + +The SVG will be used as a fallback, which works on most platforms. + +## Why We Don't Auto-Generate + +PNG generation requires either: +- Native image processing libraries (platform-dependent) +- External dependencies that bloat the build +- Build-time processing that slows down development + +Since the app works fine with SVG on most platforms, we leave PNG generation as an optional step. + diff --git a/frontend/generate-manifest.js b/frontend/generate-manifest.js new file mode 100644 index 0000000..c0ea480 --- /dev/null +++ b/frontend/generate-manifest.js @@ -0,0 +1,74 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Import branding config dynamically +const brandingModule = await import('./src/config/branding.js'); +const branding = brandingModule.branding; + +const manifest = { + name: branding.app.name, + short_name: branding.app.shortName, + description: branding.app.description, + start_url: "/", + display: "standalone", + background_color: "#1f2937", + theme_color: branding.meta.themeColor, + orientation: "any", + scope: "/", + icons: [ + { + src: "/favicon.svg", + sizes: "any", + type: "image/svg+xml" + }, + { + src: "/icon-192.png", + sizes: "192x192", + type: "image/png", + purpose: "any maskable" + }, + { + src: "/icon-512.png", + sizes: "512x512", + type: "image/png", + purpose: "any maskable" + }, + { + src: "/favicon.svg", + sizes: "512x512", + type: "image/svg+xml", + purpose: "any" + } + ], + screenshots: [], + categories: ["entertainment", "games", "utilities"], + shortcuts: [ + { + name: "Pick a Game", + short_name: "Pick", + description: "Go directly to the game picker", + url: "/picker", + icons: [] + }, + { + name: "Session History", + short_name: "History", + description: "View past gaming sessions", + url: "/history", + icons: [] + } + ] +}; + +// Write manifest to public directory +const publicDir = path.join(__dirname, 'public'); +const manifestPath = path.join(publicDir, 'manifest.json'); + +fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8'); + +console.log('✅ Generated manifest.json from branding config'); + diff --git a/frontend/generate-png-icons.html b/frontend/generate-png-icons.html new file mode 100644 index 0000000..7c11fcc --- /dev/null +++ b/frontend/generate-png-icons.html @@ -0,0 +1,166 @@ + + +
+frontend/public/icon-192.png and icon-512.png