"use client"; /* eslint-disable @next/next/no-img-element */ import { MediaKind } from "@prisma/client"; import { FileText, ImageIcon, Search, Type } from "lucide-react"; import { useState } from "react"; import { MediaFieldPicker, type MediaFieldState } from "@/components/root/media-field-picker"; import { AppCard } from "@/components/ui/app-card"; import { CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { PAGE_TITLE_TOKEN, SITE_NAME_TOKEN, type SiteSettings, type SiteSettingsMediaBindings, } from "@/lib/site-settings"; import type { AppLocale } from "@/lib/locale"; import type { MediaOption } from "@/lib/media"; type SiteSettingsFormProps = { action: (formData: FormData) => Promise; initialSettings: SiteSettings; initialBindings: SiteSettingsMediaBindings; mediaOptions: MediaOption[]; }; const localeFields: Array<{ key: AppLocale; label: string; suffix: "Ar" | "En" | "De"; sampleTitle: string; }> = [ { key: "ar", label: "Arabic", suffix: "Ar", sampleTitle: "Home", }, { key: "en", label: "English", suffix: "En", sampleTitle: "About", }, { key: "de", label: "Deutsch", suffix: "De", sampleTitle: "Portfolio", }, ]; function createImageFieldState( assetId: string | null | undefined, url: string | null | undefined, label: string, ): MediaFieldState { if (assetId) { return { mode: "library", assetId, url: "", label, kind: MediaKind.IMAGE, isCleared: false, }; } if (url) { return { mode: "external", assetId: "", url, label, kind: MediaKind.IMAGE, isCleared: false, }; } return { mode: "upload", assetId: "", url: "", label, kind: MediaKind.IMAGE, isCleared: false, }; } function getMediaPreviewUrl( value: MediaFieldState, options: MediaOption[], fallbackUrl: string | null | undefined, ) { if (value.isCleared) { return ""; } if (value.mode === "external") { return value.url || fallbackUrl || ""; } if (value.mode === "library") { return options.find((option) => option.id === value.assetId)?.url ?? fallbackUrl ?? ""; } return fallbackUrl ?? ""; } export function SiteSettingsForm({ action, initialSettings, initialBindings, mediaOptions, }: SiteSettingsFormProps) { const [settings, setSettings] = useState(initialSettings); const [siteLogoLight, setSiteLogoLight] = useState( createImageFieldState( initialBindings.siteLogoLight?.assetId, initialBindings.siteLogoLight?.url, "Site Logo Light", ), ); const [siteLogoDark, setSiteLogoDark] = useState( createImageFieldState( initialBindings.siteLogoDark?.assetId, initialBindings.siteLogoDark?.url, "Site Logo Dark", ), ); const [favicon, setFavicon] = useState( createImageFieldState( initialBindings.favicon?.assetId, initialBindings.favicon?.url, "Favicon", ), ); const [defaultOgImage, setDefaultOgImage] = useState( createImageFieldState( initialBindings.defaultOgImage?.assetId, initialBindings.defaultOgImage?.url, "Default OG Image", ), ); const siteLogoLightPreviewUrl = getMediaPreviewUrl( siteLogoLight, mediaOptions, initialBindings.siteLogoLight?.url, ); const siteLogoDarkPreviewUrl = getMediaPreviewUrl( siteLogoDark, mediaOptions, initialBindings.siteLogoDark?.url, ); const faviconPreviewUrl = getMediaPreviewUrl(favicon, mediaOptions, initialBindings.favicon?.url); const defaultOgImagePreviewUrl = getMediaPreviewUrl( defaultOgImage, mediaOptions, initialBindings.defaultOgImage?.url, ); return (
SEO Basics Diese Einstellungen bilden die globale Basis fuer Seitentitel, Description und Vorschau in Suchmaschinen.

Nutze {" "} {PAGE_TITLE_TOKEN} {" "} fuer den aktuellen Seitentitel. und {" "} {SITE_NAME_TOKEN} {" "} fuer den Namen der aktuellen Sprache.

Beispiel: {" "} {PAGE_TITLE_TOKEN} | {SITE_NAME_TOKEN}

Localized Titles And Copy Diese Werte gelten als globale Standards pro Sprache und werden verwendet, wenn eine Seite keinen eigenen Fallback hat. {localeFields.map((locale) => (

{locale.label}

Globale Standardwerte fuer diese Sprache.

setSettings((current) => ({ ...current, locales: { ...current.locales, [locale.key]: { ...current.locales[locale.key], siteName: event.target.value, }, }, })) } placeholder="Site Name" className="pl-9" />
setSettings((current) => ({ ...current, locales: { ...current.locales, [locale.key]: { ...current.locales[locale.key], titleTemplate: event.target.value, }, }, })) } placeholder="Title Template" className="pl-9" />
setSettings((current) => ({ ...current, locales: { ...current.locales, [locale.key]: { ...current.locales[locale.key], siteDescription: event.target.value, }, }, })) } placeholder="Site Description" className="pl-9" />
setSettings((current) => ({ ...current, locales: { ...current.locales, [locale.key]: { ...current.locales[locale.key], subhead: event.target.value, }, }, })) } placeholder="Subhead" className="pl-9" />
))}
Brand And Preview Images Logo erscheint im Header. Favicon erscheint im Browser. Das Default OG Bild wird fuer Social Sharing genutzt, wenn eine Seite kein eigenes Bild liefert.
Preview Suchmaschine und Social Sharing Vorschau.
{localeFields.map((locale) => { const localeSettings = settings.locales[locale.key]; const previewTitle = localeSettings.titleTemplate.includes(PAGE_TITLE_TOKEN) ? localeSettings.titleTemplate .replace(PAGE_TITLE_TOKEN, locale.sampleTitle) .replaceAll(SITE_NAME_TOKEN, localeSettings.siteName) : `${locale.sampleTitle} | ${localeSettings.siteName}`; return (

{locale.label}

Example page title: {locale.sampleTitle}

{previewTitle}

{localeSettings.siteDescription || "No description"}

{localeSettings.subhead || "No subhead"}

); })}
Header Logo Preview

Light

{siteLogoLightPreviewUrl ? ( Site Logo Light ) : (
Default light logo will be used
)}

Dark

{siteLogoDarkPreviewUrl ? ( Site Logo Dark ) : (
Default dark logo will be used
)}
Search Preview
{faviconPreviewUrl ? ( Favicon ) : (
)}

{settings.locales.de.titleTemplate.includes(PAGE_TITLE_TOKEN) ? settings.locales.de.titleTemplate .replace(PAGE_TITLE_TOKEN, "About") .replaceAll(SITE_NAME_TOKEN, settings.locales.de.siteName) : `About | ${settings.locales.de.siteName}`}

{settings.locales.de.siteDescription || "No description"}

{settings.locales.de.subhead || "No subhead"}

Social Preview
{defaultOgImagePreviewUrl ? ( Default OG ) : (
No OG image selected
)}

{settings.locales.en.titleTemplate.includes(PAGE_TITLE_TOKEN) ? settings.locales.en.titleTemplate .replace(PAGE_TITLE_TOKEN, "Portfolio") .replaceAll(SITE_NAME_TOKEN, settings.locales.en.siteName) : `Portfolio | ${settings.locales.en.siteName}`}

{settings.locales.en.siteDescription || "No description"}

); }