web: Domain-spezifische Favicons und App-Icons für alle drei Marken (R5.4)

Eigene Icon-Sets unter public/icons/{pressekonto,presseecho,businessportal24}
(SVG-Favicon + Touch-/App-Icons); ThemeHelper mappt das aktive Theme auf den
Icon-Ordner (Portal/Admin nutzt den pressekonto-Satz), alle Layout-Heads
binden Favicon + apple-touch-icon domain-abhängig ein.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-21 07:50:21 +00:00
parent 42e56a7d81
commit 58c773b153
36 changed files with 84 additions and 14 deletions

View file

@ -34,13 +34,39 @@ class ThemeHelper
}
/**
* Get the favicon path based on the current theme
* Map the current theme to its icon folder under public/icons.
*
* Das Portal-/Admin-Theme läuft auf pressekonto.test und nutzt daher
* den pressekonto-Iconsatz.
*/
public static function getFaviconPath(): string
public static function getIconFolder(): string
{
$theme = config('app.theme', 'portal');
return "img/favicons/{$theme}-favicon.ico";
$folderMap = [
'portal' => 'pressekonto',
'pressekonto' => 'pressekonto',
'presseecho' => 'presseecho',
'businessportal24' => 'businessportal24',
];
return $folderMap[$theme] ?? 'pressekonto';
}
/**
* Get the favicon (SVG) path based on the current theme.
*/
public static function getFaviconPath(): string
{
return 'icons/'.self::getIconFolder().'/favicon.svg';
}
/**
* Get the larger app/touch icon (SVG) path based on the current theme.
*/
public static function getAppIconPath(): string
{
return 'icons/'.self::getIconFolder().'/icon.svg';
}
/**

View file

@ -0,0 +1,34 @@
# Icon-Set pressekonto / presseecho / businessportal24
## Dateien pro Domain
- `favicon.svg` — Option A (dunkle Kachel, Akzent-Initiale), primäres Favicon
- `favicon.ico` — Legacy-Fallback (16/32/48 px eingebettet)
- `favicon-16/32/48.png` — PNG-Fallbacks
- `icon.svg` — Option B (Duo-Monogramm), Quelle für große Icons
- `apple-touch-icon.png` — 180 px (iOS)
- `icon-192.png`, `icon-512.png` — PWA / Web-App-Manifest
## Einbindung im `<head>` (pro Portal aus dem jeweiligen Ordner)
```html
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
```
## `site.webmanifest` (Icons-Block)
```json
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
```
## Hinweise
- PNGs/ICO wurden mit Liberation Sans/Serif Bold gerendert (metrisch kompatibel
zu Arial bzw. Times). Die SVGs nutzen den Font-Stack Helvetica/Arial bzw.
Georgia/Times. Sobald die finalen Logo-Fonts feststehen, einfach im SVG
`font-family` tauschen und PNGs neu exportieren.
- Eckenradius: 14 % der Kantenlänge (8/56), konsistent über alle Größen.
- Akzentfarben auf dunklem Grund sind bewusst aufgehellt (Kontrast bei 16 px):
Gold #c9954f, Grün #8fae7d, Rost #d97b54.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#2b3644"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="Georgia, 'Times New Roman', 'Liberation Serif', serif" font-weight="700" font-size="30.7"><tspan fill="#d97b54">24</tspan></text></svg>

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#f6f2ec"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="Georgia, 'Times New Roman', 'Liberation Serif', serif" font-weight="700" font-size="24.3"><tspan fill="#2b3644">b</tspan><tspan fill="#c0512f">24</tspan></text></svg>

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#23281f"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="Georgia, 'Times New Roman', 'Liberation Serif', serif" font-weight="700" font-size="39.7"><tspan fill="#8fae7d">e</tspan></text></svg>

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#f4f3ea"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="Georgia, 'Times New Roman', 'Liberation Serif', serif" font-weight="700" font-size="32.0"><tspan fill="#23281f">p</tspan><tspan fill="#45603e">e</tspan></text></svg>

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#1e2a3a"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="'Helvetica Neue', Arial, 'Liberation Sans', sans-serif" font-weight="700" font-size="37.1"><tspan fill="#c9954f">k</tspan></text></svg>

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="9.1" fill="#f7f4ec"/><text x="32" y="32" text-anchor="middle" dominant-baseline="central" font-family="'Helvetica Neue', Arial, 'Liberation Sans', sans-serif" font-weight="700" font-size="29.4"><tspan fill="#1e2a3a">p</tspan><tspan fill="#b08039">k</tspan></text></svg>

After

Width:  |  Height:  |  Size: 363 B

BIN
public/icons/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -46,7 +46,8 @@
<title>{{ $pageTitle }}</title>
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" />
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml" />
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}" />
@include('partials.local-fonts')

View file

@ -11,8 +11,9 @@
<title>@yield('title', $domainName ?? 'Admin - ' . config('app.name'))</title>
<!-- Favicon -->
<link rel="icon" href="{{ asset('img/favicons/admin-favicon.ico') }}">
<!-- Domain-spezifisches Favicon (Portal/Admin nutzt pressekonto-Icons) -->
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}">
<!-- Fonts -->
@include('partials.local-fonts')

View file

@ -9,7 +9,8 @@
<title>@yield('title', $domainName ?? config('app.name', 'Laravel'))</title>
<!-- Domain-spezifisches Favicon -->
<link rel="icon" href="{{ asset('img/favicons/' . $theme . '-favicon.ico') }}">
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}">
<!-- Fonts -->
@include('partials.local-fonts')

View file

@ -3,9 +3,9 @@
<title>{{ $title ?? config('app.name') }}</title>
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
{{-- Domain-spezifische Icons (pressekonto/presseecho/businessportal24) --}}
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}">
@include('partials.local-fonts')

View file

@ -3,9 +3,9 @@
<title>{{ $title ?? config('app.name') }}</title>
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
{{-- Domain-spezifische Icons (pressekonto/presseecho/businessportal24) --}}
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}">
{{-- Hub × FluxUI Phase 1: Inter Tight + JetBrains Mono + Source Serif 4
(Source Serif 4 nur für brand-mark in Headern, deshalb mitgeladen). --}}

View file

@ -67,7 +67,8 @@
@yield('structured_data')
<!-- Domain-spezifisches Favicon -->
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}">
<link rel="icon" href="{{ asset(\App\Helpers\ThemeHelper::getFaviconPath()) }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ asset(\App\Helpers\ThemeHelper::getAppIconPath()) }}">
<!-- Fonts -->
@include('partials.local-fonts')