@@ -19,7 +19,7 @@ use crate::{
1919 } ,
2020} ;
2121use floem_renderer:: text:: Weight ;
22- use peniko:: { Brush , Color , color:: { palette:: css} } ;
22+ use peniko:: { Brush , Color , color:: palette:: css} ;
2323use smallvec:: smallvec;
2424
2525style_class ! ( pub HoverTargetClass ) ;
@@ -38,77 +38,6 @@ pub struct DesignSystem {
3838 pub border_radius : f32 ,
3939 pub font_size : f32 ,
4040}
41- // const BORDER_RADIUS: f32 = 5.0;
42- // const FONT_SIZE: f32 = 12.0;
43-
44- // const BG_DARK: Color = hsl([60., 3., 90.]);
45- // const BG: Color = hsl([60., 3., 95.]);
46- // const BG_LIGHT: Color = hsl([60., 3., 100.]);
47-
48- // const BORDER: Color = hsl([60., 3., 60.]);
49- // const HIGHLIGHT: Color = hsl([60., 3., 100.]);
50-
51- // const TEXT: Color = hsl([60., 3., 5.]);
52- // const TEXT_MUTED: Color = hsl([60., 3., 30.]);
53-
54-
55- /// Contruct sRGB [Color] from HSL values.
56- pub const fn hsl ( h : f32 , s : f32 , l : f32 ) -> Color {
57- let hue = transform ( 0. , [ h, s, l] ) ;
58- let sat = transform ( 8. , [ h, s, l] ) ;
59- let lum = transform ( 4. , [ h, s, l] ) ;
60- Color :: new ( [ hue, sat, lum, 1. ] )
61- }
62-
63- const fn transform ( n : f32 , [ h, s, l] : [ f32 ; 3 ] ) -> f32 {
64- let sat = s * 0.01 ;
65- let light = l * 0.01 ;
66- let a = sat * light. min ( 1.0 - light) ;
67-
68- let x = n + h * ( 1.0 / 30.0 ) ;
69- let k = x - 12.0 * ( x * ( 1.0 / 12.0 ) ) . floor ( ) ;
70- light - a * ( k - 3.0 ) . min ( 9.0 - k) . clamp ( -1.0 , 1.0 )
71- }
72-
73- pub const fn hsl_map_lightness ( c : Color , adjustment : f32 ) -> Color {
74- let [ r, g, b, _] = c. components ;
75- let [ h, s, l] = rgb_to_hsl ( [ r, g, b] , true ) ;
76- let l = ( ( l * 0.01 ) + adjustment) * 100. ;
77- hsl ( h, s, l)
78- }
79-
80- const fn rgb_to_hsl ( [ r, g, b] : [ f32 ; 3 ] , hue_hack : bool ) -> [ f32 ; 3 ] {
81- let max = r. max ( g) . max ( b) ;
82- let min = r. min ( g) . min ( b) ;
83- let mut hue = 0.0 ;
84- let mut sat = 0.0 ;
85- let light = 0.5 * ( min + max) ;
86- let d = max - min;
87-
88- const EPSILON : f32 = 1e-6 ;
89- if d > EPSILON {
90- let denom = light. min ( 1.0 - light) ;
91- if denom. abs ( ) > EPSILON {
92- sat = ( max - light) / denom;
93- }
94- hue = if max == r {
95- ( g - b) / d
96- } else if max == g {
97- ( b - r) / d + 2.0
98- } else {
99- // max == b
100- ( r - g) / d + 4.0
101- } ;
102- hue *= 60.0 ;
103- // Deal with negative saturation from out of gamut colors
104- if hue_hack && sat < 0.0 {
105- hue += 180.0 ;
106- sat = sat. abs ( ) ;
107- }
108- hue -= 360. * ( hue * ( 1.0 / 360.0 ) ) . floor ( ) ;
109- }
110- [ hue, sat * 100.0 , light * 100.0 ]
111- }
11241
11342pub ( crate ) const LIGHT_THEME : DesignSystem = DesignSystem :: light ( ) ;
11443pub ( crate ) const DARK_THEME : DesignSystem = DesignSystem :: dark ( ) ;
@@ -117,20 +46,13 @@ impl DesignSystem {
11746 /// Create a light mode design system.
11847 pub const fn light ( ) -> Self {
11948 Self {
120- bg_base : hsl ( 60 ., 3 ., 95. ) ,
121- text_base : hsl ( 60 ., 3 ., 10. ) ,
49+ bg_base : hsl ( 0 ., 0 ., 95. ) ,
50+ text_base : hsl ( 0 ., 0 ., 10. ) ,
12251 text_lightness : 0.05 ,
123- primary_base : hsl ( 196. , 78. , 43 .) ,
52+ primary_base : hsl ( 196. , 78. , 42 .) ,
12453 success_base : hsl ( 151. , 55. , 40. ) ,
12554 warning_base : hsl ( 39. , 79. , 52. ) ,
12655 danger_base : hsl ( 355. , 67. , 53. ) ,
127- // bg_base: Color::from_rgb8(248, 248, 248),
128- // text_base: Color::from_rgb8(0, 0, 0),
129- // text_lightness: 0.05,
130- // primary_base: Color::from_rgb8(0x18, 0x96, 0xC2),
131- // success_base: Color::from_rgb8(0x2D, 0x9D, 0x67),
132- // warning_base: Color::from_rgb8(0xE5, 0xA2, 0x23),
133- // danger_base: Color::from_rgb8(0xD7, 0x37, 0x45),
13456 padding : 5. ,
13557 border_radius : 5. ,
13658 font_size : 14. ,
@@ -141,20 +63,13 @@ impl DesignSystem {
14163 /// Create a dark mode design system.
14264 pub const fn dark ( ) -> Self {
14365 Self {
144- bg_base : hsl ( 0. , 0. , 14 .) ,
66+ bg_base : hsl ( 0. , 0. , 15 .) ,
14567 text_base : hsl ( 0. , 0. , 0. ) ,
14668 text_lightness : 0.95 ,
14769 primary_base : hsl ( 197. , 67. , 54. ) ,
14870 success_base : hsl ( 153. , 47. , 52. ) ,
14971 warning_base : hsl ( 38. , 89. , 63. ) ,
15072 danger_base : hsl ( 1. , 84. , 64. ) ,
151- // bg_base: Color::from_rgb8(0x24, 0x24, 0x24),
152- // text_base: Color::from_rgb8(255, 255, 255),
153- // text_lightness: 0.95,
154- // primary_base: Color::from_rgb8(0x3A, 0xAA, 0xD8),
155- // success_base: Color::from_rgb8(0x4A, 0xBE, 0x8A),
156- // warning_base: Color::from_rgb8(0xF5, 0xB8, 0x4E),
157- // danger_base: Color::from_rgb8(0xF0, 0x56, 0x54),
15873 padding : 5. ,
15974 border_radius : 5. ,
16075 font_size : 14. ,
@@ -169,29 +84,16 @@ impl DesignSystem {
16984 }
17085
17186 pub const fn bg_elevated ( & self ) -> Color {
172- // let adjustment = 0.05;
173- // self.bg_base.map_lightness(|l| l + adjustment)
17487 hsl_map_lightness ( self . bg_base , 0.05 )
17588 }
17689
177- // pub const fn bg_overlay(&self) -> Color {
178- // // let adjustment = 0.10;
179- // let adjustment = if self.is_dark { 0.1 } else { -0.1 };
180- // // self.bg_base.map_lightness(|l| l + adjustment)
181- // hsl_map_lightness(self.bg_base, adjustment)
182- // }
183-
18490 pub const fn bg_overlay ( & self ) -> Color {
18591 let adjustment = if self . is_dark { 0.1 } else { -0.1 } ;
186- // println!("com: {:?}", &self.bg_base.components);
187- // println!("com mapped: {:?}", &self.bg_base.map_lightness(|l| l + adjustment));
188- // println!("com mapped mine: {:?}", hsl_map_lightness(self.bg_base, adjustment));
18992 hsl_map_lightness ( self . bg_base , adjustment)
19093 }
19194
19295 pub const fn bg_disabled ( & self ) -> Color {
19396 let adjustment = if self . is_dark { -0.05 } else { -0.2 } ;
194- // self.bg_base.map_lightness(|l| l + adjustment)
19597 hsl_map_lightness ( self . bg_base , adjustment)
19698 }
19799
@@ -200,30 +102,22 @@ impl DesignSystem {
200102 pub const fn border ( & self ) -> Color {
201103 let adjustment = if self . is_dark { 0.15 } else { -0.15 } ;
202104 hsl_map_lightness ( self . bg_base , adjustment)
203- // self.bg_base.map_lightness(|l| l + adjustment)
204105 }
205106
206107 pub const fn border_muted ( & self ) -> Color {
207108 let adjustment = if self . is_dark { 0.15 } else { -0.15 } ;
208- hsl_map_lightness ( self . border ( ) , adjustment)
209- // self.border()
210- // .map_lightness(|l| l + adjustment)
211- . with_alpha ( 0.8 )
109+ hsl_map_lightness ( self . border ( ) , adjustment) . with_alpha ( 0.8 )
212110 }
213111
214112 // Text
215113
216114 pub const fn text ( & self ) -> Color {
217- // self.text_base.map_lightness(|_| self.text_lightness)
218115 hsl_map_lightness ( self . text_base , self . text_lightness )
219116 }
220117
221118 pub const fn text_muted ( & self ) -> Color {
222119 let adjustment = if self . is_dark { -0.25 } else { 0.25 } ;
223- hsl_map_lightness ( self . text_base , adjustment)
224- // self.text_base
225- // .map_lightness(|l| l + adjustment)
226- . with_alpha ( 0.5 )
120+ hsl_map_lightness ( self . text_base , adjustment) . with_alpha ( 0.5 )
227121 }
228122
229123 // Primary
@@ -234,7 +128,6 @@ impl DesignSystem {
234128
235129 pub const fn primary_muted ( & self ) -> Color {
236130 hsl_map_lightness ( self . primary_base , -0.05 )
237- // self.primary_base.map_lightness(|l| l - 0.05)
238131 }
239132
240133 // Semantic colors
@@ -791,3 +684,93 @@ pub(crate) fn default_theme(os_theme: winit::window::Theme) -> Style {
791684 . transition ( Background , Transition :: linear ( 100 . millis ( ) ) )
792685 } )
793686}
687+
688+ /// Contruct sRGB [Color] from HSL values.
689+ pub const fn hsl ( h : f32 , s : f32 , l : f32 ) -> Color {
690+ let sat = s * 0.01 ;
691+ let light = l * 0.01 ;
692+ let a = sat * light. min ( 1.0 - light) ;
693+
694+ let hue = transform ( 0. , h, light, a) ;
695+ let sat = transform ( 8. , h, light, a) ;
696+ let lum = transform ( 4. , h, light, a) ;
697+ Color :: new ( [ hue, sat, lum, 1. ] )
698+ }
699+
700+ /// Map lightness using hsl colorspace.
701+ pub const fn hsl_map_lightness ( c : Color , adjustment : f32 ) -> Color {
702+ let [ r, g, b, _] = c. components ;
703+ let [ h, s, l] = rgb_to_hsl ( [ r, g, b] , true ) ;
704+ let l = ( ( l * 0.01 ) + adjustment) * 100. ;
705+ hsl ( h, s, l)
706+ }
707+
708+ const fn transform ( n : f32 , h : f32 , light : f32 , a : f32 ) -> f32 {
709+ let x = n + h * ( 1.0 / 30.0 ) ;
710+ let k = x - 12.0 * ( x * ( 1.0 / 12.0 ) ) . floor ( ) ;
711+ light - a * ( k - 3.0 ) . min ( 9.0 - k) . clamp ( -1.0 , 1.0 )
712+ }
713+
714+ const fn rgb_to_hsl ( [ r, g, b] : [ f32 ; 3 ] , hue_hack : bool ) -> [ f32 ; 3 ] {
715+ let max = r. max ( g) . max ( b) ;
716+ let min = r. min ( g) . min ( b) ;
717+ let mut hue = 0.0 ;
718+ let mut sat = 0.0 ;
719+ let light = 0.5 * ( min + max) ;
720+ let d = max - min;
721+
722+ const EPSILON : f32 = 1e-6 ;
723+ if d > EPSILON {
724+ let denom = light. min ( 1.0 - light) ;
725+ if denom. abs ( ) > EPSILON {
726+ sat = ( max - light) / denom;
727+ }
728+ hue = if max == r {
729+ ( g - b) / d
730+ } else if max == g {
731+ ( b - r) / d + 2.0
732+ } else {
733+ // max == b
734+ ( r - g) / d + 4.0
735+ } ;
736+ hue *= 60.0 ;
737+ // Deal with negative saturation from out of gamut colors
738+ if hue_hack && sat < 0.0 {
739+ hue += 180.0 ;
740+ sat = sat. abs ( ) ;
741+ }
742+ hue -= 360. * ( hue * ( 1.0 / 360.0 ) ) . floor ( ) ;
743+ }
744+ [ hue, sat * 100.0 , light * 100.0 ]
745+ }
746+
747+ #[ test]
748+ fn rgb_hsl_conversion ( ) {
749+ let rgb_bg_base = Color :: from_rgb8 ( 242 , 242 , 242 ) ;
750+ let hsl_bg_base = hsl ( 0. , 0. , 95. ) ;
751+ assert_eq ! ( rgb_bg_base. to_rgba8( ) , hsl_bg_base. to_rgba8( ) ) ;
752+
753+ let rgb_text_base = Color :: from_rgb8 ( 0 , 0 , 0 ) ;
754+ let hsl_text_base = hsl ( 0. , 0. , 0. ) ;
755+ assert_eq ! ( rgb_text_base. to_rgba8( ) , hsl_text_base. to_rgba8( ) ) ;
756+
757+ let rgb_text_lightness = Color :: from_rgb8 ( 0 , 0 , 0 ) ;
758+ let hsl_text_lightness = hsl ( 0. , 0. , 0. ) ;
759+ assert_eq ! ( rgb_text_lightness. to_rgba8( ) , hsl_text_lightness. to_rgba8( ) ) ;
760+
761+ let rgb_primary_base = Color :: from_rgb8 ( 24 , 146 , 191 ) ;
762+ let hsl_primary_base = hsl ( 196. , 78. , 42. ) ;
763+ assert_eq ! ( rgb_primary_base. to_rgba8( ) , hsl_primary_base. to_rgba8( ) ) ;
764+
765+ let rgb_success_base = Color :: from_rgb8 ( 46 , 158 , 104 ) ;
766+ let hsl_success_base = hsl ( 151. , 55. , 40. ) ;
767+ assert_eq ! ( rgb_success_base. to_rgba8( ) , hsl_success_base. to_rgba8( ) ) ;
768+
769+ let rgb_warning_base = Color :: from_rgb8 ( 229 , 162 , 36 ) ;
770+ let hsl_warning_base = hsl ( 39. , 79. , 52. ) ;
771+ assert_eq ! ( rgb_warning_base. to_rgba8( ) , hsl_warning_base. to_rgba8( ) ) ;
772+
773+ let rgb_danger_base = Color :: from_rgb8 ( 215 , 55 , 68 ) ;
774+ let hsl_danger_base = hsl ( 355. , 67. , 53. ) ;
775+ assert_eq ! ( rgb_danger_base. to_rgba8( ) , hsl_danger_base. to_rgba8( ) ) ;
776+ }
0 commit comments