1use std::collections::HashMap;
5
6use crate::font::FontHandle;
7use crate::model::Color;
8
9#[derive(Clone, Copy, Debug)]
11pub struct Insets {
12 pub top: f32,
14 pub right: f32,
16 pub bottom: f32,
18 pub left: f32,
20}
21
22impl Insets {
23 pub const fn all(v: f32) -> Self {
25 Self { top: v, right: v, bottom: v, left: v }
26 }
27 pub const fn symmetric(v: f32, h: f32) -> Self {
29 Self { top: v, right: h, bottom: v, left: h }
30 }
31}
32
33#[derive(Clone, Debug)]
35pub struct Theme {
36 pub background: Color,
38 pub text: Color,
40 pub accent: Color,
42 pub muted: Color,
44 pub code_bg: Color,
46 pub code_text: Color,
48 pub highlight: Color,
50 pub border: Color,
52 pub font_sans: String,
54 pub font_serif: String,
56 pub font_mono: String,
58 pub font_kai: String,
60 pub base_size: f32,
62 pub line_height: f32,
64 pub heading_scale: [f32; 6],
66}
67
68impl Theme {
69 pub fn light() -> Self {
71 Self {
72 background: Color::rgb(0xff, 0xff, 0xff),
73 text: Color::rgb(0x1f, 0x23, 0x28),
74 accent: Color::rgb(0x25, 0x63, 0xeb),
75 muted: Color::rgb(0x6e, 0x77, 0x81),
76 code_bg: Color::rgb(0xf3, 0xf4, 0xf6),
77 code_text: Color::rgb(0x1f, 0x23, 0x28),
78 highlight: Color::rgb(0xff, 0xf1, 0xa8),
79 border: Color::rgb(0xe5, 0xe7, 0xeb),
80 ..Self::common()
81 }
82 }
83
84 pub fn dark() -> Self {
86 Self {
87 background: Color::rgb(0x0d, 0x11, 0x17),
88 text: Color::rgb(0xe6, 0xed, 0xf3),
89 accent: Color::rgb(0x58, 0xa6, 0xff),
90 muted: Color::rgb(0x8b, 0x94, 0x9e),
91 code_bg: Color::rgb(0x16, 0x1b, 0x22),
92 code_text: Color::rgb(0xe6, 0xed, 0xf3),
93 highlight: Color::rgb(0x57, 0x4a, 0x1a),
94 border: Color::rgb(0x30, 0x36, 0x3d),
95 ..Self::common()
96 }
97 }
98
99 fn common() -> Self {
101 Self {
102 background: Color::rgb(0, 0, 0),
103 text: Color::rgb(0, 0, 0),
104 accent: Color::rgb(0, 0, 0),
105 muted: Color::rgb(0, 0, 0),
106 code_bg: Color::rgb(0, 0, 0),
107 code_text: Color::rgb(0, 0, 0),
108 highlight: Color::rgb(0, 0, 0),
109 border: Color::rgb(0, 0, 0),
110 font_sans: "Noto Sans SC".to_string(), font_serif: "Noto Serif SC".to_string(), font_mono: "JetBrains Mono".to_string(), font_kai: "LXGW WenKai GB".to_string(), base_size: 30.0,
115 line_height: 1.5,
116 heading_scale: [2.0, 1.6, 1.35, 1.15, 1.0, 0.9],
117 }
118 }
119}
120
121impl Default for Theme {
122 fn default() -> Self {
123 Self::light()
124 }
125}
126
127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum OutputFormat {
130 Png,
132 PngFast,
134 Webp,
136 WebpOrPng,
139}
140
141#[derive(Clone)]
143pub struct RenderOptions {
144 pub width: f32,
146 pub padding: Insets,
148 pub scale: f32,
150 pub theme: Theme,
152 pub fonts: FontHandle,
154 pub format: OutputFormat,
156 pub images: HashMap<String, Vec<u8>>,
158}
159
160impl Default for RenderOptions {
161 fn default() -> Self {
162 Self {
163 width: 720.0,
164 padding: Insets::symmetric(32.0, 40.0),
165 scale: 2.0,
166 theme: Theme::light(),
167 fonts: FontHandle::shared_default(),
168 format: OutputFormat::Png,
169 images: HashMap::new(),
170 }
171 }
172}
173
174impl RenderOptions {
175 pub fn with_width(mut self, w: f32) -> Self {
177 self.width = w;
178 self
179 }
180 pub fn with_padding(mut self, p: Insets) -> Self {
182 self.padding = p;
183 self
184 }
185 pub fn with_theme(mut self, t: Theme) -> Self {
187 self.theme = t;
188 self
189 }
190 pub fn with_fonts(mut self, f: FontHandle) -> Self {
192 self.fonts = f;
193 self
194 }
195 pub fn with_scale(mut self, s: f32) -> Self {
197 self.scale = s.clamp(0.25, 8.0);
198 self
199 }
200 pub fn fast(self) -> Self {
202 self.with_scale(1.0)
203 }
204 pub fn standard(self) -> Self {
206 self.with_scale(1.5)
207 }
208 pub fn sharp(self) -> Self {
210 self.with_scale(2.0)
211 }
212 pub fn ultra(self) -> Self {
214 self.with_scale(3.0)
215 }
216 pub fn with_format(mut self, f: OutputFormat) -> Self {
218 self.format = f;
219 self
220 }
221 pub fn png(self) -> Self {
223 self.with_format(OutputFormat::Png)
224 }
225 pub fn png_fast(self) -> Self {
227 self.with_format(OutputFormat::PngFast)
228 }
229 pub fn webp(self) -> Self {
231 self.with_format(OutputFormat::Webp)
232 }
233 pub fn webp_or_png(self) -> Self {
235 self.with_format(OutputFormat::WebpOrPng)
236 }
237}