Fix PWA install: static manifest.json + proper SVG icon

- Replace blob: manifest (ignored by Chrome) with static manifest.json
- Replace data: URL icon with real icon.svg file
- Link manifest and apple-touch-icon directly in <head>
- Remove blob/data URL generation from app.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-25 17:20:55 +02:00
1 parent 042ce0b095
commit 56c5662a11
7 files changed
+58 -11

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
FROM nginx:alpine
COPY index.html styles.css app.js sw.js /usr/share/nginx/html/
COPY index.html styles.css app.js sw.js manifest.json icon.svg /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
-8
View File
@@ -1251,14 +1251,6 @@ async function loadArtists(){
// ─── PWA ───
function injectPWA(){
const m={name:'NovaSonic',short_name:'NovaSonic',description:'Subsonic/Navidrome Music Client',
start_url:'index.html',display:'standalone',background_color:'#07070f',theme_color:'#07070f',
icons:[{src:"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%23e8a020'/><text y='.9em' font-size='70' x='15'>&#9835;</text></svg>",sizes:'192x192',type:'image/svg+xml'}]};
try{
const blob=new Blob([JSON.stringify(m)],{type:'application/json'});
const link=document.createElement('link');link.rel='manifest';link.href=URL.createObjectURL(blob);
document.head.appendChild(link);
}catch{}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').catch(() => {});
}
+22
View File
@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" rx="90" fill="#07070f"/>
<rect width="512" height="512" rx="90" fill="url(#bg)"/>
<defs>
<radialGradient id="bg" cx="30%" cy="40%" r="80%">
<stop offset="0%" stop-color="#1a1a2e"/>
<stop offset="100%" stop-color="#07070f"/>
</radialGradient>
</defs>
<!-- Music note -->
<g fill="#e8a020">
<!-- Note head 1 -->
<ellipse cx="180" cy="340" rx="48" ry="36" transform="rotate(-15 180 340)"/>
<!-- Note head 2 -->
<ellipse cx="332" cy="300" rx="48" ry="36" transform="rotate(-15 332 300)"/>
<!-- Stem -->
<rect x="218" y="160" width="18" height="185" rx="9"/>
<rect x="370" y="120" width="18" height="185" rx="9"/>
<!-- Beam -->
<rect x="218" y="160" width="170" height="22" rx="11"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 855 B

+2
View File
@@ -7,6 +7,8 @@
<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="NovaSonic">
<link rel="manifest" href="manifest.json">
<link rel="apple-touch-icon" href="icon.svg">
<title>NovaSonic</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
+25
View File
@@ -0,0 +1,25 @@
{
"name": "NovaSonic",
"short_name": "NovaSonic",
"description": "Self-hosted music streaming PWA",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "portrait-primary",
"background_color": "#07070f",
"theme_color": "#07070f",
"icons": [
{
"src": "icon.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "icon.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "maskable"
}
]
}
+6
View File
@@ -29,6 +29,12 @@ server {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Manifest – short cache so icon/name updates roll out quickly
location = /manifest.json {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Access-Control-Allow-Origin "*";
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
+2 -2
View File
@@ -1,5 +1,5 @@
const CACHE = 'ns-v16';
const PRECACHE = ['/', 'index.html', 'styles.css', 'app.js', 'sw.js'];
const CACHE = 'ns-v17';
const PRECACHE = ['/', 'index.html', 'styles.css', 'app.js', 'sw.js', 'manifest.json', 'icon.svg'];
const SKIP_URLS = ['/rest/stream', '/rest/download', '/config.js'];
self.addEventListener('install', e => {