cronixui 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +35 -5
  2. package/package.json +21 -3
  3. package/packages/go/cronixui/cronixui.go +784 -237
  4. package/packages/go/cronixui/go.mod +34 -9
  5. package/packages/go/cronixui/go.sum +666 -0
  6. package/packages/python/cronixui/__init__.py +131 -1
  7. package/packages/python/cronixui/alert.py +61 -0
  8. package/packages/python/cronixui/avatar.py +50 -0
  9. package/packages/python/cronixui/badge.py +46 -0
  10. package/packages/python/cronixui/button.py +64 -0
  11. package/packages/python/cronixui/card.py +62 -0
  12. package/packages/python/cronixui/form.py +255 -0
  13. package/packages/python/cronixui/layout.py +143 -0
  14. package/packages/python/cronixui/list.py +51 -0
  15. package/packages/python/cronixui/loading.py +36 -0
  16. package/packages/python/cronixui/progress.py +90 -0
  17. package/packages/python/cronixui/table.py +48 -0
  18. package/packages/python/cronixui/tokens.py +200 -0
  19. package/packages/python/cronixui/tooltip.py +28 -0
  20. package/packages/react/src/components/Accordion.tsx +82 -0
  21. package/packages/react/src/components/Alert.tsx +80 -0
  22. package/packages/react/src/components/Avatar.tsx +54 -0
  23. package/packages/react/src/components/Badge.tsx +32 -0
  24. package/packages/react/src/components/Breadcrumb.tsx +50 -0
  25. package/packages/react/src/components/Button.tsx +47 -0
  26. package/packages/react/src/components/Card.tsx +69 -0
  27. package/packages/react/src/components/Checkbox.tsx +30 -0
  28. package/packages/react/src/components/CommandPalette.tsx +131 -0
  29. package/packages/react/src/components/Container.tsx +26 -0
  30. package/packages/react/src/components/Dropdown.tsx +88 -0
  31. package/packages/react/src/components/FileInput.tsx +86 -0
  32. package/packages/react/src/components/Footer.tsx +36 -0
  33. package/packages/react/src/components/FormGroup.tsx +36 -0
  34. package/packages/react/src/components/Header.tsx +29 -0
  35. package/packages/react/src/components/Input.tsx +54 -0
  36. package/packages/react/src/components/List.tsx +55 -0
  37. package/packages/react/src/components/Modal.tsx +89 -0
  38. package/packages/react/src/components/Nav.tsx +63 -0
  39. package/packages/react/src/components/Pagination.tsx +107 -0
  40. package/packages/react/src/components/Progress.tsx +49 -0
  41. package/packages/react/src/components/Radio.tsx +64 -0
  42. package/packages/react/src/components/Search.tsx +95 -0
  43. package/packages/react/src/components/Select.tsx +41 -0
  44. package/packages/react/src/components/Sidebar.tsx +64 -0
  45. package/packages/react/src/components/Skeleton.tsx +39 -0
  46. package/packages/react/src/components/Slider.tsx +32 -0
  47. package/packages/react/src/components/Spinner.tsx +24 -0
  48. package/packages/react/src/components/Stack.tsx +69 -0
  49. package/packages/react/src/components/Stat.tsx +35 -0
  50. package/packages/react/src/components/Table.tsx +90 -0
  51. package/packages/react/src/components/Tabs.tsx +85 -0
  52. package/packages/react/src/components/Tag.tsx +30 -0
  53. package/packages/react/src/components/Textarea.tsx +21 -0
  54. package/packages/react/src/components/Toast.tsx +134 -0
  55. package/packages/react/src/components/Toggle.tsx +58 -0
  56. package/packages/react/src/components/Tooltip.tsx +31 -0
  57. package/packages/react/src/components/Typography.tsx +66 -0
  58. package/packages/react/src/index.ts +40 -0
  59. package/packages/react/src/styles.css +2039 -0
  60. package/packages/react/src/tokens/index.ts +94 -0
  61. package/packages/rust/cronixui/src/colors.rs +135 -0
  62. package/packages/rust/cronixui/src/components/accordion.rs +47 -0
  63. package/packages/rust/cronixui/src/components/alert.rs +95 -0
  64. package/packages/rust/cronixui/src/components/avatar.rs +85 -0
  65. package/packages/rust/cronixui/src/components/badge.rs +35 -0
  66. package/packages/rust/cronixui/src/components/breadcrumb.rs +58 -0
  67. package/packages/rust/cronixui/src/components/button.rs +70 -0
  68. package/packages/rust/cronixui/src/components/card.rs +259 -0
  69. package/packages/rust/cronixui/src/components/command_palette.rs +254 -0
  70. package/packages/rust/cronixui/src/components/dropdown.rs +179 -0
  71. package/packages/rust/cronixui/src/components/file_input.rs +74 -0
  72. package/packages/rust/cronixui/src/components/input.rs +21 -0
  73. package/packages/rust/cronixui/src/components/list.rs +38 -0
  74. package/packages/rust/cronixui/src/components/mod.rs +51 -0
  75. package/packages/rust/cronixui/src/{modal.rs → components/modal.rs} +15 -1
  76. package/packages/rust/cronixui/src/components/nav.rs +19 -0
  77. package/packages/rust/cronixui/src/{pagination.rs → components/pagination.rs} +14 -13
  78. package/packages/rust/cronixui/src/components/progress.rs +50 -0
  79. package/packages/rust/cronixui/src/components/search.rs +185 -0
  80. package/packages/rust/cronixui/src/components/skeleton.rs +63 -0
  81. package/packages/rust/cronixui/src/components/spinner.rs +21 -0
  82. package/packages/rust/cronixui/src/components/table.rs +56 -0
  83. package/packages/rust/cronixui/src/components/tabs.rs +43 -0
  84. package/packages/rust/cronixui/src/components/toast.rs +69 -0
  85. package/packages/rust/cronixui/src/{toggle.rs → components/toggle.rs} +7 -5
  86. package/packages/rust/cronixui/src/components/tooltip.rs +11 -0
  87. package/packages/rust/cronixui/src/lib.rs +111 -62
  88. package/packages/rust/cronixui/src/tokens.rs +107 -0
  89. package/packages/web/src/tokens.ts +120 -0
  90. package/packages/web/src/variables.css +81 -81
  91. package/packages/python/cronixui/pyproject.toml +0 -11
  92. package/packages/react/src/components/Accordion.jsx +0 -50
  93. package/packages/react/src/components/Alert.jsx +0 -62
  94. package/packages/react/src/components/Avatar.jsx +0 -34
  95. package/packages/react/src/components/Badge.jsx +0 -15
  96. package/packages/react/src/components/Breadcrumb.jsx +0 -27
  97. package/packages/react/src/components/Button.jsx +0 -21
  98. package/packages/react/src/components/Card.jsx +0 -23
  99. package/packages/react/src/components/Checkbox.jsx +0 -27
  100. package/packages/react/src/components/CommandPalette.jsx +0 -93
  101. package/packages/react/src/components/Dropdown.jsx +0 -48
  102. package/packages/react/src/components/FileInput.jsx +0 -44
  103. package/packages/react/src/components/Input.jsx +0 -22
  104. package/packages/react/src/components/List.jsx +0 -29
  105. package/packages/react/src/components/Modal.jsx +0 -65
  106. package/packages/react/src/components/Nav.jsx +0 -50
  107. package/packages/react/src/components/Pagination.jsx +0 -81
  108. package/packages/react/src/components/Progress.jsx +0 -23
  109. package/packages/react/src/components/Radio.jsx +0 -50
  110. package/packages/react/src/components/Search.jsx +0 -70
  111. package/packages/react/src/components/Select.jsx +0 -33
  112. package/packages/react/src/components/Skeleton.jsx +0 -15
  113. package/packages/react/src/components/Slider.jsx +0 -29
  114. package/packages/react/src/components/Spinner.jsx +0 -5
  115. package/packages/react/src/components/Stat.jsx +0 -19
  116. package/packages/react/src/components/Table.jsx +0 -48
  117. package/packages/react/src/components/Tabs.jsx +0 -65
  118. package/packages/react/src/components/Tag.jsx +0 -19
  119. package/packages/react/src/components/Textarea.jsx +0 -17
  120. package/packages/react/src/components/Toast.jsx +0 -78
  121. package/packages/react/src/components/Toggle.jsx +0 -34
  122. package/packages/react/src/components/Tooltip.jsx +0 -12
  123. package/packages/react/src/index.d.ts +0 -103
  124. package/packages/react/src/index.js +0 -33
  125. package/packages/rust/cronixui/src/accordion.rs +0 -49
  126. package/packages/rust/cronixui/src/command_palette.rs +0 -62
  127. package/packages/rust/cronixui/src/dropdown.rs +0 -31
  128. package/packages/rust/cronixui/src/search.rs +0 -49
  129. package/packages/rust/cronixui/src/tabs.rs +0 -23
  130. package/packages/rust/cronixui/src/toast.rs +0 -70
