Server: ThemeConfig entity + CRUD (GET/PUT /theme), SQLite persistence, ThemeUpdate broadcast to ESP32 on save and initial connect. Client: render engine uses theme colors, full-screen redraw on theme change. SPA: theme page with color pickers + presets, layout preview with TS port of layout engine, justify/align controls on containers. DisplayHint refactored to struct (kind + h_align + v_align).
115 lines
2.4 KiB
Rust
115 lines
2.4 KiB
Rust
use client_domain::{Color, TextSpan, ThemeConfig, parse_markup};
|
|
|
|
fn theme() -> ThemeConfig {
|
|
ThemeConfig::default()
|
|
}
|
|
|
|
#[test]
|
|
fn plain_text_produces_single_span() {
|
|
let spans = parse_markup("hello world", &theme());
|
|
assert_eq!(
|
|
spans,
|
|
vec![TextSpan {
|
|
text: "hello world".into(),
|
|
color: theme().text
|
|
},]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn hex_color_span() {
|
|
let spans = parse_markup("temp: {#FF0000}72°F{/}", &theme());
|
|
assert_eq!(
|
|
spans,
|
|
vec![
|
|
TextSpan {
|
|
text: "temp: ".into(),
|
|
color: theme().text
|
|
},
|
|
TextSpan {
|
|
text: "72°F".into(),
|
|
color: Color(0xFF, 0, 0)
|
|
},
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn theme_color_spans() {
|
|
let t = theme();
|
|
let spans = parse_markup("{primary}hello{/} {accent}world{/}", &t);
|
|
assert_eq!(
|
|
spans,
|
|
vec![
|
|
TextSpan {
|
|
text: "hello".into(),
|
|
color: t.primary
|
|
},
|
|
TextSpan {
|
|
text: " ".into(),
|
|
color: t.text
|
|
},
|
|
TextSpan {
|
|
text: "world".into(),
|
|
color: t.accent
|
|
},
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn reset_returns_to_text_color() {
|
|
let t = theme();
|
|
let spans = parse_markup("{accent}hi{/}bye", &t);
|
|
assert_eq!(
|
|
spans,
|
|
vec![
|
|
TextSpan {
|
|
text: "hi".into(),
|
|
color: t.accent
|
|
},
|
|
TextSpan {
|
|
text: "bye".into(),
|
|
color: t.text
|
|
},
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn empty_input_produces_no_spans() {
|
|
let spans = parse_markup("", &theme());
|
|
assert_eq!(spans, Vec::<TextSpan>::new());
|
|
}
|
|
|
|
#[test]
|
|
fn adjacent_color_spans_no_text_between() {
|
|
let t = theme();
|
|
let spans = parse_markup("{primary}a{secondary}b{/}", &t);
|
|
assert_eq!(
|
|
spans,
|
|
vec![
|
|
TextSpan {
|
|
text: "a".into(),
|
|
color: t.primary
|
|
},
|
|
TextSpan {
|
|
text: "b".into(),
|
|
color: t.secondary
|
|
},
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_tag_treated_as_literal() {
|
|
let spans = parse_markup("{unknown}text", &theme());
|
|
assert_eq!(
|
|
spans,
|
|
vec![TextSpan {
|
|
text: "text".into(),
|
|
color: theme().text
|
|
},]
|
|
);
|
|
}
|