diff --git a/packages/frontend/src/admin/AdminExternalLinksPage.tsx b/packages/frontend/src/admin/AdminExternalLinksPage.tsx index 8633765..2b1f846 100644 --- a/packages/frontend/src/admin/AdminExternalLinksPage.tsx +++ b/packages/frontend/src/admin/AdminExternalLinksPage.tsx @@ -7,11 +7,11 @@ function generateId(): string { return Date.now().toString(36) + Math.random().toString(36).slice(2, 10); } -/** Favicon-URL aus einer Website-URL ableiten (Google Favicon Service) */ +/** Favicon-URL direkt von der Webseite laden */ function getFaviconUrl(url: string): string | null { try { - const domain = new URL(url).hostname; - return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`; + const parsed = new URL(url); + return `${parsed.origin}/favicon.ico`; } catch { return null; } diff --git a/packages/frontend/src/shell/AppLayout.tsx b/packages/frontend/src/shell/AppLayout.tsx index 0e586df..2285c5d 100644 --- a/packages/frontend/src/shell/AppLayout.tsx +++ b/packages/frontend/src/shell/AppLayout.tsx @@ -12,11 +12,11 @@ interface ExternalLink { sortOrder: number; } -/** Favicon-URL aus einer Website-URL ableiten (Google Favicon Service) */ +/** Favicon-URL direkt von der Webseite laden */ function getFaviconUrl(url: string): string | null { try { - const domain = new URL(url).hostname; - return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`; + const parsed = new URL(url); + return `${parsed.origin}/favicon.ico`; } catch { return null; } @@ -82,37 +82,52 @@ export function AppLayout() { { + e.preventDefault(); + window.open( + link.url, + link.label, + 'popup,noopener', + ); + }} className={styles.navLink} > - {favicon ? ( - - ) : ( - - - - - - )} + { + // Fallback: erstes Zeichen des Labels als Text-Icon + const el = e.target as HTMLImageElement; + el.style.display = 'none'; + const fallback = el.nextElementSibling; + if (fallback) + (fallback as HTMLElement).style.display = + 'flex'; + }} + /> + + {link.label.charAt(0).toUpperCase()} + {link.label}