feat(admin): Logo und Favicon per Bild-Upload austauschbar
Neue Gruppe "Logo und Favicon" unter Admin > Inhalte mit drei Bildfeldern: Logo (Kopfzeile), optionales Logo fuer dunkle Flaechen (Mobilmenue, Fusszeile, Admin-Leiste; faellt sonst auf das normale Logo zurueck) und Favicon. Leer bleibt alles wie bisher (gezeichnetes Waben-Zeichen bzw. Standard-Icon). - lib/brand.ts liest die Pfade und prueft sie erneut gegen das Upload-Muster, bevor sie in ein src-Attribut gelangen. - Statische app/icon.svg und app/favicon.ico ersetzt durch dynamische app/icon.tsx (512 px PNG) und app/apple-icon.tsx (180 px auf Creme); lib/brand-icon.ts rendert Upload oder Standard-Icon per sharp und liest Dateien nur ueber resolveUploadPath. Cache-Control no-cache, damit ein neues Favicon ohne Tage Verzoegerung erscheint. - /favicon.ico per Rewrite auf /icon, Manifest nutzt /icon. - Hochgeladenes Logo mit fester Hoehe und begrenzter Breite (Kopfzeile mobil 56 px, ab sm 112 px), damit breite Wortmarken nichts sprengen. Uploads bleiben auf Rasterbilder beschraenkt (kein SVG, XSS-Schutz). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
ae2726b0ee
commit
4f442ec06d
19 files changed
+217
-77
No files matched your search
@@ -204,6 +204,7 @@ export default async function AdminInhaltePage() {
|
||||
const current = await loadCurrentValues();
|
||||
|
||||
const groups: { key: ContentFieldDef["group"]; heading: string }[] = [
|
||||
{ key: "brand", heading: t.adminContentPage.groupBrand },
|
||||
{ key: "company", heading: t.adminContentPage.groupCompany },
|
||||
{ key: "shipping", heading: t.adminContentPage.groupShipping },
|
||||
{ key: "home", heading: t.adminContentPage.groupHome },
|
||||
|
||||
@@ -7,6 +7,7 @@ import { logoutAction } from "@/app/konto/actions";
|
||||
import { AdminShell } from "@/components/admin-shell";
|
||||
import { getLocale } from "@/i18n/locale";
|
||||
import { getDictionary } from "@/i18n/get-dictionary";
|
||||
import { getBrandAssets } from "@/lib/brand";
|
||||
|
||||
// Admin-Daten (Bestellungen, Bestand) muessen immer aktuell sein; zudem
|
||||
// entkoppelt das den Docker-Build-Schritt von einer DB-Verbindung.
|
||||
@@ -47,6 +48,7 @@ export default async function AdminLayout({ children }: LayoutProps<"/admin">) {
|
||||
// Seitenleiste. Nur echte Arbeit: bezahlte, noch nicht versendete oder
|
||||
// abgeholte Bestellungen (keine offenen Zahlungen), neue Retouren,
|
||||
// unfreigegebene Bewertungen, neue Firmenanfragen. Reine COUNT-Abfragen.
|
||||
const brand = await getBrandAssets();
|
||||
const [openOrders, openReturns, pendingReviews, newInquiries] = await Promise.all([
|
||||
prisma.order.count({
|
||||
where: { status: { in: ["BEZAHLT", "IN_VORBEREITUNG", "VERSANDBEREIT", "ABHOLBEREIT"] }, archivedAt: null },
|
||||
@@ -59,6 +61,7 @@ export default async function AdminLayout({ children }: LayoutProps<"/admin">) {
|
||||
return (
|
||||
<AdminShell
|
||||
adminName={`${admin.firstName} ${admin.lastName}`}
|
||||
logoSrc={brand.logoInverted}
|
||||
badges={{
|
||||
"/admin/bestellungen": openOrders,
|
||||
"/admin/retouren": openReturns,
|
||||
|
||||
Reference in new issue
Block a user