diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..bd6abf5 --- /dev/null +++ b/public/sw.js @@ -0,0 +1,31 @@ +const CACHE = 'gj-v1' + +self.addEventListener('install', (e) => { + e.waitUntil( + caches.open(CACHE).then((cache) => + cache.addAll(['/', '/manifest.json', '/icon.svg']) + ) + ) + self.skipWaiting() +}) + +self.addEventListener('activate', (e) => { + e.waitUntil( + caches.keys().then((keys) => + Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))) + ) + ) + self.clients.claim() +}) + +self.addEventListener('fetch', (e) => { + // Only cache GET requests for same-origin non-API resources + if ( + e.request.method !== 'GET' || + e.request.url.includes('/api/') + ) return + + e.respondWith( + caches.match(e.request).then((cached) => cached || fetch(e.request)) + ) +}) diff --git a/src/main.tsx b/src/main.tsx index bef5202..6ff8793 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,6 +3,12 @@ import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' +if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('/sw.js') + }) +} + createRoot(document.getElementById('root')!).render( diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index e07093a..5b4db08 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -53,7 +53,7 @@ export default function SettingsPage() { const navigate = useNavigate() const fileInputRef = useRef(null) const { canInstall, isIOS, isInstalled, triggerInstall } = usePWAInstall() - const [showIOSModal, setShowIOSModal] = useState(false) + const [installModal, setInstallModal] = useState<'ios' | 'chrome' | null>(null) // Edit profile modal state const [showEditModal, setShowEditModal] = useState(false) @@ -286,14 +286,21 @@ export default function SettingsPage() { {/* App */} - {!isInstalled && (isIOS || canInstall) && ( -
+

APP

- )} {/* Data & Look */}
@@ -526,48 +532,85 @@ export default function SettingsPage() { )} - {/* iOS "Add to Home Screen" instructions modal */} - {showIOSModal && ( -
setShowIOSModal(false)}> + {/* Add to Home Screen instructions modal */} + {installModal && ( +
setInstallModal(null)}>
e.stopPropagation()}>
🌱

Add to Home Screen

-

Follow these steps in Safari:

-
    -
  1. - - - - - - - - Tap the Share button at the bottom of Safari -
  2. -
  3. - - - - - - - - Scroll down and tap Add to Home Screen -
  4. -
  5. - - - - - - Tap Add to confirm -
  6. -
+ + {installModal === 'ios' ? ( + <> +

Follow these steps in Safari:

+
    +
  1. + + + + + + + + Tap the Share button at the bottom of Safari +
  2. +
  3. + + + + + + + + Scroll down and tap Add to Home Screen +
  4. +
  5. + + + + + + Tap Add to confirm +
  6. +
+ + ) : ( + <> +

Follow these steps in Chrome:

+
    +
  1. + + + + + + Tap the â‹® menu in the top-right corner +
  2. +
  3. + + + + + + + Tap Add to Home screen +
  4. +
  5. + + + + + + Tap Add to confirm +
  6. +
+ + )} +