fix(pwa): audit fixes — safe-area, SW lifecycle, badge, tap highlight, update banner, precache
- Add safe-top to all full-screen overlays (PlanMode, DiffViewer, ChatView PlanViewer) - Add safe-top to SessionsView drill-down header + swipe-back via pushState - Move safe-top to ChatView outer container (persists when header hides) - Add skipWaiting + clients.claim for immediate SW updates - Create monochrome 96x96 badge icon for Android notifications - Add -webkit-tap-highlight-color: transparent for dark theme - Show SW update banner on all views, not just SessionsView - Fix precache duplicates with specific glob patterns (18→16 entries) - Add safe-bottom to ChatView saveToast - Fix stale poll interval comment (10s→3s) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+34
-27
@@ -231,47 +231,62 @@ export function App() {
|
||||
|
||||
const isOffline = !deviceOnline || serverOnline === false;
|
||||
|
||||
const updateBanner = swUpdateAvailable && (
|
||||
<div className="fixed bottom-6 left-4 right-4 bg-surface border border-accent/30 rounded-md px-4 py-3 flex items-center justify-between z-50 shadow-lg safe-bottom">
|
||||
<span className="text-sm text-text font-mono">New version available</span>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => window.location.reload()} className="text-sm font-medium text-accent hover:text-accent-light cursor-pointer">Refresh</button>
|
||||
<button onClick={() => setSwUpdateAvailable(false)} className="text-sm text-text-dim hover:text-text cursor-pointer">Later</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Splash screen while first health check is pending
|
||||
if (serverOnline === null) {
|
||||
return (
|
||||
<div className="min-h-screen bg-bg flex items-center justify-center">
|
||||
<LoadingAnimation size="lg" label="Connecting..." />
|
||||
</div>
|
||||
<>
|
||||
<div className="min-h-screen bg-bg flex items-center justify-center">
|
||||
<LoadingAnimation size="lg" label="Connecting..." />
|
||||
</div>
|
||||
{updateBanner}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Offline screen
|
||||
if (isOffline) {
|
||||
return <OfflineView onRetry={checkHealth} />;
|
||||
return <><OfflineView onRetry={checkHealth} />{updateBanner}</>;
|
||||
}
|
||||
|
||||
if (!authed) {
|
||||
return <LoginView onLogin={handleLogin} />;
|
||||
return <><LoginView onLogin={handleLogin} />{updateBanner}</>;
|
||||
}
|
||||
|
||||
if (view.name === 'newchat') {
|
||||
return (
|
||||
<NewChatView
|
||||
cwd={view.cwd}
|
||||
onStartChat={startChat}
|
||||
onBack={backToSessions}
|
||||
/>
|
||||
<>
|
||||
<NewChatView cwd={view.cwd} onStartChat={startChat} onBack={backToSessions} />
|
||||
{updateBanner}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (view.name === 'settings') {
|
||||
return <SettingsView onBack={() => setView({ name: 'sessions' })} />;
|
||||
return <><SettingsView onBack={() => setView({ name: 'sessions' })} />{updateBanner}</>;
|
||||
}
|
||||
|
||||
if (view.name === 'chat') {
|
||||
return (
|
||||
<ChatView
|
||||
sessionId={view.sessionId}
|
||||
cwd={view.cwd}
|
||||
initialPrompt={view.initialPrompt}
|
||||
adapter={view.adapter}
|
||||
onBack={backToSessions}
|
||||
/>
|
||||
<>
|
||||
<ChatView
|
||||
sessionId={view.sessionId}
|
||||
cwd={view.cwd}
|
||||
initialPrompt={view.initialPrompt}
|
||||
adapter={view.adapter}
|
||||
onBack={backToSessions}
|
||||
/>
|
||||
{updateBanner}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -285,15 +300,7 @@ export function App() {
|
||||
onInstall={handleInstall}
|
||||
onDismissInstall={dismissInstall}
|
||||
/>
|
||||
{swUpdateAvailable && (
|
||||
<div className="fixed bottom-6 left-4 right-4 bg-surface border border-accent/30 rounded-md px-4 py-3 flex items-center justify-between z-50 shadow-lg">
|
||||
<span className="text-sm text-text font-mono">New version available</span>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => window.location.reload()} className="text-sm font-medium text-accent hover:text-accent-light cursor-pointer">Refresh</button>
|
||||
<button onClick={() => setSwUpdateAvailable(false)} className="text-sm text-text-dim hover:text-text cursor-pointer">Later</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{updateBanner}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user