feat: PWA support — installable on all platforms

- Add vite-plugin-pwa with autoUpdate service worker
- Generate SVG + PNG icons (192, 512, apple-touch-icon, favicon)
- Web app manifest with standalone display mode
- Workbox caching: precache assets, cache Google Fonts, NetworkFirst for API
- Apple mobile web app meta tags for iOS home screen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-07 21:53:44 +00:00
co-authored by Claude Opus 4.6
parent 7d251dbd78
commit 486d6f445d
9 changed files with 3222 additions and 19 deletions
+9 -1
View File
@@ -2,8 +2,16 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>BOTFIGHTS -- A safe place to hash it out</title>
<meta name="description" content="A safe place to hash it out" />
<meta name="theme-color" content="#0a0a0a" />
<link rel="icon" href="/favicon.ico" sizes="32x32" />
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="BOTFIGHTS" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
+1
View File
@@ -18,6 +18,7 @@
"tailwindcss": "^4.2.1",
"typescript": "^5.7.3",
"vite": "^7.3.1",
"vite-plugin-pwa": "^1.2.0",
"vue-tsc": "^2.2.8"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+31
View File
@@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" rx="64" fill="#0a0a0a"/>
<rect x="32" y="32" width="448" height="448" rx="48" fill="#111" stroke="#ff2d7b" stroke-width="4"/>
<!-- Left bot (cyan) -->
<rect x="100" y="180" width="120" height="100" rx="8" fill="#00f0ff"/>
<rect x="112" y="200" width="30" height="20" rx="4" fill="#0a0a0a"/>
<rect x="178" y="200" width="30" height="20" rx="4" fill="#0a0a0a"/>
<rect x="130" y="240" width="60" height="8" rx="4" fill="#0a0a0a"/>
<rect x="110" y="160" width="16" height="30" rx="4" fill="#00f0ff"/>
<rect x="194" y="160" width="16" height="30" rx="4" fill="#00f0ff"/>
<rect x="120" y="280" width="20" height="50" rx="4" fill="#00f0ff"/>
<rect x="180" y="280" width="20" height="50" rx="4" fill="#00f0ff"/>
<!-- Right bot (pink) -->
<rect x="292" y="180" width="120" height="100" rx="8" fill="#ff2d7b"/>
<rect x="304" y="200" width="30" height="20" rx="4" fill="#0a0a0a"/>
<rect x="370" y="200" width="30" height="20" rx="4" fill="#0a0a0a"/>
<rect x="322" y="240" width="60" height="8" rx="4" fill="#0a0a0a"/>
<rect x="302" y="160" width="16" height="30" rx="4" fill="#ff2d7b"/>
<rect x="386" y="160" width="16" height="30" rx="4" fill="#ff2d7b"/>
<rect x="312" y="280" width="20" height="50" rx="4" fill="#ff2d7b"/>
<rect x="372" y="280" width="20" height="50" rx="4" fill="#ff2d7b"/>
<!-- VS spark -->
<text x="256" y="270" text-anchor="middle" font-family="sans-serif" font-weight="900" font-size="48" fill="#b83dff">VS</text>
<!-- Lightning bolts -->
<polygon points="240,140 250,170 242,170 252,200" fill="#ffe14d"/>
<polygon points="272,140 262,170 270,170 260,200" fill="#ffe14d"/>
<!-- Title -->
<text x="256" y="400" text-anchor="middle" font-family="monospace" font-weight="900" font-size="40" fill="#ff2d7b" letter-spacing="4">BOTFIGHTS</text>
<!-- Ground line -->
<rect x="60" y="340" width="392" height="4" rx="2" fill="#ffe14d" opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+46 -1
View File
@@ -1,9 +1,54 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [vue(), tailwindcss()],
plugins: [
vue(),
tailwindcss(),
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['icon.svg'],
manifest: {
name: 'BOTFIGHTS',
short_name: 'BOTFIGHTS',
description: 'A safe place to hash it out',
theme_color: '#0a0a0a',
background_color: '#0a0a0a',
display: 'standalone',
orientation: 'any',
start_url: '/',
icons: [
{ src: '/icon.svg', sizes: 'any', type: 'image/svg+xml', purpose: 'any' },
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
],
},
workbox: {
globPatterns: ['**/*.{js,css,html,svg,png,woff,woff2}'],
navigateFallback: '/index.html',
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'CacheFirst',
options: { cacheName: 'google-fonts-css', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 } },
},
{
urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i,
handler: 'CacheFirst',
options: { cacheName: 'google-fonts-webfont', expiration: { maxEntries: 30, maxAgeSeconds: 60 * 60 * 24 * 365 } },
},
{
urlPattern: /\/api\/.*/i,
handler: 'NetworkFirst',
options: { cacheName: 'api-cache', expiration: { maxEntries: 50, maxAgeSeconds: 60 * 5 } },
},
],
},
}),
],
server: {
port: 9101,
proxy: {
+3135 -17
View File
File diff suppressed because it is too large Load Diff