diff --git a/frontend/src/components/common/DynamicFavicon.tsx b/frontend/src/components/common/DynamicFavicon.tsx index d8226eab..1cade38f 100644 --- a/frontend/src/components/common/DynamicFavicon.tsx +++ b/frontend/src/components/common/DynamicFavicon.tsx @@ -14,13 +14,27 @@ export const DynamicFavicon: React.FC = () => { const existingFavicons = document.querySelectorAll("link[rel*='icon']"); existingFavicons.forEach(favicon => favicon.remove()); - // Create new favicon link - const link = document.createElement('link'); - link.rel = 'icon'; - link.type = 'image/png'; - link.href = settings.branding_favicon_url.startsWith('http') + // Create new favicon link. Derive the MIME type from the file + // extension — hardcoding image/png made SVG (and .ico) favicons + // get declared as PNG, which browsers reject (favicon didn't show). + const href = settings.branding_favicon_url.startsWith('http') ? settings.branding_favicon_url : buildResourceUrl(settings.branding_favicon_url); + const ext = href.split('?')[0].split('.').pop()?.toLowerCase(); + const typeByExt: Record = { + svg: 'image/svg+xml', + png: 'image/png', + ico: 'image/x-icon', + gif: 'image/gif', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + webp: 'image/webp', + }; + + const link = document.createElement('link'); + link.rel = 'icon'; + if (ext && typeByExt[ext]) link.type = typeByExt[ext]; + link.href = href; document.head.appendChild(link); }