at main 206 lines 7.6 kB view raw
1use miette::IntoDiagnostic; 2pub use weaver_api::sh_weaver::notebook::colour_scheme::{ColourScheme, ColourSchemeColours}; 3use weaver_api::sh_weaver::notebook::theme::Font; 4use weaver_api::sh_weaver::notebook::theme::FontName; 5use weaver_api::sh_weaver::notebook::theme::FontValue; 6pub use weaver_api::sh_weaver::notebook::theme::{ 7 Theme, ThemeDarkCodeTheme, ThemeFonts, ThemeLightCodeTheme, ThemeSpacing, 8}; 9use weaver_common::jacquard::CowStr; 10use weaver_common::jacquard::IntoStatic; 11use weaver_common::jacquard::client::AgentSession; 12use weaver_common::jacquard::cowstr::ToCowStr; 13use weaver_common::jacquard::prelude::*; 14 15#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] 16pub enum ThemeDefault { 17 #[default] 18 Auto, 19 Light, 20 Dark, 21} 22 23/// A theme with resolved colour schemes (no strongRefs, actual data) 24#[derive(Clone, Debug)] 25pub struct ResolvedTheme<'a> { 26 pub default: ThemeDefault, 27 pub dark_scheme: ColourSchemeColours<'a>, 28 pub light_scheme: ColourSchemeColours<'a>, 29 pub fonts: ThemeFonts<'a>, 30 pub spacing: ThemeSpacing<'a>, 31 pub dark_code_theme: ThemeDarkCodeTheme<'a>, 32 pub light_code_theme: ThemeLightCodeTheme<'a>, 33} 34 35pub fn default_colour_scheme_dark() -> ColourSchemeColours<'static> { 36 ColourSchemeColours { 37 base: CowStr::new_static("#191724"), 38 surface: CowStr::new_static("#1f1d2e"), 39 overlay: CowStr::new_static("#26233a"), 40 text: CowStr::new_static("#e0def4"), 41 muted: CowStr::new_static("#6e6a86"), 42 subtle: CowStr::new_static("#908caa"), 43 emphasis: CowStr::new_static("#e0def4"), 44 primary: CowStr::new_static("#c4a7e7"), 45 secondary: CowStr::new_static("#9ccfd8"), 46 tertiary: CowStr::new_static("#ebbcba"), 47 error: CowStr::new_static("#eb6f92"), 48 warning: CowStr::new_static("#f6c177"), 49 success: CowStr::new_static("#31748f"), 50 border: CowStr::new_static("#403d52"), 51 link: CowStr::new_static("#ebbcba"), 52 highlight: CowStr::new_static("#524f67"), 53 ..Default::default() 54 } 55} 56 57pub fn default_fonts() -> ThemeFonts<'static> { 58 ThemeFonts { 59 // Serif for body text, sans for headings/UI 60 body: vec![ 61 Font::new() 62 .value(FontValue::FontName( 63 CowStr::new_static("Adobe Caslon Pro").into(), 64 )) 65 .build(), 66 Font::new() 67 .value(FontValue::FontName( 68 CowStr::new_static("Latin Modern Roman").into(), 69 )) 70 .build(), 71 Font::new() 72 .value(FontValue::FontName( 73 CowStr::new_static("Times New Roman").into(), 74 )) 75 .build(), 76 Font::new() 77 .value(FontValue::FontName(CowStr::new_static("serif").into())) 78 .build(), 79 ], 80 heading: vec![ 81 Font::new() 82 .value(FontValue::FontName( 83 CowStr::new_static("IBM Plex Sans").into(), 84 )) 85 .build(), 86 Font::new() 87 .value(FontValue::FontName(CowStr::new_static("system-ui").into())) 88 .build(), 89 Font::new() 90 .value(FontValue::FontName(CowStr::new_static("sans-serif").into())) 91 .build(), 92 ], 93 monospace: vec![ 94 Font::new() 95 .value(FontValue::FontName( 96 CowStr::new_static("Ioskeley Mono").into(), 97 )) 98 .build(), 99 Font::new() 100 .value(FontValue::FontName( 101 CowStr::new_static("IBM Plex Mono").into(), 102 )) 103 .build(), 104 Font::new() 105 .value(FontValue::FontName( 106 CowStr::new_static("Berkeley Mono").into(), 107 )) 108 .build(), 109 Font::new() 110 .value(FontValue::FontName(CowStr::new_static("Consolas").into())) 111 .build(), 112 Font::new() 113 .value(FontValue::FontName(CowStr::new_static("monospace").into())) 114 .build(), 115 ], 116 extra_data: None, 117 } 118} 119 120pub fn default_spacing() -> ThemeSpacing<'static> { 121 ThemeSpacing { 122 base_size: CowStr::new_static("16px"), 123 line_height: CowStr::new_static("1.6"), 124 scale: CowStr::new_static("1.25"), 125 ..Default::default() 126 } 127} 128 129pub fn default_colour_scheme_light() -> ColourSchemeColours<'static> { 130 // Rose Pine Dawn with moderate contrast text (text/muted/subtle/emphasis darkened) 131 ColourSchemeColours { 132 base: CowStr::new_static("#faf4ed"), 133 surface: CowStr::new_static("#fffaf3"), 134 overlay: CowStr::new_static("#f2e9e1"), 135 // Text colors darkened for better contrast 136 text: CowStr::new_static("#1f1d2e"), 137 muted: CowStr::new_static("#635e74"), 138 subtle: CowStr::new_static("#4a4560"), 139 emphasis: CowStr::new_static("#1e1a2d"), 140 // Accent colors kept at original Rose Pine Dawn values 141 primary: CowStr::new_static("#907aa9"), 142 secondary: CowStr::new_static("#56949f"), 143 tertiary: CowStr::new_static("#286983"), 144 error: CowStr::new_static("#b4637a"), 145 warning: CowStr::new_static("#ea9d34"), 146 success: CowStr::new_static("#286983"), 147 border: CowStr::new_static("#dfdad9"), 148 link: CowStr::new_static("#d7827e"), 149 highlight: CowStr::new_static("#cecacd"), 150 ..Default::default() 151 } 152} 153 154pub fn default_resolved_theme() -> ResolvedTheme<'static> { 155 ResolvedTheme { 156 default: ThemeDefault::Auto, 157 dark_scheme: default_colour_scheme_dark(), 158 light_scheme: default_colour_scheme_light(), 159 fonts: default_fonts(), 160 spacing: default_spacing(), 161 dark_code_theme: ThemeDarkCodeTheme::CodeThemeName(Box::new("rose-pine".to_cowstr())), 162 light_code_theme: ThemeLightCodeTheme::CodeThemeName(Box::new( 163 "rose-pine-dawn".to_cowstr(), 164 )), 165 } 166} 167 168/// Resolve a theme by fetching its colour scheme records from the PDS 169pub async fn resolve_theme<A: AgentSession + IdentityResolver>( 170 agent: &A, 171 theme: &Theme<'_>, 172) -> miette::Result<ResolvedTheme<'static>> { 173 use weaver_common::jacquard::client::AgentSessionExt; 174 175 // Fetch dark scheme 176 let dark_response = agent 177 .get_record::<ColourScheme>(&theme.dark_scheme.uri) 178 .await 179 .into_diagnostic()?; 180 181 let dark_scheme: ColourScheme = dark_response.into_output().into_diagnostic()?.into(); 182 183 // Fetch light scheme 184 let light_response = agent 185 .get_record::<ColourScheme>(&theme.light_scheme.uri) 186 .await 187 .into_diagnostic()?; 188 189 let light_scheme: ColourScheme = light_response.into_output().into_diagnostic()?.into(); 190 let default = match theme.default_theme.as_ref().map(|t| t.as_str()) { 191 Some("auto") => ThemeDefault::Auto, 192 Some("dark") => ThemeDefault::Dark, 193 Some("light") => ThemeDefault::Light, 194 _ => ThemeDefault::Auto, 195 }; 196 197 Ok(ResolvedTheme { 198 default, 199 dark_scheme: dark_scheme.colours.into_static(), 200 light_scheme: light_scheme.colours.into_static(), 201 fonts: theme.fonts.clone().into_static(), 202 spacing: theme.spacing.clone().into_static(), 203 dark_code_theme: theme.dark_code_theme.clone().into_static(), 204 light_code_theme: theme.light_code_theme.clone().into_static(), 205 }) 206}