1use crate::utils::{is_dark, lighten, darken, mix};
48
49#[derive(Clone, Copy, Debug)]
72pub struct Palette {
73 pub bg: u32,
75 pub text: u32,
77 pub primary: u32,
79 pub accent: u32,
81 pub success: u32,
83 pub error: u32,
85 pub warning: u32,
87}
88
89impl Default for Palette {
90 fn default() -> Self {
91 Self::dark()
92 }
93}
94
95impl Palette {
96 pub fn dark() -> Self {
98 Self {
99 bg: 0x1e1e1e,
100 text: 0xffffff,
101 primary: 0x3b82f6,
102 accent: 0x0078d4,
103 success: 0x4CAF50,
104 error: 0xF44336,
105 warning: 0xF57C00,
106 }
107 }
108
109 pub fn light() -> Self {
111 Self {
112 bg: 0xf5f5f5,
113 text: 0x1a1a1a,
114 primary: 0x3b82f6,
115 accent: 0x0078d4,
116 success: 0x4CAF50,
117 error: 0xF44336,
118 warning: 0xF57C00,
119 }
120 }
121
122 pub fn with_bg(mut self, color: u32) -> Self {
124 self.bg = color;
125 self
126 }
127
128 pub fn with_text(mut self, color: u32) -> Self {
130 self.text = color;
131 self
132 }
133
134 pub fn with_primary(mut self, color: u32) -> Self {
136 self.primary = color;
137 self
138 }
139
140 pub fn with_accent(mut self, color: u32) -> Self {
142 self.accent = color;
143 self
144 }
145
146 pub fn with_success(mut self, color: u32) -> Self {
148 self.success = color;
149 self
150 }
151
152 pub fn with_error(mut self, color: u32) -> Self {
154 self.error = color;
155 self
156 }
157
158 pub fn with_warning(mut self, color: u32) -> Self {
160 self.warning = color;
161 self
162 }
163}
164
165#[derive(Clone, Copy, Debug)]
170pub struct Theme {
171 pub bg_primary: u32,
174 pub bg_secondary: u32,
176 pub bg_input: u32,
178 pub bg_input_hover: u32,
180 pub bg_hover: u32,
182 pub bg_section_header: u32,
184 pub bg_section_header_hover: u32,
186 pub bg_white: u32,
188 pub bg_light_hover: u32,
190
191 pub text_primary: u32,
194 pub text_label: u32,
196 pub text_section_header: u32,
198 pub text_value: u32,
200 pub text_muted: u32,
202 pub text_placeholder: u32,
204 pub text_dimmed: u32,
206 pub text_icon: u32,
208 pub text_dark: u32,
210 pub text_black: u32,
212
213 pub border_default: u32,
216 pub border_checkbox: u32,
218 pub border_input: u32,
220 pub border_menu: u32,
222 pub border_focus: u32,
224 pub border_focus_on_color: u32,
227 pub border_error: u32,
229
230 pub primary: u32,
233 pub primary_hover: u32,
235 pub primary_active: u32,
237 pub accent: u32,
239
240 pub success: u32,
243 pub error: u32,
245 pub warning: u32,
247 pub error_text: u32,
249
250 pub tooltip_bg: u32,
253 pub tooltip_border: u32,
255 pub tooltip_text: u32,
257
258 pub selection: u32,
260
261 pub disabled_bg: u32,
264 pub disabled_text: u32,
266
267 pub secondary_bg: u32,
270 pub secondary_bg_hover: u32,
272 pub secondary_bg_active: u32,
274 pub secondary_border: u32,
276
277 pub bg_tab_hover: u32,
280 pub border_tab_active: u32,
282
283 pub delete_bg: u32,
286 pub delete_bg_hover: u32,
288
289 pub bg_path_hover: u32,
292}
293
294impl Default for Theme {
295 fn default() -> Self {
296 Self::dark()
297 }
298}
299
300impl gpui::Global for Theme {}
302
303impl Theme {
304 pub fn dark() -> Self {
306 Self {
307 bg_primary: 0x1e1e1e,
309 bg_secondary: 0x252525,
310 bg_input: 0x2a2a2a,
311 bg_input_hover: 0x3a3a3a,
312 bg_hover: 0x4a4a4a,
313 bg_section_header: 0x363636,
314 bg_section_header_hover: 0x404040,
315 bg_white: 0xffffff,
316 bg_light_hover: 0xf0f0f0,
317
318 text_primary: 0xffffff,
320 text_label: 0xeeeeee,
321 text_section_header: 0xdddddd,
322 text_value: 0xcccccc,
323 text_muted: 0xaaaaaa,
324 text_placeholder: 0x999999,
325 text_dimmed: 0x888888,
326 text_icon: 0x666666,
327 text_dark: 0x333333,
328 text_black: 0x000000,
329
330 border_default: 0x444444,
332 border_checkbox: 0x666666,
333 border_input: 0x999999,
334 border_menu: 0xcccccc,
335 border_focus: 0x0078d4,
336 border_focus_on_color: 0xffffff, border_error: 0x662222,
338
339 primary: 0x3b82f6,
341 primary_hover: 0x2563eb,
342 primary_active: 0x1d4ed8,
343 accent: 0x0078d4,
344
345 success: 0x4CAF50,
347 error: 0xF44336,
348 warning: 0xF57C00,
349 error_text: 0xFF6B6B,
350
351 tooltip_bg: 0x2a2a2a,
353 tooltip_border: 0x444444,
354 tooltip_text: 0xeeeeee,
355
356 selection: 0x264F78,
358
359 disabled_bg: 0x6b7280,
361 disabled_text: 0x9ca3af,
362
363 secondary_bg: 0x374151,
365 secondary_bg_hover: 0x4b5563,
366 secondary_bg_active: 0x1f2937,
367 secondary_border: 0x6b7280,
368
369 bg_tab_hover: 0x323232,
371 border_tab_active: 0x007acc,
372
373 delete_bg: 0x4a3a3a,
375 delete_bg_hover: 0x5a4a4a,
376
377 bg_path_hover: 0x333333,
379 }
380 }
381
382 pub fn light() -> Self {
384 Self {
385 bg_primary: 0xf5f5f5,
387 bg_secondary: 0xffffff,
388 bg_input: 0xffffff,
389 bg_input_hover: 0xf0f0f0,
390 bg_hover: 0xe0e0e0,
391 bg_section_header: 0xeeeeee,
392 bg_section_header_hover: 0xe5e5e5,
393 bg_white: 0xffffff,
394 bg_light_hover: 0xf5f5f5,
395
396 text_primary: 0x1a1a1a,
398 text_label: 0x333333,
399 text_section_header: 0x444444,
400 text_value: 0x555555,
401 text_muted: 0x777777,
402 text_placeholder: 0x999999,
403 text_dimmed: 0xaaaaaa,
404 text_icon: 0x888888,
405 text_dark: 0x333333,
406 text_black: 0x000000,
407
408 border_default: 0xcccccc,
410 border_checkbox: 0xaaaaaa,
411 border_input: 0x444444,
412 border_menu: 0xdddddd,
413 border_focus: 0x0078d4,
414 border_focus_on_color: 0xffffff, border_error: 0xffcccc,
416
417 primary: 0x3b82f6,
419 primary_hover: 0x2563eb,
420 primary_active: 0x1d4ed8,
421 accent: 0x0078d4,
422
423 success: 0x4CAF50,
425 error: 0xF44336,
426 warning: 0xF57C00,
427 error_text: 0xdc3545,
428
429 tooltip_bg: 0xffffff,
431 tooltip_border: 0xaaaaaa,
432 tooltip_text: 0x333333,
433
434 selection: 0xADD6FF,
436
437 disabled_bg: 0xd1d5db,
439 disabled_text: 0x9ca3af,
440
441 secondary_bg: 0xe5e7eb,
443 secondary_bg_hover: 0xd1d5db,
444 secondary_bg_active: 0xf3f4f6,
445 secondary_border: 0x9ca3af,
446
447 bg_tab_hover: 0xe5e5e5,
449 border_tab_active: 0x0078d4,
450
451 delete_bg: 0xfee2e2,
453 delete_bg_hover: 0xfecaca,
454
455 bg_path_hover: 0xf5f5f5,
457 }
458 }
459
460 pub fn from_palette(palette: Palette) -> Self {
482 let dark_mode = is_dark(palette.bg);
483
484 let opposite = if dark_mode { 0xFFFFFF } else { 0x000000 };
486
487 let bg_primary = palette.bg;
489 let bg_secondary = if dark_mode {
490 lighten(palette.bg, 0.03)
491 } else {
492 0xffffff };
494 let bg_input = if dark_mode {
495 lighten(palette.bg, 0.05)
496 } else {
497 0xffffff
498 };
499 let bg_input_hover = if dark_mode {
500 lighten(palette.bg, 0.12)
501 } else {
502 darken(palette.bg, 0.03)
503 };
504 let bg_hover = if dark_mode {
505 lighten(palette.bg, 0.18)
506 } else {
507 darken(palette.bg, 0.12)
508 };
509 let bg_section_header = if dark_mode {
510 lighten(palette.bg, 0.10)
511 } else {
512 darken(palette.bg, 0.04)
513 };
514 let bg_section_header_hover = if dark_mode {
515 lighten(palette.bg, 0.14)
516 } else {
517 darken(palette.bg, 0.08)
518 };
519
520 let text_primary = palette.text;
522 let text_label = mix(palette.text, opposite, 0.07);
523 let text_section_header = mix(palette.text, opposite, 0.13);
524 let text_value = mix(palette.text, opposite, 0.20);
525 let text_muted = mix(palette.text, opposite, 0.33);
526 let text_placeholder = mix(palette.text, opposite, 0.40);
527 let text_dimmed = mix(palette.text, opposite, 0.47);
528 let text_icon = mix(palette.text, opposite, 0.60);
529
530 let border_default = mix(palette.bg, palette.text, 0.16);
532 let border_checkbox = mix(palette.bg, palette.text, 0.30);
533 let border_input = mix(palette.bg, palette.text, 0.50);
534 let border_menu = mix(palette.bg, palette.text, 0.70);
535 let border_focus = palette.accent;
536 let border_focus_on_color = 0xffffff; let border_error = if dark_mode {
538 darken(palette.error, 0.60)
539 } else {
540 lighten(palette.error, 0.60)
541 };
542
543 let primary_hover = darken(palette.primary, 0.15);
545 let primary_active = darken(palette.primary, 0.25);
546
547 let error_text = if dark_mode {
549 lighten(palette.error, 0.20)
550 } else {
551 darken(palette.error, 0.10)
552 };
553
554 let tooltip_bg = bg_input;
556 let tooltip_border = border_default;
557 let tooltip_text = text_label;
558
559 let selection = if dark_mode {
561 mix(palette.accent, palette.bg, 0.50)
562 } else {
563 lighten(palette.accent, 0.60)
564 };
565
566 let disabled_bg = mix(palette.bg, palette.text, 0.35);
568 let disabled_text = mix(palette.bg, palette.text, 0.50);
569
570 let secondary_bg = if dark_mode {
572 lighten(palette.bg, 0.12)
573 } else {
574 darken(palette.bg, 0.10)
575 };
576 let secondary_bg_hover = if dark_mode {
577 lighten(palette.bg, 0.20)
578 } else {
579 darken(palette.bg, 0.15)
580 };
581 let secondary_bg_active = if dark_mode {
582 darken(palette.bg, 0.05)
583 } else {
584 lighten(palette.bg, 0.02)
585 };
586 let secondary_border = disabled_bg;
587
588 let bg_tab_hover = if dark_mode {
590 lighten(palette.bg, 0.08)
591 } else {
592 darken(palette.bg, 0.06)
593 };
594 let border_tab_active = palette.accent;
595
596 let delete_bg = if dark_mode {
598 mix(palette.bg, palette.error, 0.15)
599 } else {
600 lighten(palette.error, 0.80)
601 };
602 let delete_bg_hover = if dark_mode {
603 mix(palette.bg, palette.error, 0.25)
604 } else {
605 lighten(palette.error, 0.70)
606 };
607
608 let bg_path_hover = if dark_mode {
610 lighten(palette.bg, 0.08)
611 } else {
612 darken(palette.bg, 0.02)
613 };
614
615 Self {
616 bg_primary,
618 bg_secondary,
619 bg_input,
620 bg_input_hover,
621 bg_hover,
622 bg_section_header,
623 bg_section_header_hover,
624 bg_white: 0xffffff,
625 bg_light_hover: 0xf0f0f0,
626
627 text_primary,
629 text_label,
630 text_section_header,
631 text_value,
632 text_muted,
633 text_placeholder,
634 text_dimmed,
635 text_icon,
636 text_dark: 0x333333,
637 text_black: 0x000000,
638
639 border_default,
641 border_checkbox,
642 border_input,
643 border_menu,
644 border_focus,
645 border_focus_on_color,
646 border_error,
647
648 primary: palette.primary,
650 primary_hover,
651 primary_active,
652 accent: palette.accent,
653
654 success: palette.success,
656 error: palette.error,
657 warning: palette.warning,
658 error_text,
659
660 tooltip_bg,
662 tooltip_border,
663 tooltip_text,
664
665 selection,
667
668 disabled_bg,
670 disabled_text,
671
672 secondary_bg,
674 secondary_bg_hover,
675 secondary_bg_active,
676 secondary_border,
677
678 bg_tab_hover,
680 border_tab_active,
681
682 delete_bg,
684 delete_bg_hover,
685
686 bg_path_hover,
688 }
689 }
690
691 pub fn with_accent(mut self, color: u32) -> Self {
695 self.accent = color;
696 self
697 }
698
699 pub fn with_primary(mut self, color: u32) -> Self {
701 self.primary = color;
702 self
703 }
704
705 pub fn with_primary_hover(mut self, color: u32) -> Self {
707 self.primary_hover = color;
708 self
709 }
710
711 pub fn with_border_focus(mut self, color: u32) -> Self {
713 self.border_focus = color;
714 self
715 }
716
717 pub fn with_border_focus_on_color(mut self, color: u32) -> Self {
719 self.border_focus_on_color = color;
720 self
721 }
722
723 pub fn with_success(mut self, color: u32) -> Self {
725 self.success = color;
726 self
727 }
728
729 pub fn with_error(mut self, color: u32) -> Self {
731 self.error = color;
732 self
733 }
734
735 pub fn with_warning(mut self, color: u32) -> Self {
737 self.warning = color;
738 self
739 }
740
741 pub fn with_bg_primary(mut self, color: u32) -> Self {
743 self.bg_primary = color;
744 self
745 }
746
747 pub fn with_bg_input(mut self, color: u32) -> Self {
749 self.bg_input = color;
750 self
751 }
752
753 pub fn with_text_primary(mut self, color: u32) -> Self {
755 self.text_primary = color;
756 self
757 }
758
759 pub fn with_bg_secondary(mut self, color: u32) -> Self {
763 self.bg_secondary = color;
764 self
765 }
766
767 pub fn with_bg_input_hover(mut self, color: u32) -> Self {
769 self.bg_input_hover = color;
770 self
771 }
772
773 pub fn with_bg_hover(mut self, color: u32) -> Self {
775 self.bg_hover = color;
776 self
777 }
778
779 pub fn with_bg_section_header(mut self, color: u32) -> Self {
781 self.bg_section_header = color;
782 self
783 }
784
785 pub fn with_bg_section_header_hover(mut self, color: u32) -> Self {
787 self.bg_section_header_hover = color;
788 self
789 }
790
791 pub fn with_bg_white(mut self, color: u32) -> Self {
793 self.bg_white = color;
794 self
795 }
796
797 pub fn with_bg_light_hover(mut self, color: u32) -> Self {
799 self.bg_light_hover = color;
800 self
801 }
802
803 pub fn with_text_label(mut self, color: u32) -> Self {
807 self.text_label = color;
808 self
809 }
810
811 pub fn with_text_section_header(mut self, color: u32) -> Self {
813 self.text_section_header = color;
814 self
815 }
816
817 pub fn with_text_value(mut self, color: u32) -> Self {
819 self.text_value = color;
820 self
821 }
822
823 pub fn with_text_muted(mut self, color: u32) -> Self {
825 self.text_muted = color;
826 self
827 }
828
829 pub fn with_text_placeholder(mut self, color: u32) -> Self {
831 self.text_placeholder = color;
832 self
833 }
834
835 pub fn with_text_dimmed(mut self, color: u32) -> Self {
837 self.text_dimmed = color;
838 self
839 }
840
841 pub fn with_text_icon(mut self, color: u32) -> Self {
843 self.text_icon = color;
844 self
845 }
846
847 pub fn with_text_dark(mut self, color: u32) -> Self {
849 self.text_dark = color;
850 self
851 }
852
853 pub fn with_text_black(mut self, color: u32) -> Self {
855 self.text_black = color;
856 self
857 }
858
859 pub fn with_border_default(mut self, color: u32) -> Self {
863 self.border_default = color;
864 self
865 }
866
867 pub fn with_border_checkbox(mut self, color: u32) -> Self {
869 self.border_checkbox = color;
870 self
871 }
872
873 pub fn with_border_input(mut self, color: u32) -> Self {
875 self.border_input = color;
876 self
877 }
878
879 pub fn with_border_menu(mut self, color: u32) -> Self {
881 self.border_menu = color;
882 self
883 }
884
885 pub fn with_border_error(mut self, color: u32) -> Self {
887 self.border_error = color;
888 self
889 }
890
891 pub fn with_primary_active(mut self, color: u32) -> Self {
895 self.primary_active = color;
896 self
897 }
898
899 pub fn with_error_text(mut self, color: u32) -> Self {
901 self.error_text = color;
902 self
903 }
904
905 pub fn with_tooltip_bg(mut self, color: u32) -> Self {
909 self.tooltip_bg = color;
910 self
911 }
912
913 pub fn with_tooltip_border(mut self, color: u32) -> Self {
915 self.tooltip_border = color;
916 self
917 }
918
919 pub fn with_tooltip_text(mut self, color: u32) -> Self {
921 self.tooltip_text = color;
922 self
923 }
924
925 pub fn with_selection(mut self, color: u32) -> Self {
929 self.selection = color;
930 self
931 }
932
933 pub fn with_disabled_bg(mut self, color: u32) -> Self {
937 self.disabled_bg = color;
938 self
939 }
940
941 pub fn with_disabled_text(mut self, color: u32) -> Self {
943 self.disabled_text = color;
944 self
945 }
946
947 pub fn with_secondary_bg(mut self, color: u32) -> Self {
951 self.secondary_bg = color;
952 self
953 }
954
955 pub fn with_secondary_bg_hover(mut self, color: u32) -> Self {
957 self.secondary_bg_hover = color;
958 self
959 }
960
961 pub fn with_secondary_bg_active(mut self, color: u32) -> Self {
963 self.secondary_bg_active = color;
964 self
965 }
966
967 pub fn with_secondary_border(mut self, color: u32) -> Self {
969 self.secondary_border = color;
970 self
971 }
972
973 pub fn with_bg_tab_hover(mut self, color: u32) -> Self {
977 self.bg_tab_hover = color;
978 self
979 }
980
981 pub fn with_border_tab_active(mut self, color: u32) -> Self {
983 self.border_tab_active = color;
984 self
985 }
986
987 pub fn with_delete_bg(mut self, color: u32) -> Self {
991 self.delete_bg = color;
992 self
993 }
994
995 pub fn with_delete_bg_hover(mut self, color: u32) -> Self {
997 self.delete_bg_hover = color;
998 self
999 }
1000
1001 pub fn with_bg_path_hover(mut self, color: u32) -> Self {
1005 self.bg_path_hover = color;
1006 self
1007 }
1008}
1009
1010pub fn get_theme(cx: &gpui::App) -> Theme {
1012 cx.try_global::<Theme>()
1013 .copied()
1014 .unwrap_or_else(Theme::dark)
1015}
1016
1017pub fn get_theme_or(cx: &gpui::App, custom: Option<&Theme>) -> Theme {
1019 custom.copied().unwrap_or_else(|| get_theme(cx))
1020}