@@ -0,0 +1,94 @@
1
+ export const tokens = {
2
+ colors: {
3
+ bg: '#0a0a0a',
4
+ surface: '#111111',
5
+ surface2: '#1a1a1a',
6
+ surface3: '#222222',
7
+ surface4: '#2a2a2a',
8
+ border: 'rgba(255, 255, 255, 0.08)',
9
+ borderHover: 'rgba(255, 255, 255, 0.15)',
10
+ borderFocus: 'rgba(255, 255, 255, 0.25)',
11
+ text: '#f0ede8',
12
+ textMuted: 'rgba(240, 237, 232, 0.5)',
13
+ textDim: 'rgba(240, 237, 232, 0.25)',
14
+ accent: '#6b2323',
15
+ accentHover: '#7d2a2a',
16
+ accentLight: '#8a3535',
17
+ accentGlow: 'rgba(107, 35, 35, 0.3)',
18
+ accentText: '#c97a7a',
19
+ success: '#1e5028',
20
+ successBorder: 'rgba(60, 140, 70, 0.4)',
21
+ successText: '#6bc47a',
22
+ warning: '#503c14',
23
+ warningBorder: 'rgba(150, 110, 30, 0.4)',
24
+ warningText: '#c4a43a',
25
+ error: '#501414',
26
+ errorBorder: 'rgba(180, 60, 60, 0.4)',
27
+ errorText: '#c46b6b',
28
+ info: '#143550',
29
+ infoBorder: 'rgba(60, 140, 200, 0.4)',
30
+ infoText: '#6ba8c4',
31
+ },
32
+ typography: {
33
+ fontFamily: "'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
34
+ fontFamilyMono: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
35
+ fontSize: {
36
+ xs: '11px',
37
+ sm: '12px',
38
+ base: '13px',
39
+ md: '14px',
40
+ lg: '16px',
41
+ xl: '20px',
42
+ '2xl': '28px',
43
+ '3xl': '36px',
44
+ },
45
+ },
46
+ spacing: {
47
+ 1: '4px',
48
+ 2: '8px',
49
+ 3: '12px',
50
+ 4: '16px',
51
+ 5: '20px',
52
+ 6: '24px',
53
+ 8: '32px',
54
+ 10: '40px',
55
+ 12: '48px',
56
+ },
57
+ borderRadius: {
58
+ sm: '6px',
59
+ base: '10px',
60
+ lg: '14px',
61
+ xl: '20px',
62
+ full: '9999px',
63
+ },
64
+ shadows: {
65
+ sm: '0 1px 2px rgba(0, 0, 0, 0.3)',
66
+ base: '0 4px 12px rgba(0, 0, 0, 0.4)',
67
+ lg: '0 8px 24px rgba(0, 0, 0, 0.5)',
68
+ glow: '0 0 20px rgba(107, 35, 35, 0.3)',
69
+ },
70
+ transitions: {
71
+ fast: '0.1s ease',
72
+ base: '0.15s ease',
73
+ slow: '0.25s ease',
74
+ },
75
+ zIndex: {
76
+ dropdown: 100,
77
+ sticky: 200,
78
+ fixed: 300,
79
+ modalBackdrop: 400,
80
+ modal: 500,
81
+ popover: 600,
82
+ tooltip: 700,
83
+ toast: 800,
84
+ },
85
+ layout: {
86
+ containerMax: '1200px',
87
+ sidebarWidth: '260px',
88
+ headerHeight: '56px',
89
+ },
90
+ } as const;
91
+
92
+ export type Tokens = typeof tokens;
93
+
94
+ export default tokens;
@@ -0,0 +1,135 @@
1
+ //! Color tokens for CronixUI
2
+
3
+ use egui::Color32;
4
+
5
+ /// All colors extracted from CSS variables
6
+ #[derive(Debug, Clone, Copy, PartialEq)]
7
+ pub struct Colors {
8
+ // Background
9
+ pub bg: Color32,
10
+ pub surface: Color32,
11
+ pub surface_2: Color32,
12
+ pub surface_3: Color32,
13
+ pub surface_4: Color32,
14
+
15
+ // Text
16
+ pub text: Color32,
17
+ pub text_muted: Color32,
18
+ pub text_dim: Color32,
19
+
20
+ // Accent (Crimson)
21
+ pub accent: Color32,
22
+ pub accent_hover: Color32,
23
+ pub accent_light: Color32,
24
+ pub accent_text: Color32,
25
+
26
+ // Semantic - Success
27
+ pub success: Color32,
28
+ pub success_border: Color32,
29
+ pub success_text: Color32,
30
+
31
+ // Semantic - Warning
32
+ pub warning: Color32,
33
+ pub warning_border: Color32,
34
+ pub warning_text: Color32,
35
+
36
+ // Semantic - Error
37
+ pub error: Color32,
38
+ pub error_border: Color32,
39
+ pub error_text: Color32,
40
+
41
+ // Semantic - Info
42
+ pub info: Color32,
43
+ pub info_border: Color32,
44
+ pub info_text: Color32,
45
+
46
+ // Border
47
+ pub border: Color32,
48
+ pub border_hover: Color32,
49
+ pub border_focus: Color32,
50
+ }
51
+
52
+ impl Default for Colors {
53
+ fn default() -> Self {
54
+ Self {
55
+ // Background
56
+ bg: Color32::from_rgb(10, 10, 10),
57
+ surface: Color32::from_rgb(17, 17, 17),
58
+ surface_2: Color32::from_rgb(26, 26, 26),
59
+ surface_3: Color32::from_rgb(34, 34, 34),
60
+ surface_4: Color32::from_rgb(42, 42, 42),
61
+
62
+ // Text
63
+ text: Color32::from_rgb(240, 237, 232),
64
+ text_muted: Color32::from_rgba_unmultiplied(240, 237, 232, 128),
65
+ text_dim: Color32::from_rgba_unmultiplied(240, 237, 232, 64),
66
+
67
+ // Accent
68
+ accent: Color32::from_rgb(107, 35, 35),
69
+ accent_hover: Color32::from_rgb(125, 42, 42),
70
+ accent_light: Color32::from_rgb(138, 53, 53),
71
+ accent_text: Color32::from_rgb(201, 122, 122),
72
+
73
+ // Success
74
+ success: Color32::from_rgb(30, 80, 40),
75
+ success_border: Color32::from_rgba_unmultiplied(60, 140, 70, 102),
76
+ success_text: Color32::from_rgb(107, 196, 122),
77
+
78
+ // Warning
79
+ warning: Color32::from_rgb(80, 60, 20),
80
+ warning_border: Color32::from_rgba_unmultiplied(150, 110, 30, 102),
81
+ warning_text: Color32::from_rgb(196, 164, 58),
82
+
83
+ // Error
84
+ error: Color32::from_rgb(80, 20, 20),
85
+ error_border: Color32::from_rgba_unmultiplied(180, 60, 60, 102),
86
+ error_text: Color32::from_rgb(196, 107, 107),
87
+
88
+ // Info
89
+ info: Color32::from_rgb(20, 53, 80),
90
+ info_border: Color32::from_rgba_unmultiplied(60, 140, 200, 102),
91
+ info_text: Color32::from_rgb(107, 168, 196),
92
+
93
+ // Border
94
+ border: Color32::from_rgba_unmultiplied(255, 255, 255, 20),
95
+ border_hover: Color32::from_rgba_unmultiplied(255, 255, 255, 38),
96
+ border_focus: Color32::from_rgba_unmultiplied(255, 255, 255, 64),
97
+ }
98
+ }
99
+ }
100
+
101
+ // Background color constants
102
+ pub const BG: Color32 = Color32::from_rgb(10, 10, 10);
103
+ pub const SURFACE: Color32 = Color32::from_rgb(17, 17, 17);
104
+ pub const SURFACE_2: Color32 = Color32::from_rgb(26, 26, 26);
105
+ pub const SURFACE_3: Color32 = Color32::from_rgb(34, 34, 34);
106
+ pub const SURFACE_4: Color32 = Color32::from_rgb(42, 42, 42);
107
+
108
+ // Text color constants
109
+ pub const TEXT: Color32 = Color32::from_rgb(240, 237, 232);
110
+ pub const TEXT_MUTED: Color32 = Color32::from_rgba_unmultiplied(240, 237, 232, 128);
111
+ pub const TEXT_DIM: Color32 = Color32::from_rgba_unmultiplied(240, 237, 232, 64);
112
+
113
+ // Accent color constants
114
+ pub const ACCENT: Color32 = Color32::from_rgb(107, 35, 35);
115
+ pub const ACCENT_HOVER: Color32 = Color32::from_rgb(125, 42, 42);
116
+ pub const ACCENT_LIGHT: Color32 = Color32::from_rgb(138, 53, 53);
117
+ pub const ACCENT_TEXT: Color32 = Color32::from_rgb(201, 122, 122);
118
+
119
+ // Semantic color constants
120
+ pub const SUCCESS: Color32 = Color32::from_rgb(30, 80, 40);
121
+ pub const SUCCESS_TEXT: Color32 = Color32::from_rgb(107, 196, 122);
122
+
123
+ pub const WARNING: Color32 = Color32::from_rgb(80, 60, 20);
124
+ pub const WARNING_TEXT: Color32 = Color32::from_rgb(196, 164, 58);
125
+
126
+ pub const ERROR: Color32 = Color32::from_rgb(80, 20, 20);
127
+ pub const ERROR_TEXT: Color32 = Color32::from_rgb(196, 107, 107);
128
+
129
+ pub const INFO: Color32 = Color32::from_rgb(20, 53, 80);
130
+ pub const INFO_TEXT: Color32 = Color32::from_rgb(107, 168, 196);
131
+
132
+ // Border color constants
133
+ pub const BORDER: Color32 = Color32::from_rgba_unmultiplied(255, 255, 255, 20);
134
+ pub const BORDER_HOVER: Color32 = Color32::from_rgba_unmultiplied(255, 255, 255, 38);
135
+ pub const BORDER_FOCUS: Color32 = Color32::from_rgba_unmultiplied(255, 255, 255, 64);
@@ -0,0 +1,47 @@
1
+ //! Accordion component
2
+
3
+ pub struct Accordion {
4
+ pub open_indices: Vec<bool>,
5
+ }
6
+
7
+ impl Accordion {
8
+ pub fn new(count: usize) -> Self {
9
+ Self {
10
+ open_indices: vec![false; count],
11
+ }
12
+ }
13
+
14
+ pub fn toggle(&mut self, index: usize) {
15
+ if index < self.open_indices.len() {
16
+ self.open_indices[index] = !self.open_indices[index];
17
+ }
18
+ }
19
+
20
+ pub fn open(&mut self, index: usize) {
21
+ if index < self.open_indices.len() {
22
+ self.open_indices[index] = true;
23
+ }
24
+ }
25
+
26
+ pub fn close(&mut self, index: usize) {
27
+ if index < self.open_indices.len() {
28
+ self.open_indices[index] = false;
29
+ }
30
+ }
31
+
32
+ pub fn open_all(&mut self) {
33
+ for open in &mut self.open_indices {
34
+ *open = true;
35
+ }
36
+ }
37
+
38
+ pub fn close_all(&mut self) {
39
+ for open in &mut self.open_indices {
40
+ *open = false;
41
+ }
42
+ }
43
+
44
+ pub fn is_open(&self, index: usize) -> bool {
45
+ self.open_indices.get(index).copied().unwrap_or(false)
46
+ }
47
+ }
@@ -0,0 +1,95 @@
1
+ //! Alert component
2
+
3
+ use crate::colors::*;
4
+ use egui::Color32;
5
+
6
+ pub enum AlertVariant {
7
+ Info,
8
+ Success,
9
+ Warning,
10
+ Error,
11
+ }
12
+
13
+ impl AlertVariant {
14
+ pub fn bg_color(&self) -> Color32 {
15
+ match self {
16
+ AlertVariant::Info => INFO,
17
+ AlertVariant::Success => SUCCESS,
18
+ AlertVariant::Warning => WARNING,
19
+ AlertVariant::Error => ERROR,
20
+ }
21
+ }
22
+
23
+ pub fn border_color(&self) -> Color32 {
24
+ match self {
25
+ AlertVariant::Info => INFO_TEXT,
26
+ AlertVariant::Success => SUCCESS_TEXT,
27
+ AlertVariant::Warning => WARNING_TEXT,
28
+ AlertVariant::Error => ERROR_TEXT,
29
+ }
30
+ }
31
+
32
+ pub fn icon(&self) -> &'static str {
33
+ match self {
34
+ AlertVariant::Info => "ℹ",
35
+ AlertVariant::Success => "✓",
36
+ AlertVariant::Warning => "⚠",
37
+ AlertVariant::Error => "✕",
38
+ }
39
+ }
40
+ }
41
+
42
+ pub struct Alert {
43
+ pub title: Option<String>,
44
+ pub message: String,
45
+ pub variant: AlertVariant,
46
+ pub dismissible: bool,
47
+ }
48
+
49
+ impl Alert {
50
+ pub fn info(message: impl Into<String>) -> Self {
51
+ Self {
52
+ title: None,
53
+ message: message.into(),
54
+ variant: AlertVariant::Info,
55
+ dismissible: false,
56
+ }
57
+ }
58
+
59
+ pub fn success(message: impl Into<String>) -> Self {
60
+ Self {
61
+ title: None,
62
+ message: message.into(),
63
+ variant: AlertVariant::Success,
64
+ dismissible: false,
65
+ }
66
+ }
67
+
68
+ pub fn warning(message: impl Into<String>) -> Self {
69
+ Self {
70
+ title: None,
71
+ message: message.into(),
72
+ variant: AlertVariant::Warning,
73
+ dismissible: false,
74
+ }
75
+ }
76
+
77
+ pub fn error(message: impl Into<String>) -> Self {
78
+ Self {
79
+ title: None,
80
+ message: message.into(),
81
+ variant: AlertVariant::Error,
82
+ dismissible: false,
83
+ }
84
+ }
85
+
86
+ pub fn title(mut self, title: impl Into<String>) -> Self {
87
+ self.title = Some(title.into());
88
+ self
89
+ }
90
+
91
+ pub fn dismissible(mut self) -> Self {
92
+ self.dismissible = true;
93
+ self
94
+ }
95
+ }
@@ -0,0 +1,85 @@
1
+ //! Avatar component
2
+
3
+ use egui::*;
4
+ use crate::{colors::*, tokens::*};
5
+
6
+ pub struct Avatar {
7
+ pub initials: String,
8
+ pub size: AvatarSize,
9
+ }
10
+
11
+ #[derive(Clone, Copy)]
12
+ pub enum AvatarSize {
13
+ SM,
14
+ MD,
15
+ LG,
16
+ XL,
17
+ }
18
+
19
+ impl AvatarSize {
20
+ pub fn diameter(&self) -> f32 {
21
+ match self {
22
+ AvatarSize::SM => 24.0,
23
+ AvatarSize::MD => 32.0,
24
+ AvatarSize::LG => 40.0,
25
+ AvatarSize::XL => 56.0,
26
+ }
27
+ }
28
+
29
+ pub fn font_size(&self) -> f32 {
30
+ match self {
31
+ AvatarSize::SM => 10.0,
32
+ AvatarSize::MD => 12.0,
33
+ AvatarSize::LG => 14.0,
34
+ AvatarSize::XL => 18.0,
35
+ }
36
+ }
37
+ }
38
+
39
+ impl Avatar {
40
+ pub fn new(initials: impl Into<String>) -> Self {
41
+ Self {
42
+ initials: initials.into(),
43
+ size: AvatarSize::MD,
44
+ }
45
+ }
46
+
47
+ pub fn size(mut self, size: AvatarSize) -> Self {
48
+ self.size = size;
49
+ self
50
+ }
51
+
52
+ pub fn show(&self, ui: &mut Ui) -> Response {
53
+ let colors = Colors::default();
54
+ let diameter = self.size.diameter();
55
+ let font_size = self.size.font_size();
56
+ let radius = diameter / 2.0;
57
+
58
+ let (rect, response) = ui.allocate_exact_size(vec2(diameter, diameter), Sense::hover());
59
+
60
+ // Draw background circle
61
+ ui.painter().circle_filled(
62
+ rect.center(),
63
+ radius,
64
+ colors.accent,
65
+ );
66
+
67
+ // Draw border
68
+ ui.painter().circle_stroke(
69
+ rect.center(),
70
+ radius,
71
+ Stroke::new(1.0, colors.border),
72
+ );
73
+
74
+ // Draw initials text
75
+ ui.painter().text(
76
+ rect.center(),
77
+ Align2::CENTER_CENTER,
78
+ &self.initials,
79
+ FontId::new(font_size, FontFamily::Proportional),
80
+ colors.accent_text,
81
+ );
82
+
83
+ response
84
+ }
85
+ }
@@ -0,0 +1,35 @@
1
+ //! Badge component
2
+
3
+ use crate::colors::*;
4
+ use egui::Color32;
5
+
6
+ pub enum BadgeVariant {
7
+ Default,
8
+ Accent,
9
+ Success,
10
+ Warning,
11
+ Error,
12
+ Info,
13
+ }
14
+
15
+ pub fn badge_color(variant: BadgeVariant) -> Color32 {
16
+ match variant {
17
+ BadgeVariant::Default => SURFACE_2,
18
+ BadgeVariant::Accent => ACCENT,
19
+ BadgeVariant::Success => SUCCESS,
20
+ BadgeVariant::Warning => WARNING,
21
+ BadgeVariant::Error => ERROR,
22
+ BadgeVariant::Info => INFO,
23
+ }
24
+ }
25
+
26
+ pub fn badge_text_color(variant: BadgeVariant) -> Color32 {
27
+ match variant {
28
+ BadgeVariant::Default => TEXT_MUTED,
29
+ BadgeVariant::Accent => ACCENT_TEXT,
30
+ BadgeVariant::Success => SUCCESS_TEXT,
31
+ BadgeVariant::Warning => WARNING_TEXT,
32
+ BadgeVariant::Error => ERROR_TEXT,
33
+ BadgeVariant::Info => INFO_TEXT,
34
+ }
35
+ }
@@ -0,0 +1,58 @@
1
+ //! Breadcrumb component
2
+
3
+ use egui::*;
4
+ use crate::{colors::*, tokens::*};
5
+
6
+ pub struct Breadcrumb {
7
+ pub items: Vec<String>,
8
+ }
9
+
10
+ impl Breadcrumb {
11
+ pub fn new() -> Self {
12
+ Self { items: Vec::new() }
13
+ }
14
+
15
+ pub fn item(mut self, item: impl Into<String>) -> Self {
16
+ self.items.push(item.into());
17
+ self
18
+ }
19
+
20
+ pub fn show(&self, ui: &mut Ui) -> Response {
21
+ let colors = Colors::default();
22
+
23
+ ui.horizontal(|ui| {
24
+ for (i, item) in self.items.iter().enumerate() {
25
+ if i > 0 {
26
+ ui.label(
27
+ RichText::new("/")
28
+ .size(tokens::FONT_SIZE_SM)
29
+ .color(colors.text_muted),
30
+ );
31
+ }
32
+
33
+ let is_last = i == self.items.len() - 1;
34
+ if is_last {
35
+ ui.label(
36
+ RichText::new(item)
37
+ .size(tokens::FONT_SIZE_BASE)
38
+ .color(colors.text)
39
+ .strong(),
40
+ );
41
+ } else {
42
+ ui.hyperlink_to(
43
+ RichText::new(item)
44
+ .size(tokens::FONT_SIZE_BASE)
45
+ .color(colors.accent_text),
46
+ format!("#{}", item.to_lowercase().replace(" ", "-")),
47
+ );
48
+ }
49
+ }
50
+ }).response
51
+ }
52
+ }
53
+
54
+ impl Default for Breadcrumb {
55
+ fn default() -> Self {
56
+ Self::new()
57
+ }
58
+ }
@@ -0,0 +1,70 @@
1
+ //! Button component
2
+
3
+ use egui::{Color32, Ui};
4
+
5
+ use crate::{colors::*, tokens::*};
6
+
7
+ pub enum ButtonVariant {
8
+ Default,
9
+ Primary,
10
+ Ghost,
11
+ Outline,
12
+ Danger,
13
+ Success,
14
+ }
15
+
16
+ pub trait ButtonExt {
17
+ fn button_primary(&mut self, text: &str) -> egui::Response;
18
+ fn button_danger(&mut self, text: &str) -> egui::Response;
19
+ fn button_success(&mut self, text: &str) -> egui::Response;
20
+ fn button_ghost(&mut self, text: &str) -> egui::Response;
21
+ fn button_outline(&mut self, text: &str) -> egui::Response;
22
+ }
23
+
24
+ impl ButtonExt for Ui {
25
+ fn button_primary(&mut self, text: &str) -> egui::Response {
26
+ self.add(egui::Button::new(text).fill(ACCENT))
27
+ }
28
+
29
+ fn button_danger(&mut self, text: &str) -> egui::Response {
30
+ self.add(egui::Button::new(text).fill(ERROR))
31
+ }
32
+
33
+ fn button_success(&mut self, text: &str) -> egui::Response {
34
+ self.add(egui::Button::new(text).fill(SUCCESS))
35
+ }
36
+
37
+ fn button_ghost(&mut self, text: &str) -> egui::Response {
38
+ self.add(egui::Button::new(text).fill(Color32::TRANSPARENT))
39
+ }
40
+
41
+ fn button_outline(&mut self, text: &str) -> egui::Response {
42
+ self.add(egui::Button::new(text)
43
+ .fill(Color32::TRANSPARENT)
44
+ .stroke(egui::Stroke::new(1.0, BORDER)))
45
+ }
46
+ }
47
+
48
+ pub fn button(ui: &mut Ui, text: &str) -> egui::Response {
49
+ ui.button(text)
50
+ }
51
+
52
+ pub fn button_primary(ui: &mut Ui, text: &str) -> egui::Response {
53
+ ui.button_primary(text)
54
+ }
55
+
56
+ pub fn button_danger(ui: &mut Ui, text: &str) -> egui::Response {
57
+ ui.button_danger(text)
58
+ }
59
+
60
+ pub fn button_success(ui: &mut Ui, text: &str) -> egui::Response {
61
+ ui.button_success(text)
62
+ }
63
+
64
+ pub fn button_ghost(ui: &mut Ui, text: &str) -> egui::Response {
65
+ ui.button_ghost(text)
66
+ }
67
+
68
+ pub fn button_outline(ui: &mut Ui, text: &str) -> egui::Response {
69
+ ui.button_outline(text)
70
+ }