From 8cd64ce3caa2cbad9028448586b5d9d2fa426bb0 Mon Sep 17 00:00:00 2001 From: Smittix Date: Mon, 23 Feb 2026 19:36:28 +0000 Subject: [PATCH] fix: PWA install prompt - add PNG icons and fix apple-touch-icon Browsers require PNG icons (192x192, 512x512) in the manifest to show the install prompt. SVG-only manifests are not sufficient. Also adds the 180x180 apple-touch-icon PNG for iOS home screen, bumps SW cache to v3, and adds scope to the manifest. Co-Authored-By: Claude Sonnet 4.6 --- static/icons/apple-touch-icon.png | Bin 0 -> 5530 bytes static/icons/favicon-32.png | Bin 0 -> 750 bytes static/icons/icon-192.png | Bin 0 -> 5884 bytes static/icons/icon-512.png | Bin 0 -> 18126 bytes static/manifest.json | 11 ++++ static/sw.js | 106 +++++++++++++++--------------- templates/index.html | 2 +- 7 files changed, 65 insertions(+), 54 deletions(-) create mode 100644 static/icons/apple-touch-icon.png create mode 100644 static/icons/favicon-32.png create mode 100644 static/icons/icon-192.png create mode 100644 static/icons/icon-512.png diff --git a/static/icons/apple-touch-icon.png b/static/icons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..de01f1fee960a1a0e2de5d267efe8322de5b734a GIT binary patch literal 5530 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 az-9QAf_%$AjQz%JB~n+_QK?q4eg7XeWdhLv literal 0 HcmV?d00001 diff --git a/static/icons/favicon-32.png b/static/icons/favicon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..97da70534c07516267d5e31907faa3344f152e00 GIT binary patch literal 750 zcmVH3l&T^DxnKSGDk<9?{W0BXpF{TYLXcT!QbY> zdGEQ;@4V-I@8JkBS@TP-h{%257+@na@&f}3)gJK7bpvPsHr@GLL^^;mCv2Rxj zawEs$Fh@eZUWu*zO$MP!rBIhNv&G@!*UGnDf|QC?cX|cv*)RZj4OxT(I1E{Y1F&mg z2N)1RBy&EENx7Pdz31-YJaL`%Xqa!WpWqq$n05nV)17Mbpk}gA)6$7v)j)7@hTQxz zlv<v>=Pzi0lwKWA`8<1lr&t!QBn6_@WR@&9DUeB&8-fO-04CzQ(Qc53ySJ4P}B5+ zm8n4twmgEf6Nu4BWcdf>XKsVQTG-FrQ0iw_as5S>CO#7lETfddGv0@L_-*nG#C*jb zf+*q7B2g-#Wd5yxGr#ieaGy9Mk)R_7rC-^a0+*8;HWbu;>^3Gehs z%It-a_f%hfM#SqT8uqa;+7lN~=mOD99B%2P;NU5irUo(FbPTx;tVNYfe|X7ccU#Kv z4QXa8CVL^F#p#4t@-}RCp;tE&T$~|CFN3ux{jK$BZ$r&&u|M5BsMe#*4|k)KV$Z&M zqJd?`yB-jnpG+$pl4KzM4M7l;T2DJ1{_-pSEu~Owq4HDI4mb^W4P@GY0$&#SD+YnV ztl@=0gF>}ui?0;z+G@x@kz;X~fz#Uw7g23~&zwsGh=hE-CW~!IkWvN3lA#;20-p$9 g6x{QB=3D?j0XE9o*SY{dE&u=k07*qoM6N<$g0qcOq5uE@ literal 0 HcmV?d00001 diff --git a/static/icons/icon-192.png b/static/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..bff2b20b0091ca4ae4ce2403f87ad06a7d7052fb GIT binary patch literal 5884 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�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%0ATqB zKNEM1zfsl>dCs6eQu*uuF~|GR!>x0u3kyO(|A`{NtqsnDIP}yaSvh_)p(I1k1COx2 zx)!ox$PRAGBB`zE%{SHqUHEuUIWR^eeiK{7-hk(87FQ@)&-l!UT4WpF? z>GJb;ab*FpuB2#MuQ5G{IRz;L^{!qv7jTC)5ZOT=Vt34lfd~5dL4cqph?$icO_RGC zwI2|%y^-7yxmhpzv+OCDPvneb#sy9*2|kFzypC{o02|=EP0JAod$HmtklX;0t-mj= z^e}Hw2`Phdd7yr4^a0=&I+aHQvd}={9rT84pXnxKsV_0!KrLQr(JVo)iy|Viw?@TQ z1_ypC1|MKK}^tpd`!Y|MWHgCm{NtoJuT)5K0Lutt1WHSZ)6+ z=i+{OV=TV^F%r1Jc(l;64;`o}lNf*39j#OMKUr8&U$jBuf8J|(iN%1LGvEQMq6NIf z{H@b^d@3*OSE(Q_&*vlx~^vdX<6U*=-<Q?S10G@=AavA zJb;Sg$wMq5IHr}iwhYqOj&}VMu$7mfBC?eQ{w!zkVhDKP{zitB1{Vj=E;@K6a?-bi zq#_1xgm@80pJjw`fFOYYPn$m(x%=h7vgy?*#vi=v`6Q<6+69z#1g8cx@q**@ZF?_w z3cqR=JOAjbw`HiZ_8);Er(mPl&@{B|U%6<3`Rijk^vyu%MOP-Fs^F0M>avC6|tpQc`}=;4CY)bIR>&5YpFLC5FBh7vjM z0pF(n`mi0x)!cmOGW+ezW&p=UX9o)qazD@JxTZ1zACy_{6i?OhOAU#z-v=t9lHP(p z6ySLCy8tof97kL#^_B5A$8fDtuL;INJcfa&O|d{_0jGQTK5G&_XEqA;3lEeJxi4TB3Dr-xtDQWNL44 z7FSII?Ka%-cZyAan4KZ0yyeV+QE#G?hO?jrv;>mLot@+nVzJN{x@tqV;2Iq~-TXS$ zFV@`Le5F?(sLBGw#A%-9u?TxzDf%1ikAX+H|LBDJ{;1p9FS3+bc^LFi6BI!s*(`(y zK!LRExn$D1ly^jah0kCdI}Ut7JnL_14Ev1HV{m2pmPG$xga;xp`Im(AKb_ovNa)hl zDXunb%z;vL)qy$bQIBnzf`AE74NOZ}X73R2x7*Tk`3iiRFD2V7J##0;Y~=X?=$o$- zeJoCQVs3{vF@Qo-b)@6Kv_VI^6}L3NIg4sB8ozvBaf$~7CI4VhKBb#B+MXRr$9rnX zCsoa6Xiz7wNckrh+@Vjs3@-vJ>#opmhZQS4fKFq&Fp>LGtT|zJa})p|`U%DA?^vGT zZTogud8i!F{1^W|;_$XgnxHEESg<0p}>jh7Gf;uho^4=isIo3uq;15KB>(mJKNT z+jC9d0vP{>U)yEZU8&_cRpx@NF!zltB``Y~iz$2J1*);};WgOQb!TMG=s%3XnlNZu@#X4L&*gsOH+Q%<#ppw zJ>8nbE70KkY{Rz)UN-Mw7YstuVbtZ0rk=q(rD^N1XNG6LlgTU zN{H!R5^(>|y^e1WDA}?+~qz7edsnEjGziUSF<}l~# zj<%VW3eZU0HnkzJt}u6*O;G%?dZf5xcx}KDjtpVMgItk27yooB!1R z?~GRF)<$UU|+NoQDtXNxb?s z%MYfm&z)#1|qeOYlXBnAxP(9`TaA(jpkl2wHhlara_378I%0>u0 zN~Y8jn-P)MU6)qQVu0jdqkntuiwjTp9%_G`WnpHvcy(Wt=E>FK+)M_n1MX+&ECuSL zYJ4)ap@W|wAM2rFPnene2G9Ofdej;)<`%CXq;2qF|B)YrslN+?D?7n5PacDdAV1C zZ~6W)-Z)-+>yP%YFX)wN{qNn*UJd=~DHc*Wi-c3s3Vbr5mxfWP-#(Mli0L_>6pr0< f0JP5Cl8>yQ5*t?3ag literal 0 HcmV?d00001 diff --git a/static/manifest.json b/static/manifest.json index 4a2eb81..aefdafa 100644 --- a/static/manifest.json +++ b/static/manifest.json @@ -3,10 +3,21 @@ "short_name": "INTERCEPT", "description": "Unified SIGINT platform for software-defined radio analysis", "start_url": "/", + "scope": "/", "display": "standalone", "background_color": "#0b1118", "theme_color": "#0b1118", "icons": [ + { + "src": "/static/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/static/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, { "src": "/static/icons/icon.svg", "sizes": "any", diff --git a/static/sw.js b/static/sw.js index af523e5..b270128 100644 --- a/static/sw.js +++ b/static/sw.js @@ -1,22 +1,22 @@ -/* INTERCEPT Service Worker — cache-first static, network-only for API/SSE/WS */ -const CACHE_NAME = 'intercept-v2'; - -const NETWORK_ONLY_PREFIXES = [ - '/stream', '/ws/', '/api/', '/gps/', '/wifi/', '/bluetooth/', - '/adsb/', '/ais/', '/acars/', '/aprs/', '/tscm/', '/satellite/', - '/meshtastic/', '/bt_locate/', '/receiver/', '/sensor/', '/pager/', - '/sstv/', '/weather-sat/', '/subghz/', '/rtlamr/', '/dsc/', '/vdl2/', +/* INTERCEPT Service Worker — cache-first static, network-only for API/SSE/WS */ +const CACHE_NAME = 'intercept-v3'; + +const NETWORK_ONLY_PREFIXES = [ + '/stream', '/ws/', '/api/', '/gps/', '/wifi/', '/bluetooth/', + '/adsb/', '/ais/', '/acars/', '/aprs/', '/tscm/', '/satellite/', + '/meshtastic/', '/bt_locate/', '/receiver/', '/sensor/', '/pager/', + '/sstv/', '/weather-sat/', '/subghz/', '/rtlamr/', '/dsc/', '/vdl2/', '/spy/', '/space-weather/', '/websdr/', '/analytics/', '/correlation/', '/recordings/', '/controller/', '/ops/', ]; - -const STATIC_PREFIXES = [ - '/static/css/', - '/static/js/', - '/static/icons/', - '/static/fonts/', -]; - + +const STATIC_PREFIXES = [ + '/static/css/', + '/static/js/', + '/static/icons/', + '/static/fonts/', +]; + const CACHE_EXACT = ['/manifest.json']; function isHttpRequest(req) { @@ -29,9 +29,9 @@ function isNetworkOnly(req) { const accept = req.headers.get('Accept') || ''; if (accept.includes('text/event-stream')) return true; const url = new URL(req.url); - return NETWORK_ONLY_PREFIXES.some(p => url.pathname.startsWith(p)); -} - + return NETWORK_ONLY_PREFIXES.some(p => url.pathname.startsWith(p)); +} + function isStaticAsset(req) { const url = new URL(req.url); if (CACHE_EXACT.includes(url.pathname)) return true; @@ -62,19 +62,19 @@ function fallbackResponse(req, status = 503) { headers: { 'Content-Type': 'text/plain; charset=utf-8' }, }); } - -self.addEventListener('install', (e) => { - self.skipWaiting(); -}); - -self.addEventListener('activate', (e) => { - e.waitUntil( - caches.keys().then(keys => - Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))) - ).then(() => self.clients.claim()) - ); -}); - + +self.addEventListener('install', (e) => { + self.skipWaiting(); +}); + +self.addEventListener('activate', (e) => { + e.waitUntil( + caches.keys().then(keys => + Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))) + ).then(() => self.clients.claim()) + ); +}); + self.addEventListener('fetch', (e) => { const req = e.request; @@ -90,18 +90,18 @@ self.addEventListener('fetch', (e) => { ); return; } - - // Cache-first for static assets - if (isStaticAsset(req)) { - e.respondWith( - caches.open(CACHE_NAME).then(cache => - cache.match(req).then(cached => { - if (cached) { - // Revalidate in background - fetch(req).then(res => { - if (res && res.status === 200) cache.put(req, res.clone()); - }).catch(() => {}); - return cached; + + // Cache-first for static assets + if (isStaticAsset(req)) { + e.respondWith( + caches.open(CACHE_NAME).then(cache => + cache.match(req).then(cached => { + if (cached) { + // Revalidate in background + fetch(req).then(res => { + if (res && res.status === 200) cache.put(req, res.clone()); + }).catch(() => {}); + return cached; } return fetch(req).then(res => { if (res && res.status === 200) cache.put(req, res.clone()); @@ -111,12 +111,12 @@ self.addEventListener('fetch', (e) => { ) ); return; - } - - // Network-first for HTML pages - e.respondWith( - fetch(req).catch(() => - caches.match(req).then(cached => cached || new Response('Offline', { status: 503 })) - ) - ); -}); + } + + // Network-first for HTML pages + e.respondWith( + fetch(req).catch(() => + caches.match(req).then(cached => cached || new Response('Offline', { status: 503 })) + ) + ); +}); diff --git a/templates/index.html b/templates/index.html index f3415b4..0ca2dfc 100644 --- a/templates/index.html +++ b/templates/index.html @@ -10,7 +10,7 @@ - +