internationalscholarsprogram/handbook-engine
0
1"""Centralized handbook visual theme — single source of truth.2 3All colour values, font sizes, spacing, and rendering tokens live here.4Templates, CSS generation, and renderers reference this module instead5of hardcoding visual rules.6 7Spec source: ISP Handbook Enhancement Guidelines + sample PDF.8"""9 10from __future__ import annotations11 12from dataclasses import dataclass, field13 14 15# ── Colour palette ──────────────────────────────────────────────16 17@dataclass(frozen=True)18class Colors:19 """Every colour used in the handbook, named by purpose."""20 21 heading_blue: str = "#0263A3"22 heading_green: str = "#199970"23 body_text: str = "#000000"24 toc_text: str = "#111111"25 note_red: str = "#C00000"26 link_blue: str = "#0263A3"27 benefits_header_bg: str = "#00F600"28 benefits_header_fg: str = "#FFFFFF"29 benefit_item_bg: str = "#00FCFC"30 benefit_item_fg: str = "#000000"31 school_info_green: str = "#199970"32 table_border: str = "#333333"33 table_header_bg: str = "#E6E6E6"34 table_header_fg: str = "#333333"35 toc_dots: str = "#777777"36 muted: str = "#666666"37 note_bg: str = "#F7F8FA"38 note_border: str = "#BBBBBB"39 page_bg: str = "#FFFFFF"40 41 42# ── Typography ──────────────────────────────────────────────────43 44@dataclass(frozen=True)45class Typography:46 """Font families, sizes, weights, and line-heights."""47 48 font_family: str = "'Century Gothic', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"49 font_size_body: str = "10pt"50 font_size_h1: str = "12pt"51 font_size_h2: str = "12pt"52 font_size_h3: str = "10pt"53 font_size_toc_heading: str = "12pt"54 font_size_toc_item: str = "10pt"55 font_size_table: str = "9.5px"56 font_size_programs_table: str = "8.5px"57 font_size_career_list: str = "8.5px"58 font_size_note: str = "9.5px"59 font_size_benefits_header: str = "10.5px"60 font_size_benefit_item: str = "10px"61 font_size_school_name: str = "12pt"62 font_size_summary_label: str = "10.5px"63 font_size_summary_value: str = "9.5px"64 font_size_qualify: str = "10px"65 line_height_body: str = "1.4"66 line_height_heading: str = "1.2"67 line_height_table: str = "1.25"68 69 70# ── Spacing / margins ──────────────────────────────────────────71 72@dataclass(frozen=True)73class Spacing:74 """Page geometry and element margins. All margins: 2.54cm."""75 76 page_margin_top: str = "2.54cm"77 page_margin_right: str = "2.54cm"78 page_margin_bottom: str = "2.54cm"79 page_margin_left: str = "2.54cm"80 paragraph_margin: str = "2px 0 8px"81 heading_margin_h1: str = "12px 0 6px"82 heading_margin_h2: str = "10px 0 4px"83 list_margin: str = "2px 0 8px 18px"84 note_padding: str = "6px 8px"85 note_margin: str = "6px 0 8px"86 table_margin: str = "6px 0 10px"87 table_cell_padding: str = "5px 6px"88 benefits_margin: str = "4px 0 4px"89 school_top_summary_width: str = "58%"90 school_top_campus_width: str = "42%"91 92 93# ── Table column widths ────────────────────────────────────────94 95@dataclass(frozen=True)96class ProgramTableColumns:97 """Fixed widths for the 5-column programs table."""98 99 program: str = "30%"100 designation: str = "20%"101 entrance_exam: str = "20%"102 funding: str = "30%"103 104 105# ── Bullet characters ──────────────────────────────────────────106 107@dataclass(frozen=True)108class Bullets:109 """Bullet characters used throughout the handbook."""110 111 primary: str = "\u27A2" # ➢112 benefit: str = "\u2022" # •113 career: str = "disc" # CSS list-style-type for career lists114 115 116# ── Render-block type registry ──────────────────────────────────117 118BLOCK_TYPES = (119 "heading_1",120 "heading_2",121 "paragraph",122 "bullet_list",123 "note",124 "table",125 "enrollment_steps",126 "school_profile",127 "university_summary",128 "toc",129 "cover",130 "full_page_image",131)132 133 134# ── Composed theme object ──────────────────────────────────────135 136@dataclass(frozen=True)137class HandbookTheme:138 """Complete handbook theme — inject into renderers and templates."""139 140 colors: Colors = field(default_factory=Colors)141 typography: Typography = field(default_factory=Typography)142 spacing: Spacing = field(default_factory=Spacing)143 program_columns: ProgramTableColumns = field(default_factory=ProgramTableColumns)144 bullets: Bullets = field(default_factory=Bullets)145 146 def css_vars(self) -> dict[str, str]:147 """Flatten theme to CSS custom properties (--hb-*)."""148 v: dict[str, str] = {}149 # Colors150 for fname in Colors.__dataclass_fields__:151 v[f"--hb-{fname.replace('_', '-')}"] = getattr(self.colors, fname)152 # Typography153 v["--hb-font-family"] = self.typography.font_family154 v["--hb-font-size-body"] = self.typography.font_size_body155 v["--hb-font-size-h1"] = self.typography.font_size_h1156 v["--hb-font-size-h2"] = self.typography.font_size_h2157 v["--hb-line-height-body"] = self.typography.line_height_body158 # Spacing159 v["--hb-page-margin-top"] = self.spacing.page_margin_top160 v["--hb-page-margin-right"] = self.spacing.page_margin_right161 v["--hb-page-margin-bottom"] = self.spacing.page_margin_bottom162 v["--hb-page-margin-left"] = self.spacing.page_margin_left163 # Bullet164 v["--hb-bullet-char"] = f'"{self.bullets.primary}"'165 return v166 167 168# Module-level singleton169THEME = HandbookTheme()170 