#[derive(Debug, Clone, PartialEq)]
pub enum FontFamily {
System,
Monospace,
Custom(String),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontWeight {
Thin = 100,
Light = 300,
Regular = 400,
Medium = 500,
SemiBold = 600,
Bold = 700,
ExtraBold = 800,
Black = 900,
}
#[derive(Debug, Clone)]
pub struct TextStyle {
pub family: FontFamily,
pub size: f32,
pub weight: FontWeight,
pub line_height: f32,
pub letter_spacing: f32,
}
impl TextStyle {
pub fn new(size: f32, weight: FontWeight) -> Self {
Self {
family: FontFamily::System,
size,
weight,
line_height: 1.4,
letter_spacing: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct Typography {
pub display_large: TextStyle, pub display_medium: TextStyle, pub display_small: TextStyle, pub headline_large: TextStyle, pub headline_medium: TextStyle, pub headline_small: TextStyle, pub title_large: TextStyle, pub title_medium: TextStyle, pub title_small: TextStyle, pub body_large: TextStyle, pub body_medium: TextStyle, pub body_small: TextStyle, pub label_large: TextStyle, pub label_medium: TextStyle, pub label_small: TextStyle, }
impl Default for Typography {
fn default() -> Self {
Self {
display_large: TextStyle::new(58.0, FontWeight::Regular),
display_medium: TextStyle::new(46.0, FontWeight::Regular),
display_small: TextStyle::new(37.0, FontWeight::Regular),
headline_large: TextStyle::new(33.0, FontWeight::Regular),
headline_medium: TextStyle::new(29.0, FontWeight::Regular),
headline_small: TextStyle::new(25.0, FontWeight::Regular),
title_large: TextStyle::new(23.0, FontWeight::Regular),
title_medium: TextStyle::new(17.0, FontWeight::Medium),
title_small: TextStyle::new(15.0, FontWeight::Medium),
body_large: TextStyle::new(17.0, FontWeight::Regular),
body_medium: TextStyle::new(15.0, FontWeight::Regular),
body_small: TextStyle::new(13.0, FontWeight::Regular),
label_large: TextStyle::new(15.0, FontWeight::Medium),
label_medium: TextStyle::new(13.0, FontWeight::Medium),
label_small: TextStyle::new(12.0, FontWeight::Medium),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn typography_scale_sizes_are_ordered() {
let t = Typography::default();
assert!(t.display_large.size > t.headline_large.size,
"display_large ({}) should be larger than headline_large ({})",
t.display_large.size, t.headline_large.size);
assert!(t.headline_large.size > t.body_large.size,
"headline_large ({}) should be larger than body_large ({})",
t.headline_large.size, t.body_large.size);
}
#[test]
fn typography_default_display_large_is_58px() {
let t = Typography::default();
assert_eq!(t.display_large.size, 58.0);
}
#[test]
fn typography_title_medium_is_medium_weight() {
let t = Typography::default();
assert_eq!(t.title_medium.weight, FontWeight::Medium);
}
#[test]
fn typography_default_line_height() {
let t = Typography::default();
assert!((t.body_large.line_height - 1.4).abs() < 1e-6);
}
#[test]
fn font_family_custom_stores_name() {
let f = FontFamily::Custom("Inter".to_string());
assert_eq!(f, FontFamily::Custom("Inter".to_string()));
assert_ne!(f, FontFamily::System);
}
}