cronixui 1.0.6 → 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 (129) hide show
  1. package/README.md +35 -5
  2. package/package.json +19 -5
  3. package/packages/go/cronixui/cronixui.go +784 -237
  4. package/packages/go/cronixui/go.mod +32 -0
  5. package/packages/go/cronixui/go.sum +666 -0
  6. package/packages/python/cronixui/__init__.py +59 -3
  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/tooltip.py +28 -0
  19. package/packages/react/src/components/Accordion.tsx +82 -0
  20. package/packages/react/src/components/Alert.tsx +80 -0
  21. package/packages/react/src/components/Avatar.tsx +54 -0
  22. package/packages/react/src/components/Badge.tsx +32 -0
  23. package/packages/react/src/components/Breadcrumb.tsx +50 -0
  24. package/packages/react/src/components/Button.tsx +47 -0
  25. package/packages/react/src/components/Card.tsx +69 -0
  26. package/packages/react/src/components/Checkbox.tsx +30 -0
  27. package/packages/react/src/components/CommandPalette.tsx +131 -0
  28. package/packages/react/src/components/Container.tsx +26 -0
  29. package/packages/react/src/components/Dropdown.tsx +88 -0
  30. package/packages/react/src/components/FileInput.tsx +86 -0
  31. package/packages/react/src/components/Footer.tsx +36 -0
  32. package/packages/react/src/components/FormGroup.tsx +36 -0
  33. package/packages/react/src/components/Header.tsx +29 -0
  34. package/packages/react/src/components/Input.tsx +54 -0
  35. package/packages/react/src/components/List.tsx +55 -0
  36. package/packages/react/src/components/Modal.tsx +89 -0
  37. package/packages/react/src/components/Nav.tsx +63 -0
  38. package/packages/react/src/components/Pagination.tsx +107 -0
  39. package/packages/react/src/components/Progress.tsx +49 -0
  40. package/packages/react/src/components/Radio.tsx +64 -0
  41. package/packages/react/src/components/Search.tsx +95 -0
  42. package/packages/react/src/components/Select.tsx +41 -0
  43. package/packages/react/src/components/Sidebar.tsx +64 -0
  44. package/packages/react/src/components/Skeleton.tsx +39 -0
  45. package/packages/react/src/components/Slider.tsx +32 -0
  46. package/packages/react/src/components/Spinner.tsx +24 -0
  47. package/packages/react/src/components/Stack.tsx +69 -0
  48. package/packages/react/src/components/Stat.tsx +35 -0
  49. package/packages/react/src/components/Table.tsx +90 -0
  50. package/packages/react/src/components/Tabs.tsx +85 -0
  51. package/packages/react/src/components/Tag.tsx +30 -0
  52. package/packages/react/src/components/Textarea.tsx +21 -0
  53. package/packages/react/src/components/Toast.tsx +134 -0
  54. package/packages/react/src/components/Toggle.tsx +58 -0
  55. package/packages/react/src/components/Tooltip.tsx +31 -0
  56. package/packages/react/src/components/Typography.tsx +66 -0
  57. package/packages/react/src/index.ts +40 -0
  58. package/packages/react/src/styles.css +2039 -0
  59. package/packages/react/src/tokens/index.ts +94 -0
  60. package/packages/rust/cronixui/src/colors.rs +135 -0
  61. package/packages/rust/cronixui/src/components/accordion.rs +47 -0
  62. package/packages/rust/cronixui/src/components/alert.rs +95 -0
  63. package/packages/rust/cronixui/src/components/avatar.rs +85 -0
  64. package/packages/rust/cronixui/src/components/badge.rs +35 -0
  65. package/packages/rust/cronixui/src/components/breadcrumb.rs +58 -0
  66. package/packages/rust/cronixui/src/components/button.rs +70 -0
  67. package/packages/rust/cronixui/src/components/card.rs +259 -0
  68. package/packages/rust/cronixui/src/components/command_palette.rs +254 -0
  69. package/packages/rust/cronixui/src/components/dropdown.rs +179 -0
  70. package/packages/rust/cronixui/src/components/file_input.rs +74 -0
  71. package/packages/rust/cronixui/src/components/input.rs +21 -0
  72. package/packages/rust/cronixui/src/components/list.rs +38 -0
  73. package/packages/rust/cronixui/src/components/mod.rs +51 -0
  74. package/packages/rust/cronixui/src/{modal.rs → components/modal.rs} +15 -1
  75. package/packages/rust/cronixui/src/components/nav.rs +19 -0
  76. package/packages/rust/cronixui/src/{pagination.rs → components/pagination.rs} +14 -13
  77. package/packages/rust/cronixui/src/components/progress.rs +50 -0
  78. package/packages/rust/cronixui/src/components/search.rs +185 -0
  79. package/packages/rust/cronixui/src/components/skeleton.rs +63 -0
  80. package/packages/rust/cronixui/src/components/spinner.rs +21 -0
  81. package/packages/rust/cronixui/src/components/table.rs +56 -0
  82. package/packages/rust/cronixui/src/components/tabs.rs +43 -0
  83. package/packages/rust/cronixui/src/components/toast.rs +69 -0
  84. package/packages/rust/cronixui/src/{toggle.rs → components/toggle.rs} +7 -5
  85. package/packages/rust/cronixui/src/components/tooltip.rs +11 -0
  86. package/packages/rust/cronixui/src/lib.rs +111 -64
  87. package/packages/rust/cronixui/src/tokens.rs +97 -127
  88. package/packages/web/src/variables.css +81 -81
  89. package/packages/go/cronixui/tokens.go +0 -129
  90. package/packages/python/cronixui/pyproject.toml +0 -11
  91. package/packages/react/src/components/Accordion.jsx +0 -50
  92. package/packages/react/src/components/Alert.jsx +0 -62
  93. package/packages/react/src/components/Avatar.jsx +0 -34
  94. package/packages/react/src/components/Badge.jsx +0 -15
  95. package/packages/react/src/components/Breadcrumb.jsx +0 -27
  96. package/packages/react/src/components/Button.jsx +0 -21
  97. package/packages/react/src/components/Card.jsx +0 -23
  98. package/packages/react/src/components/Checkbox.jsx +0 -27
  99. package/packages/react/src/components/CommandPalette.jsx +0 -93
  100. package/packages/react/src/components/Dropdown.jsx +0 -48
  101. package/packages/react/src/components/FileInput.jsx +0 -44
  102. package/packages/react/src/components/Input.jsx +0 -22
  103. package/packages/react/src/components/List.jsx +0 -29
  104. package/packages/react/src/components/Modal.jsx +0 -65
  105. package/packages/react/src/components/Nav.jsx +0 -50
  106. package/packages/react/src/components/Pagination.jsx +0 -81
  107. package/packages/react/src/components/Progress.jsx +0 -23
  108. package/packages/react/src/components/Radio.jsx +0 -50
  109. package/packages/react/src/components/Search.jsx +0 -70
  110. package/packages/react/src/components/Select.jsx +0 -33
  111. package/packages/react/src/components/Skeleton.jsx +0 -15
  112. package/packages/react/src/components/Slider.jsx +0 -29
  113. package/packages/react/src/components/Spinner.jsx +0 -5
  114. package/packages/react/src/components/Stat.jsx +0 -19
  115. package/packages/react/src/components/Table.jsx +0 -48
  116. package/packages/react/src/components/Tabs.jsx +0 -65
  117. package/packages/react/src/components/Tag.jsx +0 -19
  118. package/packages/react/src/components/Textarea.jsx +0 -17
  119. package/packages/react/src/components/Toast.jsx +0 -78
  120. package/packages/react/src/components/Toggle.jsx +0 -34
  121. package/packages/react/src/components/Tooltip.jsx +0 -12
  122. package/packages/react/src/index.d.ts +0 -103
  123. package/packages/react/src/index.js +0 -33
  124. package/packages/rust/cronixui/src/accordion.rs +0 -49
  125. package/packages/rust/cronixui/src/command_palette.rs +0 -62
  126. package/packages/rust/cronixui/src/dropdown.rs +0 -31
  127. package/packages/rust/cronixui/src/search.rs +0 -49
  128. package/packages/rust/cronixui/src/tabs.rs +0 -23
  129. package/packages/rust/cronixui/src/toast.rs +0 -70
