///|
/// Deterministic, reusable starter brand books for examples and integration tests.
pub struct BrandTemplate {
name : String
description : String
tags : Array[String]
} derive(Debug, Eq)
///|
pub fn BrandTemplate::new(
name : String,
description : String,
tags : Array[String],
) -> BrandTemplate {
{ name, description, tags }
}
///|
pub fn BrandTemplate::minimal() -> BrandBook {
BrandBook::{
name: "Minimal brand template",
tagline: "A small, coherent token set for a new product.",
voice: Voice::{
tone: "direct and helpful",
writing_principles: ["Use plain language", "Show the next action"],
},
assets: AssetSet::{
primary_logo: Logo::{
name: "Minimal mark",
path: "assets/minimal-mark.svg",
min_width_px: 64,
clear_space: Pixels(16),
background: LightOrDark,
},
alternate_logos: [],
imagery_style: "Use product evidence and generous whitespace.",
},
palette: Palette::{
colors: [
ColorToken::hex("primary", "#3157D5", role="primary action"),
ColorToken::hex("ink", "#172033", role="text"),
ColorToken::hex("surface", "#F7F9FC", role="surface"),
],
gradients: [],
},
typography: Typography::{
families: [
FontToken::{
name: "system-ui",
fallback: "-apple-system, BlinkMacSystemFont, sans-serif",
usage: "interface and documentation",
},
],
scale: [
TypeStep::{ name: "body", size_px: 16, line_height_px: 24 },
TypeStep::{ name: "title", size_px: 28, line_height_px: 36 },
],
},
components: [
ComponentSpec::{
name: "Action",
purpose: "Give the user one clear next step.",
anatomy: ["label", "focus ring"],
tokens: ["primary", "surface"],
states: ["default", "focus"],
},
],
forbidden: [
MisuseRule::{
title: "Do not add untracked colors",
reason: "Untracked colors fragment the system.",
replacement: "Use the nearest documented token.",
},
],
metadata: Meta::{
source: "Built-in template",
maintainer: "MoonBit Brandbook",
license: "Apache-2.0",
},
}
}
///|
pub fn BrandTemplate::dark_variant(book : BrandBook) -> BrandBook {
let dark_palette = Palette::{
colors: book.palette.colors.map(fn(color) {
match color.name {
"paper" => { ..color, value: "#111827", role: "dark surface" }
"ink" => { ..color, value: "#F7F9FC", role: "dark text" }
_ => color
}
}),
gradients: book.palette.gradients,
}
{
..book,
name: book.name + " Dark",
tagline: book.tagline + " Optimized for dark surfaces.",
palette: dark_palette,
}
}
///|
pub fn BrandTemplate::light_variant(book : BrandBook) -> BrandBook {
let light_palette = book.palette.light_variant(8)
{ ..book, name: book.name + " Light", palette: light_palette }
}
///|
pub fn BrandTemplate::with_palette(
book : BrandBook,
palette : Palette,
) -> BrandBook {
{ ..book, palette, }
}
///|
pub fn BrandTemplate::with_name(book : BrandBook, name : String) -> BrandBook {
{ ..book, name, }
}
///|
pub fn BrandTemplate::with_tagline(
book : BrandBook,
tagline : String,
) -> BrandBook {
{ ..book, tagline, }
}
///|
pub fn BrandTemplate::with_accent(
book : BrandBook,
name : String,
value : String,
role : String,
) -> BrandBook {
let colors = book.palette.colors
colors.push(ColorToken::hex(name, value, role~))
{ ..book, palette: Palette::{ ..book.palette, colors, } }
}
///|
pub fn BrandTemplate::template_names() -> Array[String] {
["minimal", "dark", "light"]
}
///|
pub fn BrandTemplate::describe() -> String {
"Built-in templates: minimal, dark variant, and light variant."
}
///|
pub fn BrandTemplate::metadata() -> BrandTemplate {
BrandTemplate::new(
"Brandbook starter",
"Deterministic templates for examples, tests, and new projects.",
["tokens", "documentation", "accessibility"],
)
}
///|
pub fn BrandTemplate::to_markdown(self : BrandTemplate) -> String {
"## " +
self.name +
"\n\n" +
self.description +
"\n\nTags: " +
self.tags.join(", ")
}
///|
pub fn BrandTemplate::to_json(self : BrandTemplate) -> String {
"{\"name\":\"" +
json_escape(self.name) +
"\",\"description\":\"" +
json_escape(self.description) +
"\",\"tags\":[" +
self.tags.map(fn(tag) { "\"" + json_escape(tag) + "\"" }).join(",") +
"]}"
}
///|
pub fn BrandTemplate::is_named(self : BrandTemplate, name : String) -> Bool {
normalize_identifier(self.name) == normalize_identifier(name)
}
///|
pub fn BrandTemplate::tagged(self : BrandTemplate, tag : String) -> Bool {
self.tags.any(fn(value) {
normalize_identifier(value) == normalize_identifier(tag)
})
}