// Which logo an organization's pages show, and where one is fetched from. A file of the contract // because the organization layout, the settings page's preview and the share image and email all // need the same answer, and a rule that three places each re-derive is a rule that drifts. // // An organization has up to two logos, one for each theme: `light` is the logo for a light page, // `dark` the one for a dark page. The fallback is one sentence and this file is where it is kept: // // A theme shows its own logo. When only one is uploaded it shows on both themes. When none is, // the app brand's logo for that theme shows (config/src/brand.ts). // // The first two sentences are `tenantLogo`; the third is what `resolveLogo` adds. import type { BrandView, LogoVariant } from "./view.js" /** The two stored sizes of a raster logo, 1x and 2x (`@conusai-kit/brand/logo`'s standard set). */ export const LOGO_SIZES = ["1x", "2x"] as const export type LogoSize = (typeof LOGO_SIZES)[number] export interface LogoChoice { /** Whose logo it is: the organization's own, or the app brand's. */ readonly source: "tenant" | "app" /** Which of that source's two logos was chosen; it differs from the theme asked for when the other one stood in. */ readonly variant: LogoVariant /** The path of that logo on this app's origin. */ readonly path: string } const other = (variant: LogoVariant): LogoVariant => (variant === "light" ? "dark" : "light") const pathOf = (brand: Pick, variant: LogoVariant): string | null => variant === "light" ? brand.logoLight : brand.logoDark /** The organization's logo for a theme: its own, else the other theme's, else null. */ export function tenantLogo(brand: Pick, theme: LogoVariant): LogoChoice | null { for (const variant of [theme, other(theme)]) { const path = pathOf(brand, variant) if (path !== null) return { source: "tenant", variant, path } } return null } /** The logo for a theme: the organization's (`tenantLogo`), or, when it has none, the app brand's own for that theme. */ export function resolveLogo( brand: Pick | null, app: Readonly>, theme: LogoVariant, ): LogoChoice { return (brand === null ? null : tenantLogo(brand, theme)) ?? { source: "app", variant: theme, path: app[theme] } } /** The address of one stored size of an organization's logo: its path, which carries the content tag, and the size. */ export const logoUrl = (path: string, size: LogoSize): string => `${path}${path.includes("?") ? "&" : "?"}s=${size}`