@@ -1,93 +1,93 @@
1
1
  :root {
2
- /* Colors */
3
- --fl-bg: #0a0a0a;
4
- --fl-surface: #111111;
5
- --fl-surface-2: #1a1a1a;
6
- --fl-surface-3: #222222;
7
- --fl-surface-4: #2a2a2a;
8
- --fl-border: rgba(255, 255, 255, 0.08);
9
- --fl-border-hover: rgba(255, 255, 255, 0.15);
10
- --fl-border-focus: rgba(255, 255, 255, 0.25);
11
- --fl-text: #f0ede8;
12
- --fl-text-muted: rgba(240, 237, 232, 0.5);
13
- --fl-text-dim: rgba(240, 237, 232, 0.25);
2
+ /* Colors */
3
+ --cn-bg: #0a0a0a;
4
+ --cn-surface: #111111;
5
+ --cn-surface-2: #1a1a1a;
6
+ --cn-surface-3: #222222;
7
+ --cn-surface-4: #2a2a2a;
8
+ --cn-border: rgba(255, 255, 255, 0.08);
9
+ --cn-border-hover: rgba(255, 255, 255, 0.15);
10
+ --cn-border-focus: rgba(255, 255, 255, 0.25);
11
+ --cn-text: #f0ede8;
12
+ --cn-text-muted: rgba(240, 237, 232, 0.5);
13
+ --cn-text-dim: rgba(240, 237, 232, 0.25);
14
14
 
15
- /* Accent (Crimson) */
16
- --fl-accent: #6b2323;
17
- --fl-accent-hover: #7d2a2a;
18
- --fl-accent-light: #8a3535;
19
- --fl-accent-glow: rgba(107, 35, 35, 0.3);
20
- --fl-accent-text: #c97a7a;
15
+ /* Accent (Crimson) */
16
+ --cn-accent: #6b2323;
17
+ --cn-accent-hover: #7d2a2a;
18
+ --cn-accent-light: #8a3535;
19
+ --cn-accent-glow: rgba(107, 35, 35, 0.3);
20
+ --cn-accent-text: #c97a7a;
21
21
 
22
- /* Status Colors */
23
- --fl-success: #1e5028;
24
- --fl-success-border: rgba(60, 140, 70, 0.4);
25
- --fl-success-text: #6bc47a;
26
- --fl-warning: #503c14;
27
- --fl-warning-border: rgba(150, 110, 30, 0.4);
28
- --fl-warning-text: #c4a43a;
29
- --fl-error: #501414;
30
- --fl-error-border: rgba(180, 60, 60, 0.4);
31
- --fl-error-text: #c46b6b;
32
- --fl-info: #143550;
33
- --fl-info-border: rgba(60, 140, 200, 0.4);
34
- --fl-info-text: #6ba8c4;
22
+ /* Status Colors */
23
+ --cn-success: #1e5028;
24
+ --cn-success-border: rgba(60, 140, 70, 0.4);
25
+ --cn-success-text: #6bc47a;
26
+ --cn-warning: #503c14;
27
+ --cn-warning-border: rgba(150, 110, 30, 0.4);
28
+ --cn-warning-text: #c4a43a;
29
+ --cn-error: #501414;
30
+ --cn-error-border: rgba(180, 60, 60, 0.4);
31
+ --cn-error-text: #c46b6b;
32
+ --cn-info: #143550;
33
+ --cn-info-border: rgba(60, 140, 200, 0.4);
34
+ --cn-info-text: #6ba8c4;
35
35
 
36
- /* Typography */
37
- --fl-font: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
38
- --fl-font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
36
+ /* Typography */
37
+ --cn-font: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
38
+ --cn-font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
39
39
 
40
- /* Font Sizes */
41
- --fl-text-xs: 11px;
42
- --fl-text-sm: 12px;
43
- --fl-text-base: 13px;
44
- --fl-text-md: 14px;
45
- --fl-text-lg: 16px;
46
- --fl-text-xl: 20px;
47
- --fl-text-2xl: 28px;
48
- --fl-text-3xl: 36px;
40
+ /* Font Sizes */
41
+ --cn-text-xs: 11px;
42
+ --cn-text-sm: 12px;
43
+ --cn-text-base: 13px;
44
+ --cn-text-md: 14px;
45
+ --cn-text-lg: 16px;
46
+ --cn-text-xl: 20px;
47
+ --cn-text-2xl: 28px;
48
+ --cn-text-3xl: 36px;
49
49
 
50
- /* Spacing */
51
- --fl-space-1: 4px;
52
- --fl-space-2: 8px;
53
- --fl-space-3: 12px;
54
- --fl-space-4: 16px;
55
- --fl-space-5: 20px;
56
- --fl-space-6: 24px;
57
- --fl-space-8: 32px;
58
- --fl-space-10: 40px;
59
- --fl-space-12: 48px;
50
+ /* Spacing */
51
+ --cn-space-1: 4px;
52
+ --cn-space-2: 8px;
53
+ --cn-space-3: 12px;
54
+ --cn-space-4: 16px;
55
+ --cn-space-5: 20px;
56
+ --cn-space-6: 24px;
57
+ --cn-space-8: 32px;
58
+ --cn-space-10: 40px;
59
+ --cn-space-12: 48px;
60
60
 
61
- /* Border Radius */
62
- --fl-radius-sm: 6px;
63
- --fl-radius: 10px;
64
- --fl-radius-lg: 14px;
65
- --fl-radius-xl: 20px;
66
- --fl-radius-full: 9999px;
61
+ /* Border Radius */
62
+ --cn-radius-sm: 6px;
63
+ --cn-radius: 10px;
64
+ --cn-radius-lg: 14px;
65
+ --cn-radius-xl: 20px;
66
+ --cn-radius-full: 9999px;
67
67
 
68
- /* Shadows */
69
- --fl-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
70
- --fl-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
71
- --fl-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
72
- --fl-shadow-glow: 0 0 20px var(--fl-accent-glow);
68
+ /* Shadows */
69
+ --cn-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
70
+ --cn-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
71
+ --cn-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
72
+ --cn-shadow-glow: 0 0 20px var(--cn-accent-glow);
73
73
 
74
- /* Transitions */
75
- --fl-transition-fast: 0.1s ease;
76
- --fl-transition: 0.15s ease;
77
- --fl-transition-slow: 0.25s ease;
74
+ /* Transitions */
75
+ --cn-transition-fast: 0.1s ease;
76
+ --cn-transition: 0.15s ease;
77
+ --cn-transition-slow: 0.25s ease;
78
78
 
79
- /* Z-Index */
80
- --fl-z-dropdown: 100;
81
- --fl-z-sticky: 200;
82
- --fl-z-fixed: 300;
83
- --fl-z-modal-backdrop: 400;
84
- --fl-z-modal: 500;
85
- --fl-z-popover: 600;
86
- --fl-z-tooltip: 700;
87
- --fl-z-toast: 800;
79
+ /* Z-Index */
80
+ --cn-z-dropdown: 100;
81
+ --cn-z-sticky: 200;
82
+ --cn-z-fixed: 300;
83
+ --cn-z-modal-backdrop: 400;
84
+ --cn-z-modal: 500;
85
+ --cn-z-popover: 600;
86
+ --cn-z-tooltip: 700;
87
+ --cn-z-toast: 800;
88
88
 
89
- /* Layout */
90
- --fl-container-max: 1200px;
91
- --fl-sidebar-width: 260px;
92
- --fl-header-height: 56px;
89
+ /* Layout */
90
+ --cn-container-max: 1200px;
91
+ --cn-sidebar-width: 260px;
92
+ --cn-header-height: 56px;
93
93
  }
