103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { ImageResponse } from "next/og";
|
|
|
|
import { routing } from "@/i18n/routing";
|
|
|
|
import { getSiteSettings, getSiteSettingsMediaBindings } from "./app-config";
|
|
|
|
const INTERNAL_FAVICON_PATH = "/favicon.ico";
|
|
const INTERNAL_APPLE_ICON_PATH = "/apple-icon.png";
|
|
const INTERNAL_MANIFEST_PATH = "/manifest.webmanifest";
|
|
const DEFAULT_ICON_VERSION = "default";
|
|
|
|
type SiteIconInput = {
|
|
siteName: string;
|
|
faviconAssetId?: string | null;
|
|
faviconUrl?: string | null;
|
|
};
|
|
|
|
type SiteIconUrls = {
|
|
siteName: string;
|
|
version: string;
|
|
faviconHref: string;
|
|
appleIconHref: string;
|
|
manifestHref: string;
|
|
faviconAssetUrl: string | null;
|
|
};
|
|
|
|
function appendVersionToUrl(url: string, version: string): string {
|
|
const base = url.startsWith("http://") || url.startsWith("https://") ? undefined : "https://local.invalid";
|
|
const resolved = new URL(url, base);
|
|
|
|
resolved.searchParams.set("v", version);
|
|
|
|
if (base) {
|
|
return `${resolved.pathname}${resolved.search}${resolved.hash}`;
|
|
}
|
|
|
|
return resolved.toString();
|
|
}
|
|
|
|
function getFallbackLabel(siteName: string): string {
|
|
const firstCharacter = siteName.trim().charAt(0).toUpperCase() || "M";
|
|
|
|
return firstCharacter;
|
|
}
|
|
|
|
export function buildSiteIconUrls(input: SiteIconInput): SiteIconUrls {
|
|
const siteName = input.siteName.trim() || "Moh";
|
|
const version = input.faviconAssetId?.trim() || DEFAULT_ICON_VERSION;
|
|
|
|
return {
|
|
siteName,
|
|
version,
|
|
faviconHref: appendVersionToUrl(INTERNAL_FAVICON_PATH, version),
|
|
appleIconHref: appendVersionToUrl(INTERNAL_APPLE_ICON_PATH, version),
|
|
manifestHref: appendVersionToUrl(INTERNAL_MANIFEST_PATH, version),
|
|
faviconAssetUrl: input.faviconUrl ? appendVersionToUrl(input.faviconUrl, version) : null,
|
|
};
|
|
}
|
|
|
|
export async function getDynamicSiteIconUrls(): Promise<SiteIconUrls> {
|
|
const [settings, bindings] = await Promise.all([getSiteSettings(), getSiteSettingsMediaBindings()]);
|
|
const defaultLocaleSettings = settings.locales[routing.defaultLocale];
|
|
|
|
return buildSiteIconUrls({
|
|
siteName: defaultLocaleSettings.siteName,
|
|
faviconAssetId: bindings.favicon?.assetId,
|
|
faviconUrl: bindings.favicon?.url,
|
|
});
|
|
}
|
|
|
|
export function buildFallbackIconResponse(siteName: string, size: number) {
|
|
const label = getFallbackLabel(siteName);
|
|
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
background: "linear-gradient(135deg, #111827 0%, #0f766e 100%)",
|
|
color: "#f8fafc",
|
|
fontSize: size * 0.52,
|
|
fontWeight: 700,
|
|
letterSpacing: "-0.08em",
|
|
borderRadius: size * 0.22,
|
|
}}
|
|
>
|
|
{label}
|
|
</div>
|
|
),
|
|
{
|
|
width: size,
|
|
height: size,
|
|
headers: {
|
|
"Cache-Control": "no-store, max-age=0",
|
|
},
|
|
},
|
|
);
|
|
}
|