acidui-core 1.0.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 (194) hide show
  1. package/README.md +127 -0
  2. package/eslint.config.js +23 -0
  3. package/git +0 -0
  4. package/index.html +13 -0
  5. package/package.json +38 -0
  6. package/public/vite.svg +1 -0
  7. package/src/App.css +8 -0
  8. package/src/App.tsx +26 -0
  9. package/src/assets/react.svg +1 -0
  10. package/src/cli/main.mjs +209 -0
  11. package/src/components/AcidAccordion.css +52 -0
  12. package/src/components/AcidAccordion.tsx +72 -0
  13. package/src/components/AcidAlert.css +86 -0
  14. package/src/components/AcidAlert.tsx +52 -0
  15. package/src/components/AcidAnimatedNotification.css +103 -0
  16. package/src/components/AcidAnimatedNotification.tsx +62 -0
  17. package/src/components/AcidAspectRatio.css +16 -0
  18. package/src/components/AcidAspectRatio.tsx +21 -0
  19. package/src/components/AcidAuroraText.css +49 -0
  20. package/src/components/AcidAuroraText.tsx +19 -0
  21. package/src/components/AcidAvatar.css +70 -0
  22. package/src/components/AcidAvatar.tsx +32 -0
  23. package/src/components/AcidBadge.css +54 -0
  24. package/src/components/AcidBadge.tsx +27 -0
  25. package/src/components/AcidBentoGrid.css +98 -0
  26. package/src/components/AcidBentoGrid.tsx +68 -0
  27. package/src/components/AcidBorderBeam.css +27 -0
  28. package/src/components/AcidBorderBeam.tsx +37 -0
  29. package/src/components/AcidBreadcrumb.css +36 -0
  30. package/src/components/AcidBreadcrumb.tsx +35 -0
  31. package/src/components/AcidButton.css +97 -0
  32. package/src/components/AcidButton.tsx +29 -0
  33. package/src/components/AcidCalendar.css +136 -0
  34. package/src/components/AcidCalendar.tsx +144 -0
  35. package/src/components/AcidCard.css +42 -0
  36. package/src/components/AcidCard.tsx +26 -0
  37. package/src/components/AcidCarousel.css +166 -0
  38. package/src/components/AcidCarousel.tsx +168 -0
  39. package/src/components/AcidChart.css +132 -0
  40. package/src/components/AcidChart.tsx +198 -0
  41. package/src/components/AcidCheckbox.css +64 -0
  42. package/src/components/AcidCheckbox.tsx +58 -0
  43. package/src/components/AcidCodeBlock.css +51 -0
  44. package/src/components/AcidCodeBlock.tsx +25 -0
  45. package/src/components/AcidCodeDisplay.css +79 -0
  46. package/src/components/AcidCodeDisplay.tsx +42 -0
  47. package/src/components/AcidCollapsible.css +54 -0
  48. package/src/components/AcidCollapsible.tsx +56 -0
  49. package/src/components/AcidCommand.css +207 -0
  50. package/src/components/AcidCommand.tsx +149 -0
  51. package/src/components/AcidConfettiButton.tsx +37 -0
  52. package/src/components/AcidContextMenu.css +84 -0
  53. package/src/components/AcidContextMenu.tsx +111 -0
  54. package/src/components/AcidCountUp.css +54 -0
  55. package/src/components/AcidCountUp.tsx +66 -0
  56. package/src/components/AcidDialog.css +124 -0
  57. package/src/components/AcidDialog.tsx +89 -0
  58. package/src/components/AcidDivider.css +44 -0
  59. package/src/components/AcidDivider.tsx +28 -0
  60. package/src/components/AcidDock.css +74 -0
  61. package/src/components/AcidDock.tsx +65 -0
  62. package/src/components/AcidDragOrderList.css +45 -0
  63. package/src/components/AcidDragOrderList.tsx +58 -0
  64. package/src/components/AcidDrawer.css +64 -0
  65. package/src/components/AcidDrawer.tsx +55 -0
  66. package/src/components/AcidDropdown.css +103 -0
  67. package/src/components/AcidDropdown.tsx +87 -0
  68. package/src/components/AcidDynamicNavbar.css +273 -0
  69. package/src/components/AcidDynamicNavbar.tsx +157 -0
  70. package/src/components/AcidElectroBorder.css +141 -0
  71. package/src/components/AcidElectroBorder.tsx +53 -0
  72. package/src/components/AcidFloatingNavbar.css +152 -0
  73. package/src/components/AcidFloatingNavbar.tsx +111 -0
  74. package/src/components/AcidForm.css +78 -0
  75. package/src/components/AcidForm.tsx +45 -0
  76. package/src/components/AcidGlassFolder.css +111 -0
  77. package/src/components/AcidGlassFolder.tsx +34 -0
  78. package/src/components/AcidGradientButton.css +99 -0
  79. package/src/components/AcidGradientButton.tsx +37 -0
  80. package/src/components/AcidGridBox.css +61 -0
  81. package/src/components/AcidGridBox.tsx +26 -0
  82. package/src/components/AcidIconBox.css +42 -0
  83. package/src/components/AcidIconBox.tsx +18 -0
  84. package/src/components/AcidInput.css +99 -0
  85. package/src/components/AcidInput.tsx +27 -0
  86. package/src/components/AcidInputOtp.css +57 -0
  87. package/src/components/AcidInputOtp.tsx +102 -0
  88. package/src/components/AcidLabel.css +26 -0
  89. package/src/components/AcidLabel.tsx +18 -0
  90. package/src/components/AcidLayout.css +42 -0
  91. package/src/components/AcidLayout.tsx +35 -0
  92. package/src/components/AcidLink.css +26 -0
  93. package/src/components/AcidLink.tsx +19 -0
  94. package/src/components/AcidMagicCard.css +27 -0
  95. package/src/components/AcidMagicCard.tsx +49 -0
  96. package/src/components/AcidMagicLoader.css +47 -0
  97. package/src/components/AcidMagicLoader.tsx +43 -0
  98. package/src/components/AcidMarquee.css +59 -0
  99. package/src/components/AcidMarquee.tsx +28 -0
  100. package/src/components/AcidMeter.css +118 -0
  101. package/src/components/AcidMeter.tsx +37 -0
  102. package/src/components/AcidNavbar.css +142 -0
  103. package/src/components/AcidNavbar.tsx +111 -0
  104. package/src/components/AcidNavigationMenu.css +47 -0
  105. package/src/components/AcidNavigationMenu.tsx +38 -0
  106. package/src/components/AcidPagination.css +57 -0
  107. package/src/components/AcidPagination.tsx +51 -0
  108. package/src/components/AcidProgress.css +57 -0
  109. package/src/components/AcidProgress.tsx +40 -0
  110. package/src/components/AcidRadioGroup.css +98 -0
  111. package/src/components/AcidRadioGroup.tsx +70 -0
  112. package/src/components/AcidResizable.css +34 -0
  113. package/src/components/AcidResizable.tsx +46 -0
  114. package/src/components/AcidRippleButton.css +34 -0
  115. package/src/components/AcidRippleButton.tsx +61 -0
  116. package/src/components/AcidRippleLoader.css +23 -0
  117. package/src/components/AcidRippleLoader.tsx +40 -0
  118. package/src/components/AcidScrollArea.css +28 -0
  119. package/src/components/AcidScrollArea.tsx +21 -0
  120. package/src/components/AcidScrollList.css +107 -0
  121. package/src/components/AcidScrollList.tsx +58 -0
  122. package/src/components/AcidScrollReveal.tsx +29 -0
  123. package/src/components/AcidScrollStack.css +46 -0
  124. package/src/components/AcidScrollStack.tsx +54 -0
  125. package/src/components/AcidSelect.css +144 -0
  126. package/src/components/AcidSelect.tsx +108 -0
  127. package/src/components/AcidSeparator.css +15 -0
  128. package/src/components/AcidSeparator.tsx +24 -0
  129. package/src/components/AcidSheet.css +99 -0
  130. package/src/components/AcidSheet.tsx +68 -0
  131. package/src/components/AcidShineButton.css +36 -0
  132. package/src/components/AcidShineButton.tsx +24 -0
  133. package/src/components/AcidShinyText.css +22 -0
  134. package/src/components/AcidShinyText.tsx +20 -0
  135. package/src/components/AcidSidebar.css +152 -0
  136. package/src/components/AcidSidebar.tsx +44 -0
  137. package/src/components/AcidSkeleton.css +61 -0
  138. package/src/components/AcidSkeleton.tsx +29 -0
  139. package/src/components/AcidSlider.css +89 -0
  140. package/src/components/AcidSlider.tsx +87 -0
  141. package/src/components/AcidSolidCard.css +55 -0
  142. package/src/components/AcidSolidCard.tsx +35 -0
  143. package/src/components/AcidStackList.css +59 -0
  144. package/src/components/AcidStackList.tsx +38 -0
  145. package/src/components/AcidStepList.css +35 -0
  146. package/src/components/AcidStepList.tsx +31 -0
  147. package/src/components/AcidSwitch.css +48 -0
  148. package/src/components/AcidSwitch.tsx +48 -0
  149. package/src/components/AcidTable.css +60 -0
  150. package/src/components/AcidTable.tsx +44 -0
  151. package/src/components/AcidTabs.css +102 -0
  152. package/src/components/AcidTabs.tsx +47 -0
  153. package/src/components/AcidTerminalCard.css +63 -0
  154. package/src/components/AcidTerminalCard.tsx +35 -0
  155. package/src/components/AcidTextMarquee.css +30 -0
  156. package/src/components/AcidTextMarquee.tsx +37 -0
  157. package/src/components/AcidTextarea.tsx +32 -0
  158. package/src/components/AcidTimeline.css +129 -0
  159. package/src/components/AcidTimeline.tsx +59 -0
  160. package/src/components/AcidToast.css +77 -0
  161. package/src/components/AcidToast.tsx +72 -0
  162. package/src/components/AcidToggle.css +73 -0
  163. package/src/components/AcidToggle.tsx +56 -0
  164. package/src/components/AcidToggleGroup.css +61 -0
  165. package/src/components/AcidToggleGroup.tsx +76 -0
  166. package/src/components/AcidTooltip.css +81 -0
  167. package/src/components/AcidTooltip.tsx +44 -0
  168. package/src/components/AcidTopLoader.css +24 -0
  169. package/src/components/AcidTopLoader.tsx +61 -0
  170. package/src/components/AcidTopStickyBar.css +99 -0
  171. package/src/components/AcidTopStickyBar.tsx +51 -0
  172. package/src/components/AcidTrialButton.css +55 -0
  173. package/src/components/AcidTrialButton.tsx +26 -0
  174. package/src/components/AcidTrustedUsers.css +59 -0
  175. package/src/components/AcidTrustedUsers.tsx +46 -0
  176. package/src/components/AcidTypewriterInput.css +37 -0
  177. package/src/components/AcidTypewriterInput.tsx +31 -0
  178. package/src/components/AcidTypingText.tsx +32 -0
  179. package/src/components/AcidVideoText.css +35 -0
  180. package/src/components/AcidVideoText.tsx +25 -0
  181. package/src/data/sidebar.ts +135 -0
  182. package/src/data/snippets.ts +13 -0
  183. package/src/index.css +136 -0
  184. package/src/main.tsx +13 -0
  185. package/src/pages/Docs.css +604 -0
  186. package/src/pages/Docs.tsx +2347 -0
  187. package/src/pages/Landing.css +342 -0
  188. package/src/pages/Landing.tsx +216 -0
  189. package/src/pages/Library.css +426 -0
  190. package/src/pages/Library.tsx +254 -0
  191. package/tsconfig.app.json +28 -0
  192. package/tsconfig.json +7 -0
  193. package/tsconfig.node.json +26 -0
  194. package/vite.config.ts +7 -0
