Files

175 lines
5.2 KiB
TypeScript

import type { AppLocale } from "./locale";
export const SITE_NAME_KEY = "siteName";
export const SITE_SETTINGS_KEY = "site_settings";
export const SITE_SETTINGS_ENTITY_TYPE = "site-settings";
export const SITE_SETTINGS_ENTITY_ID = "global";
export const SITE_SETTINGS_FAVICON_FIELD_KEY = "favicon";
export const SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY = "defaultOgImage";
export const SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY = "siteLogoLight";
export const SITE_SETTINGS_LOGO_DARK_FIELD_KEY = "siteLogoDark";
export const PAGE_TITLE_TOKEN = "{pageTitle}";
export const SITE_NAME_TOKEN = "{siteName}";
export const DEFAULT_SITE_NAME = "moh-sass";
export const DEFAULT_SITE_DESCRIPTION = "Multilingual Next.js base project";
export const DEFAULT_SITE_PRIMARY_COLOR = "#dc5a35";
type SiteLocaleSettings = {
siteName: string;
titleTemplate: string;
siteDescription: string;
subhead: string;
};
type SiteBrandSettings = {
primaryColor: string;
};
export type SiteSettings = {
defaultLocale: AppLocale;
brand: SiteBrandSettings;
locales: Record<AppLocale, SiteLocaleSettings>;
};
export type SiteSettingsMediaBinding = {
assetId: string;
url: string;
version: string;
};
export type SiteSettingsMediaBindings = {
siteLogoLight: SiteSettingsMediaBinding | null;
siteLogoDark: SiteSettingsMediaBinding | null;
favicon: SiteSettingsMediaBinding | null;
defaultOgImage: SiteSettingsMediaBinding | null;
};
function normalizeSiteLocaleSettings(
input: unknown,
fallbackName: string,
fallbackDescription: string,
): SiteLocaleSettings {
const value = input && typeof input === "object" ? (input as Record<string, unknown>) : {};
return {
siteName:
typeof value.siteName === "string" && value.siteName.trim()
? value.siteName.trim()
: fallbackName,
titleTemplate:
typeof value.titleTemplate === "string" &&
value.titleTemplate.trim() &&
value.titleTemplate.includes(PAGE_TITLE_TOKEN)
? value.titleTemplate.trim()
: `${PAGE_TITLE_TOKEN} | ${SITE_NAME_TOKEN}`,
siteDescription:
typeof value.siteDescription === "string"
? value.siteDescription.trim()
: fallbackDescription,
subhead: typeof value.subhead === "string" ? value.subhead.trim() : "",
};
}
export function normalizeSiteDefaultLocale(input: unknown): AppLocale {
return input === "ar" || input === "en" || input === "de" ? input : "de";
}
export function normalizeSitePrimaryColor(input: unknown): string {
if (typeof input !== "string") {
return DEFAULT_SITE_PRIMARY_COLOR;
}
const value = input.trim();
return /^#([0-9a-fA-F]{6})$/.test(value) ? value.toLowerCase() : DEFAULT_SITE_PRIMARY_COLOR;
}
export function getDefaultSiteSettingsMediaBindings(): SiteSettingsMediaBindings {
return {
siteLogoLight: null,
siteLogoDark: null,
favicon: null,
defaultOgImage: null,
};
}
export function buildDefaultSiteSettings(fallbackName = DEFAULT_SITE_NAME): SiteSettings {
return {
defaultLocale: "de",
brand: {
primaryColor: DEFAULT_SITE_PRIMARY_COLOR,
},
locales: {
ar: {
siteName: fallbackName,
titleTemplate: `${PAGE_TITLE_TOKEN} | ${SITE_NAME_TOKEN}`,
siteDescription: DEFAULT_SITE_DESCRIPTION,
subhead: "",
},
en: {
siteName: fallbackName,
titleTemplate: `${PAGE_TITLE_TOKEN} | ${SITE_NAME_TOKEN}`,
siteDescription: DEFAULT_SITE_DESCRIPTION,
subhead: "",
},
de: {
siteName: fallbackName,
titleTemplate: `${PAGE_TITLE_TOKEN} | ${SITE_NAME_TOKEN}`,
siteDescription: DEFAULT_SITE_DESCRIPTION,
subhead: "",
},
},
};
}
export function parseSiteSettingsValue(
rawValue: string | null | undefined,
fallbackName = DEFAULT_SITE_NAME,
): SiteSettings {
const defaults = buildDefaultSiteSettings(fallbackName);
if (!rawValue) {
return defaults;
}
try {
const parsed = JSON.parse(rawValue) as Record<string, unknown>;
const locales = parsed.locales && typeof parsed.locales === "object"
? (parsed.locales as Record<string, unknown>)
: {};
const siteSettings: SiteSettings = {
defaultLocale: normalizeSiteDefaultLocale(parsed.defaultLocale),
brand: {
primaryColor: normalizeSitePrimaryColor(
parsed.brand && typeof parsed.brand === "object"
? (parsed.brand as Record<string, unknown>).primaryColor
: undefined,
),
},
locales: {
ar: normalizeSiteLocaleSettings(
locales.ar && typeof locales.ar === "object" ? (locales.ar as Record<string, unknown>) : {},
defaults.locales.ar.siteName,
defaults.locales.ar.siteDescription,
),
en: normalizeSiteLocaleSettings(
locales.en && typeof locales.en === "object" ? (locales.en as Record<string, unknown>) : {},
defaults.locales.en.siteName,
defaults.locales.en.siteDescription,
),
de: normalizeSiteLocaleSettings(
locales.de && typeof locales.de === "object" ? (locales.de as Record<string, unknown>) : {},
defaults.locales.de.siteName,
defaults.locales.de.siteDescription,
),
},
};
return siteSettings;
} catch {
return defaults;
}
}