Skip to main content

freya_components/theming/
themes.rs

1use freya_core::prelude::*;
2#[cfg(feature = "titlebar")]
3use torin::prelude::Length;
4use torin::{
5    gaps::Gaps,
6    size::Size,
7};
8
9#[cfg(feature = "calendar")]
10use crate::calendar::CalendarThemePreference;
11#[cfg(feature = "router")]
12use crate::link::LinkThemePreference;
13#[cfg(feature = "markdown")]
14use crate::markdown::MarkdownViewerThemePreference;
15#[cfg(feature = "titlebar")]
16use crate::titlebar::TitlebarButtonThemePreference;
17use crate::{
18    accordion::AccordionThemePreference,
19    button::{
20        ButtonColorsThemePreference,
21        ButtonLayoutThemePreference,
22    },
23    card::{
24        CardColorsThemePreference,
25        CardLayoutThemePreference,
26    },
27    checkbox::CheckboxThemePreference,
28    chip::ChipThemePreference,
29    color_picker::ColorPickerThemePreference,
30    floating_tab::FloatingTabThemePreference,
31    input::{
32        InputColorsThemePreference,
33        InputLayoutThemePreference,
34    },
35    loader::CircularLoaderThemePreference,
36    menu::{
37        MenuContainerThemePreference,
38        MenuItemThemePreference,
39    },
40    popup::PopupThemePreference,
41    progressbar::ProgressBarThemePreference,
42    radio_item::RadioItemThemePreference,
43    resizable_container::ResizableHandleThemePreference,
44    scrollviews::ScrollBarThemePreference,
45    segmented_button::{
46        ButtonSegmentThemePreference,
47        SegmentedButtonThemePreference,
48    },
49    select::SelectThemePreference,
50    sidebar::SideBarItemThemePreference,
51    slider::SliderThemePreference,
52    switch::{
53        SwitchColorsThemePreference,
54        SwitchLayoutThemePreference,
55    },
56    table::TableThemePreference,
57    theming::{
58        component_themes::{
59            ColorsSheet,
60            Theme,
61        },
62        macros::Preference,
63    },
64    tooltip::TooltipThemePreference,
65};
66
67pub const LIGHT_COLORS: ColorsSheet = ColorsSheet {
68    // Brand & Accent
69    primary: Color::from_rgb(103, 80, 164),
70    secondary: Color::from_rgb(202, 193, 227),
71    tertiary: Color::from_rgb(79, 61, 130),
72
73    // Status
74    success: Color::from_rgb(76, 175, 80),
75    warning: Color::from_rgb(255, 193, 7),
76    error: Color::from_rgb(244, 67, 54),
77    info: Color::from_rgb(33, 150, 243),
78
79    // Surfaces
80    background: Color::from_rgb(250, 250, 250),
81    surface_primary: Color::from_rgb(210, 210, 210),
82    surface_secondary: Color::from_rgb(225, 225, 225),
83    surface_tertiary: Color::from_rgb(245, 245, 245),
84    surface_inverse: Color::from_rgb(125, 125, 125),
85    surface_inverse_secondary: Color::from_rgb(110, 110, 110),
86    surface_inverse_tertiary: Color::from_rgb(90, 90, 90),
87
88    // Borders
89    border: Color::from_rgb(210, 210, 210),
90    border_focus: Color::from_rgb(180, 180, 180),
91    border_disabled: Color::from_rgb(210, 210, 210),
92
93    // Text
94    text_primary: Color::from_rgb(10, 10, 10),
95    text_secondary: Color::from_rgb(100, 100, 100),
96    text_placeholder: Color::from_rgb(150, 150, 150),
97    text_inverse: Color::WHITE,
98    text_highlight: Color::from_rgb(38, 89, 170),
99
100    // States
101    hover: Color::from_rgb(235, 235, 235),
102    focus: Color::from_rgb(225, 225, 255),
103    active: Color::from_rgb(200, 200, 200),
104    disabled: Color::from_rgb(210, 210, 210),
105
106    // Utility
107    overlay: Color::from_af32rgb(0.5, 0, 0, 0),
108    shadow: Color::from_af32rgb(0.2, 0, 0, 0),
109};
110
111pub const DARK_COLORS: ColorsSheet = ColorsSheet {
112    // Brand & Accent
113    primary: Color::from_rgb(103, 80, 164),
114    secondary: Color::from_rgb(202, 193, 227),
115    tertiary: Color::from_rgb(79, 61, 130),
116
117    // Status
118    success: Color::from_rgb(129, 199, 132),
119    warning: Color::from_rgb(255, 213, 79),
120    error: Color::from_rgb(229, 115, 115),
121    info: Color::from_rgb(100, 181, 246),
122
123    // Surfaces
124    background: Color::from_rgb(20, 20, 20),
125    surface_primary: Color::from_rgb(60, 60, 60),
126    surface_secondary: Color::from_rgb(45, 45, 45),
127    surface_tertiary: Color::from_rgb(25, 25, 25),
128    surface_inverse: Color::from_rgb(135, 135, 135),
129    surface_inverse_secondary: Color::from_rgb(150, 150, 150),
130    surface_inverse_tertiary: Color::from_rgb(170, 170, 170),
131
132    // Borders
133    border: Color::from_rgb(60, 60, 60),
134    border_focus: Color::from_rgb(110, 110, 110),
135    border_disabled: Color::from_rgb(80, 80, 80),
136
137    // Text
138    text_primary: Color::from_rgb(250, 250, 250),
139    text_secondary: Color::from_rgb(210, 210, 210),
140    text_placeholder: Color::from_rgb(150, 150, 150),
141    text_inverse: Color::WHITE,
142    text_highlight: Color::from_rgb(96, 145, 224),
143
144    // States
145    hover: Color::from_rgb(80, 80, 80),
146    focus: Color::from_rgb(100, 100, 120),
147    active: Color::from_rgb(70, 70, 70),
148    disabled: Color::from_rgb(50, 50, 50),
149
150    // Utility
151    overlay: Color::from_af32rgb(0.2, 255, 255, 255),
152    shadow: Color::from_af32rgb(0.6, 0, 0, 0),
153};
154
155fn register_base_component_themes(theme: &mut Theme) {
156    theme.set(
157        "button_layout",
158        ButtonLayoutThemePreference {
159            padding: Preference::Specific(Gaps::new(6., 12., 6., 12.)),
160            margin: Preference::Specific(Gaps::new_all(0.)),
161            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
162            width: Preference::Specific(Size::Inner),
163            height: Preference::Specific(Size::Inner),
164        },
165    );
166    theme.set(
167        "compact_button_layout",
168        ButtonLayoutThemePreference {
169            padding: Preference::Specific(Gaps::new(3., 6., 3., 6.)),
170            margin: Preference::Specific(Gaps::new_all(0.)),
171            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
172            width: Preference::Specific(Size::Inner),
173            height: Preference::Specific(Size::Inner),
174        },
175    );
176    theme.set(
177        "expanded_button_layout",
178        ButtonLayoutThemePreference {
179            padding: Preference::Specific(Gaps::new(10., 16., 10., 16.)),
180            margin: Preference::Specific(Gaps::new_all(0.)),
181            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
182            width: Preference::Specific(Size::Inner),
183            height: Preference::Specific(Size::Inner),
184        },
185    );
186    theme.set(
187        "button",
188        ButtonColorsThemePreference {
189            background: Preference::Reference("surface_tertiary"),
190            hover_background: Preference::Reference("hover"),
191            border_fill: Preference::Reference("border"),
192            focus_border_fill: Preference::Reference("border_focus"),
193            color: Preference::Reference("text_primary"),
194        },
195    );
196    theme.set(
197        "filled_button",
198        ButtonColorsThemePreference {
199            background: Preference::Reference("primary"),
200            hover_background: Preference::Reference("tertiary"),
201            border_fill: Preference::Specific(Color::TRANSPARENT),
202            focus_border_fill: Preference::Reference("secondary"),
203            color: Preference::Reference("text_inverse"),
204        },
205    );
206    theme.set(
207        "outline_button",
208        ButtonColorsThemePreference {
209            background: Preference::Reference("surface_tertiary"),
210            hover_background: Preference::Reference("hover"),
211            border_fill: Preference::Reference("border"),
212            focus_border_fill: Preference::Reference("secondary"),
213            color: Preference::Reference("primary"),
214        },
215    );
216    theme.set(
217        "flat_button",
218        ButtonColorsThemePreference {
219            background: Preference::Specific(Color::TRANSPARENT),
220            hover_background: Preference::Reference("surface_tertiary"),
221            border_fill: Preference::Specific(Color::TRANSPARENT),
222            focus_border_fill: Preference::Reference("border"),
223            color: Preference::Reference("text_primary"),
224        },
225    );
226    theme.set(
227        "card_layout",
228        CardLayoutThemePreference {
229            padding: Preference::Specific(Gaps::new(16., 16., 16., 16.)),
230            corner_radius: Preference::Specific(CornerRadius::new_all(8.)),
231        },
232    );
233    theme.set(
234        "compact_card_layout",
235        CardLayoutThemePreference {
236            padding: Preference::Specific(Gaps::new(8., 12., 8., 12.)),
237            corner_radius: Preference::Specific(CornerRadius::new_all(8.)),
238        },
239    );
240    theme.set(
241        "filled_card",
242        CardColorsThemePreference {
243            background: Preference::Reference("primary"),
244            hover_background: Preference::Reference("tertiary"),
245            border_fill: Preference::Specific(Color::TRANSPARENT),
246            color: Preference::Reference("text_inverse"),
247            shadow: Preference::Reference("shadow"),
248        },
249    );
250    theme.set(
251        "outline_card",
252        CardColorsThemePreference {
253            background: Preference::Reference("surface_tertiary"),
254            hover_background: Preference::Reference("hover"),
255            border_fill: Preference::Reference("border"),
256            color: Preference::Reference("text_primary"),
257            shadow: Preference::Reference("shadow"),
258        },
259    );
260    theme.set(
261        "accordion",
262        AccordionThemePreference {
263            color: Preference::Reference("text_primary"),
264            background: Preference::Reference("surface_tertiary"),
265            border_fill: Preference::Reference("border"),
266        },
267    );
268    theme.set(
269        "switch",
270        SwitchColorsThemePreference {
271            background: Preference::Reference("surface_secondary"),
272            thumb_background: Preference::Reference("surface_inverse"),
273            toggled_background: Preference::Reference("secondary"),
274            toggled_thumb_background: Preference::Reference("primary"),
275            focus_border_fill: Preference::Reference("border_focus"),
276        },
277    );
278    theme.set(
279        "switch_layout",
280        SwitchLayoutThemePreference {
281            margin: Preference::Specific(Gaps::new_all(0.)),
282            width: Preference::Specific(48.),
283            height: Preference::Specific(28.),
284            padding: Preference::Specific(4.),
285            thumb_size: Preference::Specific(16.),
286            toggled_thumb_size: Preference::Specific(20.),
287            pressed_thumb_size_offset: Preference::Specific(4.),
288            thumb_offset: Preference::Specific(2.),
289            toggled_thumb_offset: Preference::Specific(20.),
290        },
291    );
292    theme.set(
293        "expanded_switch_layout",
294        SwitchLayoutThemePreference {
295            margin: Preference::Specific(Gaps::new_all(0.)),
296            width: Preference::Specific(56.),
297            height: Preference::Specific(32.),
298            padding: Preference::Specific(4.),
299            thumb_size: Preference::Specific(18.),
300            toggled_thumb_size: Preference::Specific(22.),
301            pressed_thumb_size_offset: Preference::Specific(4.),
302            thumb_offset: Preference::Specific(2.),
303            toggled_thumb_offset: Preference::Specific(26.),
304        },
305    );
306    theme.set(
307        "scrollbar",
308        ScrollBarThemePreference {
309            background: Preference::Reference("surface_primary"),
310            thumb_background: Preference::Reference("surface_inverse"),
311            hover_thumb_background: Preference::Reference("surface_inverse_secondary"),
312            active_thumb_background: Preference::Reference("surface_inverse_tertiary"),
313            size: Preference::Specific(15.),
314        },
315    );
316    theme.set(
317        "progressbar",
318        ProgressBarThemePreference {
319            color: Preference::Reference("text_inverse"),
320            background: Preference::Reference("surface_primary"),
321            progress_background: Preference::Reference("primary"),
322            height: Preference::Specific(20.),
323        },
324    );
325    theme.set(
326        "sidebar_item",
327        SideBarItemThemePreference {
328            color: Preference::Reference("text_primary"),
329            background: Preference::Reference("surface_tertiary"),
330            active_background: Preference::Reference("surface_secondary"),
331            hover_background: Preference::Reference("hover"),
332            corner_radius: Preference::Specific(CornerRadius::new_all(12.)),
333            margin: Preference::Specific(Gaps::new_all(0.)),
334            padding: Preference::Specific(Gaps::new(8., 12., 8., 12.)),
335        },
336    );
337    #[cfg(feature = "router")]
338    theme.set(
339        "link",
340        LinkThemePreference {
341            color: Preference::Reference("text_highlight"),
342        },
343    );
344    theme.set(
345        "tooltip",
346        TooltipThemePreference {
347            background: Preference::Reference("surface_tertiary"),
348            color: Preference::Reference("text_primary"),
349            border_fill: Preference::Reference("surface_primary"),
350            font_size: Preference::Specific(14.),
351        },
352    );
353    theme.set(
354        "circular_loader",
355        CircularLoaderThemePreference {
356            primary_color: Preference::Reference("surface_primary"),
357            inversed_color: Preference::Reference("surface_inverse"),
358        },
359    );
360    theme.set(
361        "input_layout",
362        InputLayoutThemePreference {
363            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
364            inner_margin: Preference::Specific(Gaps::new(8., 8., 8., 8.)),
365        },
366    );
367    theme.set(
368        "compact_input_layout",
369        InputLayoutThemePreference {
370            corner_radius: Preference::Specific(CornerRadius::new_all(4.)),
371            inner_margin: Preference::Specific(Gaps::new(4., 6., 4., 6.)),
372        },
373    );
374    theme.set(
375        "expanded_input_layout",
376        InputLayoutThemePreference {
377            corner_radius: Preference::Specific(CornerRadius::new_all(8.)),
378            inner_margin: Preference::Specific(Gaps::new(12., 12., 12., 12.)),
379        },
380    );
381    theme.set(
382        "input",
383        InputColorsThemePreference {
384            background: Preference::Reference("surface_tertiary"),
385            hover_background: Preference::Reference("background"),
386            color: Preference::Reference("text_primary"),
387            placeholder_color: Preference::Reference("text_secondary"),
388            border_fill: Preference::Reference("border"),
389            focus_border_fill: Preference::Reference("border_focus"),
390        },
391    );
392    theme.set(
393        "filled_input",
394        InputColorsThemePreference {
395            background: Preference::Reference("primary"),
396            hover_background: Preference::Reference("tertiary"),
397            color: Preference::Reference("text_inverse"),
398            placeholder_color: Preference::Reference("text_inverse"),
399            border_fill: Preference::Specific(Color::TRANSPARENT),
400            focus_border_fill: Preference::Reference("secondary"),
401        },
402    );
403    theme.set(
404        "flat_input",
405        InputColorsThemePreference {
406            background: Preference::Specific(Color::TRANSPARENT),
407            hover_background: Preference::Reference("surface_tertiary"),
408            color: Preference::Reference("text_primary"),
409            placeholder_color: Preference::Reference("text_secondary"),
410            border_fill: Preference::Specific(Color::TRANSPARENT),
411            focus_border_fill: Preference::Reference("border"),
412        },
413    );
414    theme.set(
415        "radio",
416        RadioItemThemePreference {
417            unselected_fill: Preference::Reference("surface_inverse_tertiary"),
418            selected_fill: Preference::Reference("primary"),
419            border_fill: Preference::Reference("surface_primary"),
420        },
421    );
422    theme.set(
423        "checkbox",
424        CheckboxThemePreference {
425            unselected_fill: Preference::Reference("surface_inverse_tertiary"),
426            selected_fill: Preference::Reference("primary"),
427            selected_icon_fill: Preference::Reference("secondary"),
428            border_fill: Preference::Reference("surface_primary"),
429        },
430    );
431    theme.set(
432        "resizable_handle",
433        ResizableHandleThemePreference {
434            background: Preference::Reference("surface_secondary"),
435            hover_background: Preference::Reference("surface_primary"),
436            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
437        },
438    );
439    theme.set(
440        "floating_tab",
441        FloatingTabThemePreference {
442            background: Preference::Specific(Color::TRANSPARENT),
443            hover_background: Preference::Reference("surface_secondary"),
444            color: Preference::Reference("text_primary"),
445            padding: Preference::Specific(Gaps::new(6., 12., 6., 12.)),
446            width: Preference::Specific(Size::Inner),
447            height: Preference::Specific(Size::Inner),
448            corner_radius: Preference::Specific(CornerRadius::new_all(99.)),
449        },
450    );
451    theme.set(
452        "slider",
453        SliderThemePreference {
454            background: Preference::Reference("surface_primary"),
455            thumb_background: Preference::Reference("secondary"),
456            thumb_inner_background: Preference::Reference("primary"),
457            border_fill: Preference::Reference("surface_primary"),
458        },
459    );
460    theme.set(
461        "color_picker",
462        ColorPickerThemePreference {
463            background: Preference::Reference("surface_tertiary"),
464            border_fill: Preference::Reference("border"),
465            color: Preference::Reference("text_primary"),
466        },
467    );
468    theme.set(
469        "select",
470        SelectThemePreference {
471            width: Preference::Specific(Size::Inner),
472            margin: Preference::Specific(Gaps::new_all(0.)),
473            select_background: Preference::Reference("background"),
474            background_button: Preference::Reference("surface_tertiary"),
475            hover_background: Preference::Reference("hover"),
476            color: Preference::Reference("text_primary"),
477            border_fill: Preference::Reference("border"),
478            focus_border_fill: Preference::Reference("border_focus"),
479            arrow_fill: Preference::Reference("text_primary"),
480        },
481    );
482    theme.set(
483        "popup",
484        PopupThemePreference {
485            background: Preference::Reference("background"),
486            color: Preference::Reference("text_primary"),
487        },
488    );
489    theme.set(
490        "table",
491        TableThemePreference {
492            background: Preference::Reference("background"),
493            arrow_fill: Preference::Reference("text_primary"),
494            row_background: Preference::Specific(Color::TRANSPARENT),
495            hover_row_background: Preference::Reference("surface_secondary"),
496            divider_fill: Preference::Reference("surface_primary"),
497            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
498            color: Preference::Reference("text_primary"),
499        },
500    );
501    #[cfg(feature = "markdown")]
502    theme.set(
503        "markdown_viewer",
504        MarkdownViewerThemePreference {
505            color: Preference::Reference("text_primary"),
506            background_code: Preference::Reference("surface_tertiary"),
507            color_code: Preference::Reference("text_primary"),
508            background_blockquote: Preference::Reference("surface_tertiary"),
509            border_blockquote: Preference::Reference("surface_primary"),
510            background_divider: Preference::Reference("border"),
511            heading_h1: Preference::Specific(32.0),
512            heading_h2: Preference::Specific(28.0),
513            heading_h3: Preference::Specific(24.0),
514            heading_h4: Preference::Specific(20.0),
515            heading_h5: Preference::Specific(18.0),
516            heading_h6: Preference::Specific(16.0),
517            paragraph_size: Preference::Specific(16.0),
518            code_font_size: Preference::Specific(14.0),
519            table_font_size: Preference::Specific(14.0),
520        },
521    );
522    theme.set(
523        "chip",
524        ChipThemePreference {
525            background: Preference::Reference("background"),
526            hover_background: Preference::Reference("tertiary"),
527            selected_background: Preference::Reference("primary"),
528            border_fill: Preference::Reference("border"),
529            hover_border_fill: Preference::Reference("tertiary"),
530            selected_border_fill: Preference::Reference("primary"),
531            focus_border_fill: Preference::Reference("secondary"),
532            padding: Preference::Specific(Gaps::new(8., 14., 8., 14.)),
533            margin: Preference::Specific(0.),
534            corner_radius: Preference::Specific(CornerRadius::new_all(99.)),
535            width: Preference::Specific(Size::Inner),
536            height: Preference::Specific(Size::Inner),
537            color: Preference::Reference("text_primary"),
538            hover_color: Preference::Reference("text_inverse"),
539            selected_color: Preference::Reference("text_inverse"),
540            selected_icon_fill: Preference::Reference("secondary"),
541            hover_icon_fill: Preference::Reference("secondary"),
542        },
543    );
544    theme.set(
545        "menu_item",
546        MenuItemThemePreference {
547            background: Preference::Specific(Color::TRANSPARENT),
548            hover_background: Preference::Reference("surface_secondary"),
549            select_background: Preference::Reference("surface_secondary"),
550            border_fill: Preference::Specific(Color::TRANSPARENT),
551            select_border_fill: Preference::Reference("border_focus"),
552            corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
553            color: Preference::Reference("text_primary"),
554        },
555    );
556    theme.set(
557        "menu_container",
558        MenuContainerThemePreference {
559            background: Preference::Reference("background"),
560            padding: Preference::Specific(Gaps::new_all(4.)),
561            shadow: Preference::Reference("shadow"),
562            border_fill: Preference::Reference("surface_primary"),
563            corner_radius: Preference::Specific(CornerRadius::new_all(8.)),
564        },
565    );
566    theme.set(
567        "button_segment",
568        ButtonSegmentThemePreference {
569            background: Preference::Reference("surface_tertiary"),
570            hover_background: Preference::Reference("hover"),
571            disabled_background: Preference::Reference("disabled"),
572            selected_background: Preference::Reference("hover"),
573            focus_background: Preference::Reference("surface_secondary"),
574            padding: Preference::Specific(Gaps::new(8., 16., 8., 16.)),
575            selected_padding: Preference::Specific(Gaps::new(8., 12., 8., 12.)),
576            width: Preference::Specific(Size::Inner),
577            height: Preference::Specific(Size::Inner),
578            color: Preference::Reference("text_primary"),
579            selected_icon_fill: Preference::Reference("primary"),
580        },
581    );
582    theme.set(
583        "segmented_button",
584        SegmentedButtonThemePreference {
585            background: Preference::Reference("surface_tertiary"),
586            border_fill: Preference::Reference("border"),
587            corner_radius: Preference::Specific(CornerRadius::new_all(99.)),
588        },
589    );
590    #[cfg(feature = "calendar")]
591    theme.set(
592        "calendar",
593        CalendarThemePreference {
594            background: Preference::Reference("surface_tertiary"),
595            day_background: Preference::Specific(Color::TRANSPARENT),
596            day_hover_background: Preference::Reference("hover"),
597            day_selected_background: Preference::Reference("surface_primary"),
598            color: Preference::Reference("text_primary"),
599            day_other_month_color: Preference::Reference("text_placeholder"),
600            header_color: Preference::Reference("text_primary"),
601            corner_radius: Preference::Specific(CornerRadius::new_all(8.)),
602            padding: Preference::Specific(Gaps::new_all(12.)),
603            day_corner_radius: Preference::Specific(CornerRadius::new_all(6.)),
604            nav_button_hover_background: Preference::Reference("hover"),
605        },
606    );
607    #[cfg(feature = "titlebar")]
608    theme.set(
609        "titlebar_button",
610        TitlebarButtonThemePreference {
611            background: Preference::Specific(Color::TRANSPARENT),
612            hover_background: Preference::Reference("hover"),
613            corner_radius: Preference::Specific(CornerRadius::new_all(0.0)),
614            width: Preference::Specific(Size::Pixels(Length::new(46.0))),
615            height: Preference::Specific(Size::Fill),
616        },
617    );
618}
619
620/// Light theme with all built-in component themes registered.
621pub fn light_theme() -> Theme {
622    let mut theme = Theme::new("light", LIGHT_COLORS);
623    register_base_component_themes(&mut theme);
624    theme
625}
626
627/// Dark theme with all built-in component themes registered.
628pub fn dark_theme() -> Theme {
629    let mut theme = Theme::new("dark", DARK_COLORS);
630    register_base_component_themes(&mut theme);
631    theme
632}