@@ -0,0 +1,166 @@
1
+ .ac-carousel-container {
2
+ display: flex;
3
+ gap: 2rem;
4
+ width: 100%;
5
+ color: var(--ac-text);
6
+ }
7
+
8
+ .ac-carousel-container.ac-vertical {
9
+ flex-direction: row;
10
+ }
11
+
12
+ .ac-carousel-container.ac-horizontal {
13
+ flex-direction: column;
14
+ }
15
+
16
+ .ac-carousel-controls {
17
+ display: flex;
18
+ gap: 1rem;
19
+ flex: 1;
20
+ }
21
+
22
+ .ac-carousel-container.ac-vertical .ac-carousel-controls {
23
+ flex-direction: column;
24
+ min-width: 300px;
25
+ max-width: 400px;
26
+ }
27
+
28
+ .ac-carousel-container.ac-horizontal .ac-carousel-controls {
29
+ flex-direction: row;
30
+ }
31
+
32
+ .ac-carousel-tab {
33
+ display: flex;
34
+ flex-direction: column;
35
+ text-align: left;
36
+ background: transparent;
37
+ border: none;
38
+ padding: 1.5rem 0;
39
+ cursor: pointer;
40
+ border-bottom: 1px solid var(--ac-border);
41
+ position: relative;
42
+ opacity: 0.5;
43
+ transition: all 0.3s ease;
44
+ }
45
+
46
+ .ac-carousel-tab.active {
47
+ opacity: 1;
48
+ }
49
+
50
+ .ac-carousel-tab:hover {
51
+ opacity: 0.8;
52
+ }
53
+
54
+ .ac-tab-header {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 1rem;
58
+ }
59
+
60
+ .ac-asterisk {
61
+ color: var(--ac-text-muted);
62
+ }
63
+
64
+ .ac-asterisk.active {
65
+ color: var(--ac-brand);
66
+ }
67
+
68
+ .ac-tab-title-group {
69
+ display: flex;
70
+ flex-direction: column;
71
+ }
72
+
73
+ .ac-tab-label {
74
+ font-size: 0.65rem;
75
+ font-family: 'JetBrains Mono', monospace;
76
+ letter-spacing: 0.1em;
77
+ color: var(--ac-brand);
78
+ margin-bottom: 0.25rem;
79
+ }
80
+
81
+ .ac-tab-title {
82
+ font-size: 1.25rem;
83
+ font-weight: 700;
84
+ margin: 0;
85
+ letter-spacing: -0.02em;
86
+ }
87
+
88
+ .ac-tab-content {
89
+ overflow: hidden;
90
+ padding-left: 2.5rem;
91
+ /* align with text, bypassing asterisk */
92
+ }
93
+
94
+ .ac-tab-content p {
95
+ font-size: 0.9rem;
96
+ color: var(--ac-text-muted);
97
+ margin: 1rem 0 0 0;
98
+ line-height: 1.6;
99
+ }
100
+
101
+ .ac-tab-progress-bg {
102
+ position: absolute;
103
+ bottom: -1px;
104
+ /* Overlap border */
105
+ left: 0;
106
+ width: 100%;
107
+ height: 2px;
108
+ background: transparent;
109
+ overflow: hidden;
110
+ }
111
+
112
+ .ac-tab-progress-fill {
113
+ height: 100%;
114
+ background: var(--ac-brand);
115
+ }
116
+
117
+ /* Display Area */
118
+ .ac-carousel-display {
119
+ flex: 2;
120
+ position: relative;
121
+ min-height: 400px;
122
+ border-radius: 12px;
123
+ background: var(--ac-surface);
124
+ border: 1px solid var(--ac-border);
125
+ overflow: hidden;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ }
130
+
131
+ .ac-carousel-container.ac-horizontal .ac-carousel-display {
132
+ width: 100%;
133
+ min-height: 500px;
134
+ }
135
+
136
+ .ac-carousel-visual {
137
+ width: 100%;
138
+ height: 100%;
139
+ position: absolute;
140
+ top: 0;
141
+ left: 0;
142
+ }
143
+
144
+ .ac-carousel-placeholder {
145
+ width: 100%;
146
+ height: 100%;
147
+ display: flex;
148
+ flex-direction: column;
149
+ align-items: center;
150
+ justify-content: center;
151
+ gap: 1rem;
152
+ font-family: 'JetBrains Mono', monospace;
153
+ font-size: 0.75rem;
154
+ color: var(--ac-text-muted);
155
+ letter-spacing: 0.1em;
156
+ }
157
+
158
+ @media (max-width: 768px) {
159
+ .ac-carousel-container.ac-vertical {
160
+ flex-direction: column;
161
+ }
162
+
163
+ .ac-carousel-controls {
164
+ max-width: 100%;
165
+ }
166
+ }
@@ -0,0 +1,168 @@
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
2
+ import { motion, AnimatePresence } from 'framer-motion';
3
+ import clsx from 'clsx';
4
+ import './AcidCarousel.css';
5
+
6
+ export interface AcidCarouselItem {
7
+ id: string;
8
+ title: string;
9
+ label?: string;
10
+ description: string;
11
+ content?: React.ReactNode;
12
+ }
13
+
14
+ export interface AcidCarouselProps {
15
+ items: AcidCarouselItem[];
16
+ direction?: 'horizontal' | 'vertical';
17
+ autoPlay?: boolean;
18
+ interval?: number;
19
+ className?: string;
20
+ }
21
+
22
+ export const AcidCarousel = ({
23
+ items,
24
+ direction = 'horizontal',
25
+ autoPlay = false,
26
+ interval = 5000,
27
+ className
28
+ }: AcidCarouselProps) => {
29
+ const [activeIndex, setActiveIndex] = useState(0);
30
+ const [progress, setProgress] = useState(0);
31
+ const progressRef = useRef(0);
32
+ const lastTimeRef = useRef(0);
33
+ const requestRef = useRef<number | undefined>(undefined);
34
+
35
+ const nextSlide = useCallback(() => {
36
+ setActiveIndex((prev) => (prev + 1) % items.length);
37
+ setProgress(0);
38
+ progressRef.current = 0;
39
+ }, [items.length]);
40
+
41
+ const selectSlide = (index: number) => {
42
+ setActiveIndex(index);
43
+ setProgress(0);
44
+ progressRef.current = 0;
45
+ };
46
+
47
+ const animate = useCallback((time: number) => {
48
+ if (!autoPlay) return;
49
+
50
+ if (lastTimeRef.current !== undefined) {
51
+ const deltaTime = time - lastTimeRef.current;
52
+ progressRef.current += (deltaTime / interval) * 100;
53
+
54
+ if (progressRef.current >= 100) {
55
+ nextSlide();
56
+ } else {
57
+ setProgress(progressRef.current);
58
+ }
59
+ }
60
+
61
+ lastTimeRef.current = time;
62
+ requestRef.current = requestAnimationFrame(animate);
63
+ }, [autoPlay, interval, nextSlide]);
64
+
65
+ useEffect(() => {
66
+ if (autoPlay) {
67
+ requestRef.current = requestAnimationFrame(animate);
68
+ return () => {
69
+ if (requestRef.current) cancelAnimationFrame(requestRef.current);
70
+ };
71
+ } else {
72
+ setProgress(0);
73
+ progressRef.current = 0;
74
+ }
75
+ }, [autoPlay, animate]);
76
+
77
+ // Asterisk icon to match the aesthetic
78
+ const Asterisk = ({ active }: { active: boolean }) => (
79
+ <motion.div
80
+ className={clsx('ac-asterisk', active && 'active')}
81
+ animate={{ rotate: active ? 180 : 0 }}
82
+ transition={{ duration: 0.8, ease: "easeInOut" }}
83
+ >
84
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
85
+ <path d="M12 2v20M17 5L7 19M22 12H2M19 17L5 7" />
86
+ </svg>
87
+ </motion.div>
88
+ );
89
+
90
+ return (
91
+ <div className={clsx('ac-carousel-container', `ac-${direction}`, className)}>
92
+ <div className="ac-carousel-controls">
93
+ {items.map((item, idx) => {
94
+ const isActive = idx === activeIndex;
95
+ return (
96
+ <button
97
+ key={item.id}
98
+ className={clsx('ac-carousel-tab', isActive && 'active')}
99
+ onClick={() => selectSlide(idx)}
100
+ >
101
+ <div className="ac-tab-header">
102
+ <div className="ac-tab-indicator">
103
+ <Asterisk active={isActive} />
104
+ </div>
105
+ <div className="ac-tab-title-group">
106
+ {item.label && <span className="ac-tab-label">{item.label}</span>}
107
+ <h3 className="ac-tab-title">{item.title}</h3>
108
+ </div>
109
+ </div>
110
+
111
+ <AnimatePresence>
112
+ {isActive && (
113
+ <motion.div
114
+ initial={{ height: 0, opacity: 0 }}
115
+ animate={{ height: 'auto', opacity: 1 }}
116
+ exit={{ height: 0, opacity: 0 }}
117
+ className="ac-tab-content"
118
+ >
119
+ <p>{item.description}</p>
120
+ </motion.div>
121
+ )}
122
+ </AnimatePresence>
123
+
124
+ {/* Progress Bar for Autoplay */}
125
+ {autoPlay && (
126
+ <div className="ac-tab-progress-bg">
127
+ <motion.div
128
+ className="ac-tab-progress-fill"
129
+ initial={{ width: '0%' }}
130
+ animate={{ width: isActive ? `${progress}%` : (idx < activeIndex ? '100%' : '0%') }}
131
+ transition={{ duration: 0 }}
132
+ />
133
+ </div>
134
+ )}
135
+ </button>
136
+ );
137
+ })}
138
+ </div>
139
+
140
+ <div className="ac-carousel-display">
141
+ <AnimatePresence mode="popLayout">
142
+ <motion.div
143
+ key={activeIndex}
144
+ initial={{ opacity: 0, scale: 0.96, filter: 'blur(10px)' }}
145
+ animate={{ opacity: 1, scale: 1, filter: 'blur(0px)' }}
146
+ exit={{ opacity: 0, scale: 1.04, filter: 'blur(10px)' }}
147
+ transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}
148
+ className="ac-carousel-visual"
149
+ >
150
+ {items[activeIndex].content || (
151
+ <div className="ac-carousel-placeholder">
152
+ <motion.div
153
+ animate={{ rotate: 360 }}
154
+ transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
155
+ >
156
+ <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.2 }}>
157
+ <path d="M12 2v20M17 5L7 19M22 12H2M19 17L5 7" />
158
+ </svg>
159
+ </motion.div>
160
+ <span>{items[activeIndex].title} VISUAL_MODULE</span>
161
+ </div>
162
+ )}
163
+ </motion.div>
164
+ </AnimatePresence>
165
+ </div>
166
+ </div>
167
+ );
168
+ };
@@ -0,0 +1,132 @@
1
+ .ac-chart {
2
+ width: 100%;
3
+ display: flex;
4
+ flex-direction: column;
5
+ background: rgba(255, 255, 255, 0.02);
6
+ border: 1px solid var(--ac-border-muted);
7
+ border-radius: 8px;
8
+ padding: 1.5rem;
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ .ac-chart-header {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 8px;
16
+ margin-bottom: 1.5rem;
17
+ }
18
+
19
+ .ac-chart-dot {
20
+ width: 6px;
21
+ height: 6px;
22
+ background: var(--ac-brand);
23
+ border-radius: 50%;
24
+ box-shadow: 0 0 8px var(--ac-brand);
25
+ }
26
+
27
+ .ac-chart-title {
28
+ font-size: 0.75rem;
29
+ font-weight: 700;
30
+ letter-spacing: 0.1em;
31
+ color: var(--ac-text-muted);
32
+ }
33
+
34
+ .ac-chart-container {
35
+ flex: 1;
36
+ min-height: 0;
37
+ position: relative;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ }
42
+
43
+ .ac-chart-svg {
44
+ width: 100%;
45
+ height: 100%;
46
+ overflow: visible;
47
+ }
48
+
49
+ .ac-chart-grid line {
50
+ stroke: var(--ac-border-muted);
51
+ stroke-width: 1;
52
+ stroke-dasharray: 4 4;
53
+ }
54
+
55
+ .ac-chart-path-line {
56
+ fill: none;
57
+ stroke: var(--ac-brand);
58
+ stroke-width: 2;
59
+ stroke-linecap: round;
60
+ stroke-linejoin: round;
61
+ }
62
+
63
+ .ac-chart-point {
64
+ fill: var(--ac-bg);
65
+ stroke: var(--ac-brand);
66
+ stroke-width: 2;
67
+ }
68
+
69
+ .ac-chart-bar {
70
+ fill: var(--ac-brand);
71
+ opacity: 0.8;
72
+ transition: opacity 0.2s;
73
+ }
74
+
75
+ .ac-chart-bar:hover {
76
+ opacity: 1;
77
+ }
78
+
79
+ .ac-chart-path-area-fill {
80
+ fill: var(--ac-brand);
81
+ opacity: 0.1;
82
+ }
83
+
84
+ .ac-chart-path-area-line {
85
+ fill: none;
86
+ stroke: var(--ac-brand);
87
+ stroke-width: 2;
88
+ }
89
+
90
+ .ac-chart-pie-slice {
91
+ stroke: var(--ac-bg);
92
+ stroke-width: 2;
93
+ fill: var(--ac-brand);
94
+ opacity: calc(1 - (var(--slice-index) * 0.15));
95
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
96
+ transform-origin: center;
97
+ }
98
+
99
+ .ac-chart-pie-slice:hover {
100
+ transform: scale(1.05);
101
+ }
102
+
103
+ .ac-chart-pie-inner {
104
+ fill: var(--ac-bg);
105
+ }
106
+
107
+ .ac-chart-radar-grid {
108
+ fill: none;
109
+ stroke: var(--ac-border-muted);
110
+ stroke-width: 1;
111
+ }
112
+
113
+ .ac-chart-path-radar {
114
+ fill: var(--ac-brand);
115
+ fill-opacity: 0.2;
116
+ stroke: var(--ac-brand);
117
+ stroke-width: 2;
118
+ }
119
+
120
+ .ac-chart-labels {
121
+ display: flex;
122
+ justify-content: space-between;
123
+ margin-top: 1rem;
124
+ padding: 0 40px;
125
+ }
126
+
127
+ .ac-chart-label-item {
128
+ font-family: var(--font-mono);
129
+ font-size: 0.65rem;
130
+ color: var(--ac-text-muted);
131
+ text-transform: uppercase;
132
+ }
@@ -0,0 +1,198 @@
1
+ import React, { useMemo } from 'react';
2
+ import clsx from 'clsx';
3
+ import './AcidChart.css';
4
+
5
+ export interface ChartDataPoint {
6
+ label: string;
7
+ value: number;
8
+ color?: string;
9
+ }
10
+
11
+ export interface AcidChartProps {
12
+ type: 'line' | 'bar' | 'area' | 'pie' | 'radar';
13
+ data: ChartDataPoint[];
14
+ title?: string;
15
+ height?: number | string;
16
+ className?: string;
17
+ showGrid?: boolean;
18
+ showLabels?: boolean;
19
+ }
20
+
21
+ export const AcidChart = ({
22
+ type,
23
+ data,
24
+ title,
25
+ height = 300,
26
+ className,
27
+ showGrid = true,
28
+ showLabels = true
29
+ }: AcidChartProps) => {
30
+ const maxValue = useMemo(() => Math.max(...data.map(d => d.value), 1), [data]);
31
+
32
+ // Line / Bar / Area helpers
33
+ const padding = 40;
34
+ const viewWidth = 500;
35
+ const viewHeight = 300;
36
+ const chartWidth = viewWidth - padding * 2;
37
+ const chartHeight = viewHeight - padding * 2;
38
+
39
+ const points = useMemo(() => {
40
+ return data.map((d, i) => ({
41
+ x: padding + (i * (chartWidth / (data.length - 1 || 1))),
42
+ y: viewHeight - padding - (d.value / maxValue * chartHeight)
43
+ }));
44
+ }, [data, maxValue, chartWidth, chartHeight]);
45
+
46
+ const renderChart = () => {
47
+ switch (type) {
48
+ case 'line': {
49
+ const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
50
+ return (
51
+ <svg viewBox={`0 0 ${viewWidth} ${viewHeight}`} className="ac-chart-svg">
52
+ {showGrid && renderGrid()}
53
+ <path d={linePath} className="ac-chart-path-line" />
54
+ {points.map((p, i) => (
55
+ <circle key={i} cx={p.x} cy={p.y} r="4" className="ac-chart-point" />
56
+ ))}
57
+ </svg>
58
+ );
59
+ }
60
+ case 'bar': {
61
+ const barWidth = (chartWidth / data.length) * 0.8;
62
+ return (
63
+ <svg viewBox={`0 0 ${viewWidth} ${viewHeight}`} className="ac-chart-svg">
64
+ {showGrid && renderGrid()}
65
+ {data.map((d, i) => {
66
+ const x = padding + (i * (chartWidth / data.length)) + (chartWidth / data.length - barWidth) / 2;
67
+ const h = (d.value / maxValue) * chartHeight;
68
+ const y = viewHeight - padding - h;
69
+ return (
70
+ <rect
71
+ key={i}
72
+ x={x}
73
+ y={y}
74
+ width={barWidth}
75
+ height={h}
76
+ className="ac-chart-bar"
77
+ />
78
+ );
79
+ })}
80
+ </svg>
81
+ );
82
+ }
83
+ case 'area': {
84
+ const areaLine = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
85
+ const fillPath = `${areaLine} L ${points[points.length - 1].x} ${viewHeight - padding} L ${points[0].x} ${viewHeight - padding} Z`;
86
+ return (
87
+ <svg viewBox={`0 0 ${viewWidth} ${viewHeight}`} className="ac-chart-svg">
88
+ {showGrid && renderGrid()}
89
+ <path d={fillPath} className="ac-chart-path-area-fill" />
90
+ <path d={areaLine} className="ac-chart-path-area-line" />
91
+ </svg>
92
+ );
93
+ }
94
+ case 'pie': {
95
+ let currentAngle = 0;
96
+ const total = data.reduce((acc, d) => acc + d.value, 0);
97
+ const radius = 100;
98
+ const cx = viewWidth / 2;
99
+ const cy = viewHeight / 2;
100
+
101
+ return (
102
+ <svg viewBox={`0 0 ${viewWidth} ${viewHeight}`} className="ac-chart-svg">
103
+ {data.map((d, i) => {
104
+ const sliceAngle = (d.value / total) * 360;
105
+ const x1 = cx + radius * Math.cos((currentAngle - 90) * Math.PI / 180);
106
+ const y1 = cy + radius * Math.sin((currentAngle - 90) * Math.PI / 180);
107
+ currentAngle += sliceAngle;
108
+ const x2 = cx + radius * Math.cos((currentAngle - 90) * Math.PI / 180);
109
+ const y2 = cy + radius * Math.sin((currentAngle - 90) * Math.PI / 180);
110
+
111
+ const largeArc = sliceAngle > 180 ? 1 : 0;
112
+ const pathData = `M ${cx} ${cy} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
113
+
114
+ return (
115
+ <path
116
+ key={i}
117
+ d={pathData}
118
+ className="ac-chart-pie-slice"
119
+ style={{ '--slice-index': i } as React.CSSProperties}
120
+ />
121
+ );
122
+ })}
123
+ <circle cx={cx} cy={cy} r={radius * 0.6} className="ac-chart-pie-inner" />
124
+ </svg>
125
+ );
126
+ }
127
+ case 'radar': {
128
+ const rRadius = 100;
129
+ const rCx = viewWidth / 2;
130
+ const rCy = viewHeight / 2;
131
+ const angleStep = (Math.PI * 2) / data.length;
132
+
133
+ const radarPoints = data.map((d, i) => {
134
+ const r = (d.value / maxValue) * rRadius;
135
+ return {
136
+ x: rCx + r * Math.cos(i * angleStep - Math.PI / 2),
137
+ y: rCy + r * Math.sin(i * angleStep - Math.PI / 2)
138
+ };
139
+ });
140
+
141
+ const radarPath = radarPoints.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ') + ' Z';
142
+
143
+ return (
144
+ <svg viewBox={`0 0 ${viewWidth} ${viewHeight}`} className="ac-chart-svg">
145
+ {/* Radar Grids */}
146
+ {[0.2, 0.4, 0.6, 0.8, 1].map(scale => (
147
+ <path
148
+ key={scale}
149
+ d={data.map((_, i) => {
150
+ const r = scale * rRadius;
151
+ const x = rCx + r * Math.cos(i * angleStep - Math.PI / 2);
152
+ const y = rCy + r * Math.sin(i * angleStep - Math.PI / 2);
153
+ return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
154
+ }).join(' ') + ' Z'}
155
+ className="ac-chart-radar-grid"
156
+ />
157
+ ))}
158
+ <path d={radarPath} className="ac-chart-path-radar" />
159
+ </svg>
160
+ );
161
+ }
162
+ default:
163
+ return null;
164
+ }
165
+ };
166
+
167
+ const renderGrid = () => (
168
+ <g className="ac-chart-grid">
169
+ {[0, 0.25, 0.5, 0.75, 1].map(v => {
170
+ const y = padding + v * chartHeight;
171
+ return <line key={v} x1={padding} y1={y} x2={viewWidth - padding} y2={y} />;
172
+ })}
173
+ </g>
174
+ );
175
+
176
+ return (
177
+ <div className={clsx('ac-chart', className)} style={{ height }}>
178
+ {title && (
179
+ <div className="ac-chart-header">
180
+ <span className="ac-chart-dot" />
181
+ <span className="ac-chart-title">{title}</span>
182
+ </div>
183
+ )}
184
+ <div className="ac-chart-container">
185
+ {renderChart()}
186
+ </div>
187
+ {showLabels && type !== 'pie' && type !== 'radar' && (
188
+ <div className="ac-chart-labels">
189
+ {data.map((d, i) => (
190
+ <div key={i} className="ac-chart-label-item">
191
+ {d.label}
192
+ </div>
193
+ ))}
194
+ </div>
195
+ )}
196
+ </div>
197
+ );
198
+ };