// === Branding === export type FontCategory = 'serif' | 'sans-serif' | 'monospace'; export interface FontConfig { family: string; source: 'google' | 'url' | 'local'; weights?: number[]; url?: string; /** Font category — controls the fallback chain when the primary family * fails to load. Defaults preserve prior behavior: `'serif'` for header, * `'sans-serif'` for body, `'monospace'` for mono. * * Set explicitly when the consumer's chosen family doesn't match the * slot's default category — e.g. set `header: { family: 'Inter', * category: 'sans-serif' }` so the fallback chain is * `'Inter', system-ui, sans-serif` instead of `'Inter', Georgia, serif`. */ category?: FontCategory; } export interface LogoConfig { path: string; alt: string; url?: string; remoteUrl?: string; light?: string; dark?: string; localLight?: string; localDark?: string; } export interface FaviconIcon { /** The `rel` attribute: "icon", "shortcut icon", "apple-touch-icon", "manifest". */ rel: string; /** Icon file path. Bare filenames ("favicon.ico") get BASE_PATH-prefixed * automatically; absolute URLs and root-relative paths are emitted as-is. */ href: string; /** Optional MIME type hint (e.g., "image/png", "image/svg+xml"). */ type?: string; /** Optional sizes attribute (e.g., "180x180", "any"). */ sizes?: string; } export interface FaviconConfig { /** Path prefix for all favicon URLs. Defaults to BASE_PATH-aware '/'. */ base_path?: string; /** Skip emitting the default block. Use when the consumer provides * their own icons via `icons` or wants zero favicon tags. */ skip_default_links?: boolean; /** Consumer-declared icons (DATA, not HTML). Replaces the default 16-link * set when non-empty. Each entry renders to a single tag with * BASE_PATH-aware href. */ icons?: FaviconIcon[]; /** @deprecated Use `icons` instead. Raw HTML emitted verbatim — impossible * to validate, can't be safely BASE_PATH-rewritten. Kept for backward * compat; emits a console warning when used. */ links_html?: string; /** Consumer-side directory (relative to cwd) holding canonical favicon files. * The CLI's favicon step copies these into public/, overriding defaults. */ source_dir?: string; } export interface SiteBranding { primaryColor?: string; darkColor?: string; fonts?: { /** Most prominent display text on each page — home hero, concept name * on the detail page, group/dataset title. No category is dictated; * pick `serif`, `sans-serif`, or `monospace` for any slot. */ title?: FontConfig; /** Section headings (h2–h6). */ heading?: FontConfig; /** Backward-compat alias for `heading` (deprecated). */ header?: FontConfig; /** Paragraph text, lists, table cells. */ body?: FontConfig; /** Code blocks, inline code, kbd. */ mono?: FontConfig; }; logo?: LogoConfig; footerLogo?: LogoConfig; favicon?: string | FaviconConfig; ownerName?: string; ownerUrl?: string; } // === Features === export interface PoweredByConfig { message?: string; url?: string; } export interface SiteFeatures { news?: boolean; stats?: boolean; graph?: boolean; about?: boolean; search?: boolean; poweredBy?: PoweredByConfig; } // === Analytics === export interface AnalyticsConfig { googleAnalyticsId?: string; } // === Navigation === export interface NavItem { label: string; route: string; } export interface SocialLinks { github?: string; twitter?: string; [key: string]: string | undefined; } // === Routing === export type RoutingType = 'site' | 'url'; export interface RoutingEntry { uri: string; type: RoutingType; targetDataset?: string; baseUrl?: string; url?: string; label: string; } // === Dataset === export type DatasetColorSpec = string | { light: string; dark: string }; export interface DatasetConfig { id: string; uri: string; uriAliases?: string[]; gcrPackage: string; sourceRepo?: string; localPath?: string; title: string; description?: string; owner?: string; /** * Dataset accent color. Accepts either a single hex (applied to both * light and dark modes) or an explicit `{ light, dark }` pair. * Per-deployment overrides via `site-config.json` `colors.dataset[id]` * take precedence. */ color?: DatasetColorSpec; tags?: string[]; languageOrder?: string[]; ref?: string; refAliases?: string[]; downloads?: string[]; translations?: Record; } // === Contributors === export interface Contributor { name: string; role?: string; organization?: string; url?: string; email?: string; } // === Downloads === export interface BulkFormatInfo { file: string; format: string; size: number; } export const FORMAT_LABELS: Record = { turtle: 'Turtle (RDF)', jsonld: 'JSON-LD (SKOS)', tbx: 'TBX-XML', jsonl: 'JSONL', yaml: 'YAML', }; // === Pages === /** * Page type tag. Any string is allowed — built-in tags are listed in * `page-types.ts` PAGE_TYPES registry. Adding a new built-in type is * a registry entry, not an edit to this union. */ export type PageType = string; export interface PageConfig { type: PageType; route: string; title: string; icon: string; source?: string; datasetScoped?: boolean; } // === Dataset Groups === /** * Kind of dataset group. Determines how the group is rendered in the sidebar * and home page, and what semantic relationships between members are assumed. * * - `lineage` — same vocabulary, different editions (e.g. VIML 1968/2000/2013/2022). * Members have temporal ordering and a supersession chain. Rendered as a * timeline with year badges and "current" markers. * * - `topic` — different vocabularies on the same subject (e.g. three SDOs * publishing "intelligent transport systems" terminology). Members may * overlap in concepts but have no temporal ordering. Rendered as a card * grid with overlap indicators. * * - `family` — related vocabularies from the same publisher or program * (e.g. all OIML publications). Hierarchical grouping, no required * relationships between members. Rendered as a flat list under a labeled * header. * * - `collection` — curated bundle of datasets (e.g. "Starter pack for new * metrologists"). Arbitrary selection, often cross-publisher. Rendered as * a featured card with custom descriptions. * * - `default` (omitted) — backward-compatible flat list. No special * semantics. Used when no `kind` is specified. * * The registry in `src/config/group-types.ts` maps each kind to its renderer * component, so new kinds can be added without modifying existing code * (open/closed principle). */ export type DatasetGroupKind = 'lineage' | 'topic' | 'family' | 'collection' | 'default'; export interface DatasetGroup { id: string; label: string; description?: string; /** * Group accent color. Same shape as DatasetConfig.color. * Per-deployment overrides via `site-config.json` `colors.group[id]`. */ color?: DatasetColorSpec; datasets: string[]; translations?: Record; /** * Discriminator for the group's semantic type and UX. See DatasetGroupKind * for the full list of supported values. Defaults to 'default' (flat list). * * Replaces the older `series?: boolean` flag — use `kind: lineage` instead. */ kind?: DatasetGroupKind; /** * For lineage series: the dataset id of the current (newest valid) edition. * If omitted, the newest member by year (or last in `datasets` order) is * used. Setting this explicitly avoids misdetection when only a subset of * editions happen to be loaded. */ current?: string; /** * @deprecated Use `kind: 'lineage'` instead. Still respected as a * backward-compat shorthand: `series: true` is treated as `kind: 'lineage'`. */ series?: boolean; } // === Site Config === export interface SiteColors { /** Per-dataset color overrides. Keyed by dataset id. */ dataset?: Record; /** Per-group color overrides. Keyed by group id. */ group?: Record; /** Per-relation-type color overrides. Keyed by type id (e.g. "supersedes"). */ relationshipType?: Record; /** Per-relation-category color overrides. Keyed by category id (e.g. "lifecycle"). */ relationshipCategory?: Record; /** Per-concept-status color overrides. Keyed by status id. */ conceptStatus?: Record; /** Per-group-kind color overrides. Keyed by DatasetGroupKind. */ groupKind?: Record; } export interface SiteConfig { id: string; domain: string; uriBase?: string; basePath?: string; title: string; subtitle?: string; description?: string; translations?: Record; datasets: DatasetConfig[]; datasetGroups?: DatasetGroup[]; routing: RoutingEntry[]; branding: SiteBranding; analytics?: AnalyticsConfig; features?: SiteFeatures; social?: SocialLinks; nav?: NavItem[]; footerNav?: NavItem[]; /** Color overrides. Merged over `data/colors.json` defaults. */ colors?: SiteColors; defaults: { language?: string; languageOrder?: string[]; mainLanguages?: string[]; }; email?: string; pages?: PageConfig[]; contributors?: Contributor[]; copyright?: string; }