@@ -1,129 +0,0 @@
1
- package cronixui
2
-
3
- // Color represents a color token
4
- type Color struct {
5
- Hex string
6
- R int
7
- G int
8
- B int
9
- }
10
-
11
- // Background colors
12
- var (
13
- BG = Color{Hex: "#0a0a0a", R: 10, G: 10, B: 10}
14
- Surface = Color{Hex: "#111111", R: 17, G: 17, B: 17}
15
- Surface2 = Color{Hex: "#1a1a1a", R: 26, G: 26, B: 26}
16
- Surface3 = Color{Hex: "#222222", R: 34, G: 34, B: 34}
17
- Surface4 = Color{Hex: "#2a2a2a", R: 42, G: 42, B: 42}
18
- )
19
-
20
- // Text colors
21
- var (
22
- Text = Color{Hex: "#f0ede8", R: 240, G: 237, B: 232}
23
- TextMuted = "rgba(240, 237, 232, 0.5)"
24
- TextDim = "rgba(240, 237, 232, 0.25)"
25
- )
26
-
27
- // Accent colors (Crimson)
28
- var (
29
- Accent = Color{Hex: "#6b2323", R: 107, G: 35, B: 35}
30
- AccentHover = Color{Hex: "#7d2a2a", R: 125, G: 42, B: 42}
31
- AccentLight = Color{Hex: "#8a3535", R: 138, G: 53, B: 53}
32
- AccentGlow = "rgba(107, 35, 35, 0.3)"
33
- AccentText = Color{Hex: "#c97a7a", R: 201, G: 122, B: 122}
34
- )
35
-
36
- // Semantic colors
37
- var (
38
- Success = Color{Hex: "#1e5028", R: 30, G: 80, B: 40}
39
- SuccessBorder = "rgba(60, 140, 70, 0.4)"
40
- SuccessText = Color{Hex: "#6bc47a", R: 107, G: 196, B: 122}
41
-
42
- Warning = Color{Hex: "#503c14", R: 80, G: 60, B: 20}
43
- WarningBorder = "rgba(150, 110, 30, 0.4)"
44
- WarningText = Color{Hex: "#c4a43a", R: 196, G: 164, B: 58}
45
-
46
- Error_ = Color{Hex: "#501414", R: 80, G: 20, B: 20}
47
- ErrorBorder = "rgba(180, 60, 60, 0.4)"
48
- ErrorText = Color{Hex: "#c46b6b", R: 196, G: 107, B: 107}
49
-
50
- Info = Color{Hex: "#143550", R: 20, G: 53, B: 80}
51
- InfoBorder = "rgba(60, 140, 200, 0.4)"
52
- InfoText = Color{Hex: "#6ba8c4", R: 107, G: 168, B: 196}
53
- )
54
-
55
- // Border colors
56
- var (
57
- Border = "rgba(255, 255, 255, 0.08)"
58
- BorderHover = "rgba(255, 255, 255, 0.15)"
59
- BorderFocus = "rgba(255, 255, 255, 0.25)"
60
- )
61
-
62
- // Typography tokens
63
- var (
64
- FontFamily = "'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
65
- FontMono = "'JetBrains Mono', 'Fira Code', 'Consolas', monospace"
66
- FontSizeXs = 11
67
- FontSizeSm = 12
68
- FontSizeBase = 13
69
- FontSizeMd = 14
70
- FontSizeLg = 16
71
- FontSizeXl = 20
72
- FontSize2xl = 28
73
- FontSize3xl = 36
74
- )
75
-
76
- // Spacing tokens
77
- var (
78
- Space1 = 4
79
- Space2 = 8
80
- Space3 = 12
81
- Space4 = 16
82
- Space5 = 20
83
- Space6 = 24
84
- Space8 = 32
85
- Space10 = 40
86
- Space12 = 48
87
- )
88
-
89
- // Border radius tokens
90
- var (
91
- RadiusSm = 6
92
- Radius = 10
93
- RadiusLg = 14
94
- RadiusXl = 20
95
- RadiusFull = 9999
96
- )
97
-
98
- // Shadow tokens
99
- var (
100
- ShadowSm = "0 1px 2px rgba(0, 0, 0, 0.3)"
101
- Shadow = "0 4px 12px rgba(0, 0, 0, 0.4)"
102
- ShadowLg = "0 8px 24px rgba(0, 0, 0, 0.5)"
103
- ShadowGlow = "0 0 20px rgba(107, 35, 35, 0.3)"
104
- )
105
-
106
- // Transition tokens
107
- var (
108
- TransitionFast = "0.1s ease"
109
- TransitionDefault = "0.15s ease"
110
- TransitionSlow = "0.25s ease"
111
- )
112
-
113
- // Z-index tokens
114
- var (
115
- ZIndexDropdown = 100
116
- ZIndexSticky = 200
117
- ZIndexFixed = 300
118
- ZIndexModalBackdrop = 400
119
- ZIndexModal = 500
120
- ZIndexPopover = 600
121
- ZIndexTooltip = 700
122
- ZIndexToast = 800
123
- )
124
-
125
- // Layout tokens
126
- var (
127
- ContainerMax = 1200
128
- SidebarWidth = 260
129
- )
@@ -1,11 +0,0 @@
1
- [project]
2
- name = "cronixui"
3
- version = "1.0.2"
4
- description = "CronixUI - A dark-themed UI toolkit with crimson accents and Outfit typography"
5
- license = {text = "GPL-3.0"}
6
- authors = [{name = "CazyUndee"}]
7
- keywords = ["ui", "dark-mode", "design-system", "components"]
8
- requires-python = ">=3.8"
9
-
10
- [project.urls]
11
- Repository = "https://github.com/CazyUndee/CronixUI"
@@ -1,50 +0,0 @@
1
- import { useState } from 'react';
2
-
3
- export default function Accordion({
4
- allowMultiple = false,
5
- defaultOpen = [],
6
- children,
7
- className = ''
8
- }) {
9
- const [openItems, setOpenItems] = useState(new Set(defaultOpen));
10
-
11
- const toggleItem = (index) => {
12
- setOpenItems((prev) => {
13
- const next = new Set(prev);
14
- if (next.has(index)) {
15
- next.delete(index);
16
- } else {
17
- if (!allowMultiple) {
18
- next.clear();
19
- }
20
- next.add(index);
21
- }
22
- return next;
23
- });
24
- };
25
-
26
- const items = Array.isArray(children) ? children : [children];
27
-
28
- return (
29
- <div className={`cn-accordion ${className}`}>
30
- {items.map((child, idx) => (
31
- <div key={idx} className={`cn-accordion-item ${openItems.has(idx) ? 'cn-accordion-open' : ''}`}>
32
- <div className="cn-accordion-header" onClick={() => toggleItem(idx)}>
33
- <span>{child.props.title}</span>
34
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="20" height="20">
35
- <polyline points="6 9 12 15 18 9"></polyline>
36
- </svg>
37
- </div>
38
- <div className="cn-accordion-content">
39
- {child.props.children}
40
- </div>
41
- </div>
42
- ))}
43
- </div>
44
- );
45
- }
46
-
47
- export function AccordionItem({ children }) {
48
- return children;
49
- }
50
- AccordionItem.displayName = 'AccordionItem';
@@ -1,62 +0,0 @@
1
- import { useState } from 'react';
2
-
3
- export default function Alert({
4
- type = 'info',
5
- title,
6
- children,
7
- closable = true,
8
- onClose,
9
- className = ''
10
- }) {
11
- const [visible, setVisible] = useState(true);
12
-
13
- const handleClose = () => {
14
- setVisible(false);
15
- onClose?.();
16
- };
17
-
18
- if (!visible) return null;
19
-
20
- return (
21
- <div className={`cn-alert cn-alert-${type} ${className}`}>
22
- <div className="cn-alert-icon">
23
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
24
- {type === 'success' && <polyline points="20 6 9 17 4 12"></polyline>}
25
- {type === 'error' && (
26
- <>
27
- <circle cx="12" cy="12" r="10"></circle>
28
- <line x1="15" y1="9" x2="9" y2="15"></line>
29
- <line x1="9" y1="9" x2="15" y2="15"></line>
30
- </>
31
- )}
32
- {type === 'warning' && (
33
- <>
34
- <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
35
- <line x1="12" y1="9" x2="12" y2="13"></line>
36
- <line x1="12" y1="17" x2="12.01" y2="17"></line>
37
- </>
38
- )}
39
- {type === 'info' && (
40
- <>
41
- <circle cx="12" cy="12" r="10"></circle>
42
- <line x1="12" y1="16" x2="12" y2="12"></line>
43
- <line x1="12" y1="8" x2="12.01" y2="8"></line>
44
- </>
45
- )}
46
- </svg>
47
- </div>
48
- <div className="cn-alert-content">
49
- {title && <div className="cn-alert-title">{title}</div>}
50
- <div className="cn-alert-message">{children}</div>
51
- </div>
52
- {closable && (
53
- <button className="cn-alert-close" onClick={handleClose}>
54
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
55
- <line x1="18" y1="6" x2="6" y2="18"></line>
56
- <line x1="6" y1="6" x2="18" y2="18"></line>
57
- </svg>
58
- </button>
59
- )}
60
- </div>
61
- );
62
- }
@@ -1,34 +0,0 @@
1
- export default function Avatar({
2
- src,
3
- alt = '',
4
- initials,
5
- size = 'md',
6
- className = ''
7
- }) {
8
- const sizeClass = size !== 'md' ? `cn-avatar-${size}` : '';
9
-
10
- return (
11
- <div className={`cn-avatar ${sizeClass} ${className}`}>
12
- {src ? (
13
- <img src={src} alt={alt} />
14
- ) : initials ? (
15
- initials
16
- ) : null}
17
- </div>
18
- );
19
- }
20
-
21
- export function AvatarGroup({ children, max, className = '' }) {
22
- const items = Array.isArray(children) ? children : [children];
23
- const visible = max ? items.slice(0, max) : items;
24
- const remaining = max ? items.length - max : 0;
25
-
26
- return (
27
- <div className={`cn-avatar-group ${className}`}>
28
- {visible}
29
- {remaining > 0 && (
30
- <div className="cn-avatar">+{remaining}</div>
31
- )}
32
- </div>
33
- );
34
- }
@@ -1,15 +0,0 @@
1
- export default function Badge({
2
- children,
3
- variant = 'default',
4
- size = 'md',
5
- className = ''
6
- }) {
7
- const variantClass = variant !== 'default' ? `cn-badge-${variant}` : '';
8
- const sizeClass = size !== 'md' ? `cn-badge-${size}` : '';
9
-
10
- return (
11
- <span className={`cn-badge ${variantClass} ${sizeClass} ${className}`}>
12
- {children}
13
- </span>
14
- );
15
- }
@@ -1,27 +0,0 @@
1
- export function Breadcrumb({ children, className = '' }) {
2
- const items = Array.isArray(children) ? children : [children];
3
-
4
- return (
5
- <nav className={`cn-breadcrumb ${className}`}>
6
- {items.map((child, idx) => (
7
- <span key={idx}>
8
- {child}
9
- {idx < items.length - 1 && (
10
- <span className="cn-breadcrumb-separator">/</span>
11
- )}
12
- </span>
13
- ))}
14
- </nav>
15
- );
16
- }
17
-
18
- export function BreadcrumbItem({ children, href, active = false, className = '' }) {
19
- if (active) {
20
- return <span className={`cn-breadcrumb-current ${className}`}>{children}</span>;
21
- }
22
- return (
23
- <a href={href} className={`cn-breadcrumb-item ${className}`}>
24
- {children}
25
- </a>
26
- );
27
- }
@@ -1,21 +0,0 @@
1
- export default function Button({
2
- children,
3
- variant = 'default',
4
- size = 'md',
5
- disabled = false,
6
- className = '',
7
- ...props
8
- }) {
9
- const variantClass = variant !== 'default' ? `cn-btn-${variant}` : '';
10
- const sizeClass = size !== 'md' ? `cn-btn-${size}` : '';
11
-
12
- return (
13
- <button
14
- className={`cn-btn ${variantClass} ${sizeClass} ${className}`}
15
- disabled={disabled}
16
- {...props}
17
- >
18
- {children}
19
- </button>
20
- );
21
- }
@@ -1,23 +0,0 @@
1
- export default function Card({
2
- children,
3
- hoverable = false,
4
- className = ''
5
- }) {
6
- return (
7
- <div className={`cn-card ${hoverable ? 'cn-card-hoverable' : ''} ${className}`}>
8
- {children}
9
- </div>
10
- );
11
- }
12
-
13
- Card.Header = function CardHeader({ children, className = '' }) {
14
- return <div className={`cn-card-header ${className}`}>{children}</div>;
15
- };
16
-
17
- Card.Body = function CardBody({ children, className = '' }) {
18
- return <div className={`cn-card-body ${className}`}>{children}</div>;
19
- };
20
-
21
- Card.Footer = function CardFooter({ children, className = '' }) {
22
- return <div className={`cn-card-footer ${className}`}>{children}</div>;
23
- };
@@ -1,27 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Checkbox = forwardRef(function Checkbox({
4
- checked = false,
5
- onChange,
6
- disabled = false,
7
- children,
8
- className = '',
9
- ...props
10
- }, ref) {
11
- return (
12
- <label className={`cn-checkbox ${disabled ? 'disabled' : ''} ${className}`}>
13
- <input
14
- ref={ref}
15
- type="checkbox"
16
- checked={checked}
17
- onChange={(e) => onChange?.(e.target.checked)}
18
- disabled={disabled}
19
- {...props}
20
- />
21
- <span className="cn-checkbox-box"></span>
22
- {children && <span className="cn-checkbox-label">{children}</span>}
23
- </label>
24
- );
25
- });
26
-
27
- export default Checkbox;
@@ -1,93 +0,0 @@
1
- import { useState, useEffect, useRef } from 'react';
2
-
3
- export default function CommandPalette({
4
- items = [],
5
- isOpen = false,
6
- onClose,
7
- onSelect,
8
- placeholder = 'Search commands...',
9
- className = ''
10
- }) {
11
- const [query, setQuery] = useState('');
12
- const [activeIndex, setActiveIndex] = useState(0);
13
- const inputRef = useRef(null);
14
-
15
- const filtered = items.filter(item =>
16
- item.title.toLowerCase().includes(query.toLowerCase()) ||
17
- (item.subtitle && item.subtitle.toLowerCase().includes(query.toLowerCase()))
18
- );
19
-
20
- useEffect(() => {
21
- if (isOpen) {
22
- setQuery('');
23
- setActiveIndex(0);
24
- setTimeout(() => inputRef.current?.focus(), 100);
25
- }
26
- }, [isOpen]);
27
-
28
- useEffect(() => {
29
- const handleKeyDown = (e) => {
30
- if (!isOpen) return;
31
-
32
- if (e.key === 'Escape') {
33
- onClose?.();
34
- } else if (e.key === 'ArrowDown') {
35
- e.preventDefault();
36
- setActiveIndex(i => Math.min(i + 1, filtered.length - 1));
37
- } else if (e.key === 'ArrowUp') {
38
- e.preventDefault();
39
- setActiveIndex(i => Math.max(i - 1, 0));
40
- } else if (e.key === 'Enter' && filtered[activeIndex]) {
41
- handleSelect(filtered[activeIndex]);
42
- }
43
- };
44
-
45
- document.addEventListener('keydown', handleKeyDown);
46
- return () => document.removeEventListener('keydown', handleKeyDown);
47
- }, [isOpen, filtered, activeIndex, onClose]);
48
-
49
- const handleSelect = (item) => {
50
- item.action?.();
51
- onSelect?.(item);
52
- onClose?.();
53
- };
54
-
55
- if (!isOpen) return null;
56
-
57
- return (
58
- <div className={`cn-command-palette cn-command-palette-open ${className}`} onClick={(e) => e.target === e.currentTarget && onClose?.()}>
59
- <div className="cn-command-palette-inner">
60
- <input
61
- ref={inputRef}
62
- type="text"
63
- className="cn-command-palette-input"
64
- placeholder={placeholder}
65
- value={query}
66
- onChange={(e) => {
67
- setQuery(e.target.value);
68
- setActiveIndex(0);
69
- }}
70
- />
71
- <div className="cn-command-palette-results">
72
- {filtered.map((item, idx) => (
73
- <div
74
- key={idx}
75
- className={`cn-command-item ${idx === activeIndex ? 'cn-command-item-active' : ''}`}
76
- onClick={() => handleSelect(item)}
77
- onMouseEnter={() => setActiveIndex(idx)}
78
- >
79
- {item.icon && <div className="cn-command-item-icon">{item.icon}</div>}
80
- <div className="cn-command-item-content">
81
- <div className="cn-command-item-title">{item.title}</div>
82
- {item.subtitle && (
83
- <div className="cn-command-item-subtitle">{item.subtitle}</div>
84
- )}
85
- </div>
86
- {item.kbd && <div className="cn-command-item-kbd">{item.kbd}</div>}
87
- </div>
88
- ))}
89
- </div>
90
- </div>
91
- </div>
92
- );
93
- }