Load rule templates from API
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import type { RuleTemplateDto } from "../create/fetchTemplates";
|
||||
import { templateSummaryFromBody } from "../create/templateReviewMapping";
|
||||
import type { GovernanceTemplateCatalogEntry } from "./governanceTemplateCatalog";
|
||||
import {
|
||||
GOVERNANCE_TEMPLATE_CATALOG,
|
||||
getGovernanceTemplateCatalogEntry,
|
||||
governanceTemplateIconPath,
|
||||
} from "./governanceTemplateCatalog";
|
||||
|
||||
/** Matches TemplateReviewCard when slug is absent from the Figma catalog. */
|
||||
export const TEMPLATE_GRID_FALLBACK_PRESENTATION = {
|
||||
iconPath: governanceTemplateIconPath("consensus"),
|
||||
backgroundColor: "bg-[var(--color-surface-invert-brand-teal)]",
|
||||
} as const;
|
||||
|
||||
export type TemplateGridCardEntry = GovernanceTemplateCatalogEntry;
|
||||
|
||||
function presentationForSlug(slug: string): Pick<
|
||||
GovernanceTemplateCatalogEntry,
|
||||
"iconPath" | "backgroundColor"
|
||||
> {
|
||||
const catalog = getGovernanceTemplateCatalogEntry(slug);
|
||||
return catalog ?? TEMPLATE_GRID_FALLBACK_PRESENTATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* One grid card: API copy + Figma icon/surface from catalog (or fallback).
|
||||
*/
|
||||
export function ruleTemplateToGridEntry(template: RuleTemplateDto): TemplateGridCardEntry {
|
||||
const pres = presentationForSlug(template.slug);
|
||||
const description = templateSummaryFromBody(template.description, template.body);
|
||||
return {
|
||||
slug: template.slug,
|
||||
title: template.title,
|
||||
description,
|
||||
iconPath: pres.iconPath,
|
||||
backgroundColor: pres.backgroundColor,
|
||||
};
|
||||
}
|
||||
|
||||
const bySlug = (templates: RuleTemplateDto[]) =>
|
||||
new Map(templates.map((t) => [t.slug, t] as const));
|
||||
|
||||
/**
|
||||
* Ordered subset for home: follow `slugOrder`; skip missing slugs.
|
||||
*/
|
||||
export function gridEntriesForSlugOrder(
|
||||
templates: RuleTemplateDto[],
|
||||
slugOrder: readonly string[],
|
||||
): TemplateGridCardEntry[] {
|
||||
const map = bySlug(templates);
|
||||
const out: TemplateGridCardEntry[] = [];
|
||||
for (const slug of slugOrder) {
|
||||
const t = map.get(slug);
|
||||
if (t) out.push(ruleTemplateToGridEntry(t));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home row: prefer API row per slug; if missing, use static Figma catalog entry.
|
||||
*/
|
||||
export function gridEntriesForSlugOrderWithCatalogFallback(
|
||||
templates: RuleTemplateDto[],
|
||||
slugOrder: readonly string[],
|
||||
): TemplateGridCardEntry[] {
|
||||
const map = bySlug(templates);
|
||||
const out: TemplateGridCardEntry[] = [];
|
||||
for (const slug of slugOrder) {
|
||||
const t = map.get(slug);
|
||||
if (t) {
|
||||
out.push(ruleTemplateToGridEntry(t));
|
||||
continue;
|
||||
}
|
||||
const cat = getGovernanceTemplateCatalogEntry(slug);
|
||||
if (cat) out.push(cat);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full templates index: `featured` first, then `sortOrder`, then title.
|
||||
*/
|
||||
export function gridEntriesForFullCatalog(templates: RuleTemplateDto[]): TemplateGridCardEntry[] {
|
||||
const withSort = [...templates].sort((a, b) => {
|
||||
if (a.featured !== b.featured) return a.featured ? -1 : 1;
|
||||
if (a.sortOrder !== b.sortOrder) return a.sortOrder - b.sortOrder;
|
||||
return a.title.localeCompare(b.title);
|
||||
});
|
||||
return withSort.map(ruleTemplateToGridEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marketing `/templates`: use API order when rows exist; otherwise static catalog.
|
||||
*/
|
||||
export function gridEntriesForFullCatalogWithFallback(
|
||||
templates: RuleTemplateDto[],
|
||||
): TemplateGridCardEntry[] {
|
||||
if (templates.length === 0) {
|
||||
return [...GOVERNANCE_TEMPLATE_CATALOG];
|
||||
}
|
||||
return gridEntriesForFullCatalog(templates);
|
||||
}
|
||||
Reference in New Issue
Block a user