@caffeinebounce/ui 0.62.2

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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/FinancialStatementTable-BNUrdTU4.d.cts +249 -0
  4. package/dist/FinancialStatementTable-BNUrdTU4.d.ts +249 -0
  5. package/dist/NewsletterSignup-BPreFi5W.d.cts +37 -0
  6. package/dist/NewsletterSignup-BPreFi5W.d.ts +37 -0
  7. package/dist/TestimonialsSection-DtPu2OeR.d.ts +736 -0
  8. package/dist/TestimonialsSection-z-yotRfv.d.cts +736 -0
  9. package/dist/UnifiedTableControls-CG299y9h.d.ts +1233 -0
  10. package/dist/UnifiedTableControls-CIjRpNhy.d.cts +1233 -0
  11. package/dist/blog.d.cts +99 -0
  12. package/dist/blog.d.ts +99 -0
  13. package/dist/blog.js +292 -0
  14. package/dist/blog.mjs +279 -0
  15. package/dist/button-BHnoRUkF.d.cts +34 -0
  16. package/dist/button-BHnoRUkF.d.ts +34 -0
  17. package/dist/charts.d.cts +80 -0
  18. package/dist/charts.d.ts +80 -0
  19. package/dist/charts.js +19 -0
  20. package/dist/charts.mjs +2 -0
  21. package/dist/chunk-33JR5SYE.js +44 -0
  22. package/dist/chunk-3NDB4YPC.js +247 -0
  23. package/dist/chunk-5RW4PYZ6.js +1504 -0
  24. package/dist/chunk-5THF4YP6.mjs +155 -0
  25. package/dist/chunk-6BUBNZPG.mjs +164 -0
  26. package/dist/chunk-6DVWMJ3H.mjs +7029 -0
  27. package/dist/chunk-6TGV2DNP.js +120 -0
  28. package/dist/chunk-72JGQ7IJ.mjs +1498 -0
  29. package/dist/chunk-7DHKQODW.mjs +2932 -0
  30. package/dist/chunk-7IKHZKAC.js +160 -0
  31. package/dist/chunk-ADIDI7AJ.js +11 -0
  32. package/dist/chunk-BFWX5GJZ.mjs +940 -0
  33. package/dist/chunk-BMFQG6RA.mjs +5537 -0
  34. package/dist/chunk-C4UT5V3P.js +65 -0
  35. package/dist/chunk-CC4KUIKC.js +2004 -0
  36. package/dist/chunk-D3QXPL47.mjs +1814 -0
  37. package/dist/chunk-DQWHYBV2.js +36 -0
  38. package/dist/chunk-E42B4GSB.js +993 -0
  39. package/dist/chunk-ESZ7CBA2.js +1007 -0
  40. package/dist/chunk-EYJJQVV4.js +111 -0
  41. package/dist/chunk-FRRS2YZH.mjs +129 -0
  42. package/dist/chunk-G5TQWWQA.mjs +37 -0
  43. package/dist/chunk-GAIQJCAZ.js +5612 -0
  44. package/dist/chunk-GMBGWOCR.mjs +48 -0
  45. package/dist/chunk-GUSTCU2W.mjs +105 -0
  46. package/dist/chunk-HBLKVQIQ.mjs +23 -0
  47. package/dist/chunk-HMAMMC72.js +26 -0
  48. package/dist/chunk-IMKLN273.mjs +9 -0
  49. package/dist/chunk-J6OLBSZR.js +250 -0
  50. package/dist/chunk-JAE45W2T.js +28 -0
  51. package/dist/chunk-JORVSG52.js +606 -0
  52. package/dist/chunk-KB7UXIQZ.mjs +984 -0
  53. package/dist/chunk-KGGQ5NZV.js +186 -0
  54. package/dist/chunk-KHCC5UKW.mjs +22 -0
  55. package/dist/chunk-KRRIRS6A.mjs +1945 -0
  56. package/dist/chunk-LQCVRWVF.js +48 -0
  57. package/dist/chunk-MHZXUOGN.mjs +168 -0
  58. package/dist/chunk-MPZFPU4X.js +349 -0
  59. package/dist/chunk-MVYRNJA6.js +74 -0
  60. package/dist/chunk-N6AFNFZR.mjs +565 -0
  61. package/dist/chunk-OFQLWSUR.mjs +214 -0
  62. package/dist/chunk-OLAAXLXY.mjs +219 -0
  63. package/dist/chunk-OZZWDIOY.js +1859 -0
  64. package/dist/chunk-PZRI43EZ.js +111 -0
  65. package/dist/chunk-Q256HRYD.js +176 -0
  66. package/dist/chunk-Q52ZEL62.mjs +223 -0
  67. package/dist/chunk-R26Y7LGJ.js +142 -0
  68. package/dist/chunk-RBUYW6QQ.js +39 -0
  69. package/dist/chunk-RVEFPVZF.mjs +43 -0
  70. package/dist/chunk-SORWLKOK.js +96 -0
  71. package/dist/chunk-STEP6C4C.mjs +33 -0
  72. package/dist/chunk-T5R6HUDG.mjs +22 -0
  73. package/dist/chunk-T6ZBA6VJ.js +7109 -0
  74. package/dist/chunk-UM7WMXIU.js +2995 -0
  75. package/dist/chunk-VBD4Q5LL.mjs +117 -0
  76. package/dist/chunk-WOITB4JL.js +195 -0
  77. package/dist/chunk-YKZEKJMZ.mjs +71 -0
  78. package/dist/chunk-YL7RZRHM.mjs +103 -0
  79. package/dist/chunk-YSLD2HLP.mjs +346 -0
  80. package/dist/chunk-ZFLZA7UP.mjs +140 -0
  81. package/dist/chunk-ZKUIUE7W.mjs +26 -0
  82. package/dist/chunk-ZOA7B32D.js +248 -0
  83. package/dist/data-table.d.cts +46 -0
  84. package/dist/data-table.d.ts +46 -0
  85. package/dist/data-table.js +270 -0
  86. package/dist/data-table.mjs +13 -0
  87. package/dist/editor.d.cts +89 -0
  88. package/dist/editor.d.ts +89 -0
  89. package/dist/editor.js +10 -0
  90. package/dist/editor.mjs +1 -0
  91. package/dist/forms.d.cts +142 -0
  92. package/dist/forms.d.ts +142 -0
  93. package/dist/forms.js +24 -0
  94. package/dist/forms.mjs +11 -0
  95. package/dist/hooks-8ORd7T1A.d.cts +751 -0
  96. package/dist/hooks-B2jU1GVT.d.ts +751 -0
  97. package/dist/hooks.d.cts +6 -0
  98. package/dist/hooks.d.ts +6 -0
  99. package/dist/hooks.js +99 -0
  100. package/dist/hooks.mjs +10 -0
  101. package/dist/index.d.cts +3141 -0
  102. package/dist/index.d.ts +3141 -0
  103. package/dist/index.js +7332 -0
  104. package/dist/index.mjs +5876 -0
  105. package/dist/layouts-DPfDDF53.d.cts +1001 -0
  106. package/dist/layouts-DPfDDF53.d.ts +1001 -0
  107. package/dist/layouts.d.cts +4 -0
  108. package/dist/layouts.d.ts +4 -0
  109. package/dist/layouts.js +100 -0
  110. package/dist/layouts.mjs +11 -0
  111. package/dist/marketing-3d.d.cts +51 -0
  112. package/dist/marketing-3d.d.ts +51 -0
  113. package/dist/marketing-3d.js +553 -0
  114. package/dist/marketing-3d.mjs +526 -0
  115. package/dist/marketing.d.cts +583 -0
  116. package/dist/marketing.d.ts +583 -0
  117. package/dist/marketing.js +299 -0
  118. package/dist/marketing.mjs +10 -0
  119. package/dist/media.d.cts +29 -0
  120. package/dist/media.d.ts +29 -0
  121. package/dist/media.js +189 -0
  122. package/dist/media.mjs +182 -0
  123. package/dist/navigation.d.cts +591 -0
  124. package/dist/navigation.d.ts +591 -0
  125. package/dist/navigation.js +108 -0
  126. package/dist/navigation.mjs +15 -0
  127. package/dist/portal.d.cts +58 -0
  128. package/dist/portal.d.ts +58 -0
  129. package/dist/portal.js +403 -0
  130. package/dist/portal.mjs +395 -0
  131. package/dist/primitives.d.cts +508 -0
  132. package/dist/primitives.d.ts +508 -0
  133. package/dist/primitives.js +295 -0
  134. package/dist/primitives.mjs +14 -0
  135. package/dist/settings.d.cts +216 -0
  136. package/dist/settings.d.ts +216 -0
  137. package/dist/settings.js +34 -0
  138. package/dist/settings.mjs +9 -0
  139. package/dist/shared-Dqn36QHZ.d.cts +4 -0
  140. package/dist/shared-Dqn36QHZ.d.ts +4 -0
  141. package/dist/styles.css +1213 -0
  142. package/package.json +189 -0
  143. package/styles.css +1 -0
@@ -0,0 +1,111 @@
1
+ 'use strict';
2
+
3
+ var chunkADIDI7AJ_js = require('./chunk-ADIDI7AJ.js');
4
+ var classVarianceAuthority = require('class-variance-authority');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ var alertVariants = classVarianceAuthority.cva(
8
+ "relative w-full rounded-box border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-card text-card-foreground",
13
+ destructive: "border-destructive text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90"
14
+ }
15
+ },
16
+ defaultVariants: {
17
+ variant: "default"
18
+ }
19
+ }
20
+ );
21
+ function Alert({
22
+ className,
23
+ variant,
24
+ ...props
25
+ }) {
26
+ return /* @__PURE__ */ jsxRuntime.jsx(
27
+ "div",
28
+ {
29
+ "data-slot": "alert",
30
+ role: "alert",
31
+ className: chunkADIDI7AJ_js.cn(alertVariants({ variant }), className),
32
+ ...props
33
+ }
34
+ );
35
+ }
36
+ function AlertTitle({ className, ...props }) {
37
+ return /* @__PURE__ */ jsxRuntime.jsx(
38
+ "div",
39
+ {
40
+ "data-slot": "alert-title",
41
+ className: chunkADIDI7AJ_js.cn(
42
+ "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43
+ className
44
+ ),
45
+ ...props
46
+ }
47
+ );
48
+ }
49
+ function AlertDescription({
50
+ className,
51
+ ...props
52
+ }) {
53
+ return /* @__PURE__ */ jsxRuntime.jsx(
54
+ "div",
55
+ {
56
+ "data-slot": "alert-description",
57
+ className: chunkADIDI7AJ_js.cn(
58
+ "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
59
+ className
60
+ ),
61
+ ...props
62
+ }
63
+ );
64
+ }
65
+ var badgeVariants = classVarianceAuthority.cva(
66
+ "inline-flex items-center border font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
67
+ {
68
+ variants: {
69
+ variant: {
70
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
71
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
72
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
73
+ outline: "text-foreground",
74
+ success: "border-transparent bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400",
75
+ warning: "border-transparent bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400",
76
+ muted: "border-transparent bg-muted text-muted-foreground"
77
+ },
78
+ shape: {
79
+ pill: "rounded-full",
80
+ rounded: "rounded-md",
81
+ square: "rounded-none"
82
+ },
83
+ size: {
84
+ sm: "px-1 text-[9px]",
85
+ default: "px-1.5 text-[10px]",
86
+ lg: "px-2 py-0.5 text-xs"
87
+ }
88
+ },
89
+ defaultVariants: {
90
+ variant: "default",
91
+ shape: "pill",
92
+ size: "default"
93
+ }
94
+ }
95
+ );
96
+ function Badge({ className, variant, shape, size, ...props }) {
97
+ return /* @__PURE__ */ jsxRuntime.jsx(
98
+ "div",
99
+ {
100
+ "data-slot": "badge",
101
+ className: chunkADIDI7AJ_js.cn(badgeVariants({ variant, shape, size }), className),
102
+ ...props
103
+ }
104
+ );
105
+ }
106
+
107
+ exports.Alert = Alert;
108
+ exports.AlertDescription = AlertDescription;
109
+ exports.AlertTitle = AlertTitle;
110
+ exports.Badge = Badge;
111
+ exports.badgeVariants = badgeVariants;
@@ -0,0 +1,176 @@
1
+ 'use strict';
2
+
3
+ var lucideReact = require('lucide-react');
4
+
5
+ // src/utils/avatar-gradient.ts
6
+ var GRADIENT_PAIRS = [
7
+ // Vibrant contrasts
8
+ { from: "#f97316", to: "#ec4899" },
9
+ // Orange → Pink
10
+ { from: "#ef4444", to: "#a855f7" },
11
+ // Red → Purple
12
+ { from: "#f59e0b", to: "#ef4444" },
13
+ // Amber → Red
14
+ { from: "#ec4899", to: "#8b5cf6" },
15
+ // Pink → Violet
16
+ { from: "#f43f5e", to: "#fb923c" },
17
+ // Rose → Orange
18
+ // Cool gradients
19
+ { from: "#3b82f6", to: "#a855f7" },
20
+ // Blue → Purple
21
+ { from: "#6366f1", to: "#ec4899" },
22
+ // Indigo → Pink
23
+ { from: "#8b5cf6", to: "#06b6d4" },
24
+ // Violet → Cyan
25
+ { from: "#a855f7", to: "#3b82f6" },
26
+ // Purple → Blue
27
+ { from: "#06b6d4", to: "#10b981" },
28
+ // Cyan → Emerald
29
+ // Bold combos
30
+ { from: "#10b981", to: "#3b82f6" },
31
+ // Emerald → Blue
32
+ { from: "#14b8a6", to: "#8b5cf6" },
33
+ // Teal → Violet
34
+ { from: "#22c55e", to: "#06b6d4" },
35
+ // Green → Cyan
36
+ { from: "#0ea5e9", to: "#f43f5e" },
37
+ // Sky → Rose
38
+ { from: "#eab308", to: "#22c55e" }
39
+ // Yellow → Green
40
+ ];
41
+ function hashString(str) {
42
+ let hash = 0;
43
+ for (let i = 0; i < str.length; i++) {
44
+ const char = str.charCodeAt(i);
45
+ hash = (hash << 5) - hash + char;
46
+ hash = hash & hash;
47
+ }
48
+ return Math.abs(hash);
49
+ }
50
+ function getAvatarGradient(userId) {
51
+ const index = hashString(userId) % GRADIENT_PAIRS.length;
52
+ const gradient = GRADIENT_PAIRS[index];
53
+ return {
54
+ from: gradient.from,
55
+ to: gradient.to,
56
+ style: {
57
+ background: `linear-gradient(135deg, ${gradient.from} 0%, ${gradient.to} 100%)`
58
+ },
59
+ className: "text-white"
60
+ };
61
+ }
62
+ function getGradientIndex(userId) {
63
+ return hashString(userId) % GRADIENT_PAIRS.length;
64
+ }
65
+ function getGradientPairs() {
66
+ return GRADIENT_PAIRS;
67
+ }
68
+ var DATA_STATE_COPY = {
69
+ loading: {
70
+ title: "Loading data",
71
+ description: "Please wait while we prepare your finance data."
72
+ },
73
+ empty: {
74
+ title: "No data yet",
75
+ description: "There\u2019s no data for this selection yet."
76
+ },
77
+ stale: {
78
+ title: "Showing older data",
79
+ description: "This view may be out of date. Refresh to see the latest values."
80
+ },
81
+ partial: {
82
+ title: "Some data is missing",
83
+ description: "We loaded what we could, but part of this view is unavailable."
84
+ },
85
+ error: {
86
+ title: "Something went wrong",
87
+ description: "We couldn\u2019t load this data right now. Please try again."
88
+ },
89
+ unauthorized: {
90
+ title: "Access needed",
91
+ description: "You don\u2019t currently have permission to view this data."
92
+ },
93
+ misconfigured: {
94
+ title: "Setup required",
95
+ description: "This view needs additional setup before data can be shown."
96
+ }
97
+ };
98
+ function resolveDataState({
99
+ error,
100
+ data,
101
+ metadata,
102
+ hasData
103
+ }) {
104
+ const normalizedError = error;
105
+ const isUnauthorized = metadata?.isUnauthorized || normalizedError?.status === 401 || normalizedError?.status === 403 || normalizedError?.code === "unauthorized";
106
+ const isMisconfigured = metadata?.isMisconfigured || normalizedError?.status === 501 || normalizedError?.code === "misconfigured";
107
+ const computedHasData = hasData ? hasData(data) : metadata?.hasData ?? (Array.isArray(data) ? data.length > 0 : data != null && (typeof data !== "object" || Object.keys(data).length > 0));
108
+ if (metadata?.isLoading || metadata?.isFetching) {
109
+ return {
110
+ state: "loading",
111
+ retryable: false,
112
+ copy: DATA_STATE_COPY.loading
113
+ };
114
+ }
115
+ if (isUnauthorized) {
116
+ return {
117
+ state: "unauthorized",
118
+ retryable: false,
119
+ copy: DATA_STATE_COPY.unauthorized
120
+ };
121
+ }
122
+ if (isMisconfigured) {
123
+ return {
124
+ state: "misconfigured",
125
+ retryable: false,
126
+ copy: DATA_STATE_COPY.misconfigured
127
+ };
128
+ }
129
+ if (error) {
130
+ return { state: "error", retryable: true, copy: DATA_STATE_COPY.error };
131
+ }
132
+ if (metadata?.isPartial) {
133
+ return { state: "partial", retryable: true, copy: DATA_STATE_COPY.partial };
134
+ }
135
+ if (metadata?.isStale) {
136
+ return { state: "stale", retryable: true, copy: DATA_STATE_COPY.stale };
137
+ }
138
+ if (metadata?.isEmpty || !computedHasData) {
139
+ return { state: "empty", retryable: false, copy: DATA_STATE_COPY.empty };
140
+ }
141
+ return { state: null, retryable: false };
142
+ }
143
+ function getDataStateIcon(state) {
144
+ switch (state) {
145
+ case "loading":
146
+ return lucideReact.LoaderCircle;
147
+ case "empty":
148
+ return lucideReact.Database;
149
+ case "error":
150
+ case "unauthorized":
151
+ case "misconfigured":
152
+ return lucideReact.AlertCircle;
153
+ case "partial":
154
+ return lucideReact.AlertTriangle;
155
+ default:
156
+ return lucideReact.RefreshCcw;
157
+ }
158
+ }
159
+ function getDataStateIconClassName(state) {
160
+ switch (state) {
161
+ case "loading":
162
+ return "animate-spin";
163
+ case "empty":
164
+ return "animate-pulse";
165
+ default:
166
+ return "";
167
+ }
168
+ }
169
+
170
+ exports.DATA_STATE_COPY = DATA_STATE_COPY;
171
+ exports.getAvatarGradient = getAvatarGradient;
172
+ exports.getDataStateIcon = getDataStateIcon;
173
+ exports.getDataStateIconClassName = getDataStateIconClassName;
174
+ exports.getGradientIndex = getGradientIndex;
175
+ exports.getGradientPairs = getGradientPairs;
176
+ exports.resolveDataState = resolveDataState;
@@ -0,0 +1,223 @@
1
+ import { cn } from './chunk-IMKLN273.mjs';
2
+ import * as React from 'react';
3
+ import { Tooltip } from 'recharts';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ var ChartContext = React.createContext(null);
7
+ function useChart() {
8
+ const context = React.useContext(ChartContext);
9
+ if (!context) {
10
+ throw new Error("useChart must be used within a <ChartContainer />");
11
+ }
12
+ return context;
13
+ }
14
+ var ChartContainer = React.forwardRef(({ id, className, children, config, ...props }, ref) => {
15
+ const uniqueId = React.useId();
16
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
17
+ const containerRef = React.useRef(null);
18
+ const [_dimensions, setDimensions] = React.useState(null);
19
+ React.useImperativeHandle(ref, () => containerRef.current);
20
+ React.useEffect(() => {
21
+ const container = containerRef.current;
22
+ if (!container) return;
23
+ const updateDimensions = () => {
24
+ const { width, height } = container.getBoundingClientRect();
25
+ if (width > 0 && height > 0) {
26
+ setDimensions({ width: Math.floor(width), height: Math.floor(height) });
27
+ }
28
+ };
29
+ const timeout = setTimeout(updateDimensions, 50);
30
+ const resizeObserver = new ResizeObserver((entries) => {
31
+ for (const entry of entries) {
32
+ const { width, height } = entry.contentRect;
33
+ if (width > 0 && height > 0) {
34
+ setDimensions({
35
+ width: Math.floor(width),
36
+ height: Math.floor(height)
37
+ });
38
+ }
39
+ }
40
+ });
41
+ resizeObserver.observe(container);
42
+ return () => {
43
+ clearTimeout(timeout);
44
+ resizeObserver.disconnect();
45
+ };
46
+ }, []);
47
+ return /* @__PURE__ */ jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs(
48
+ "div",
49
+ {
50
+ "data-chart": chartId,
51
+ ref: containerRef,
52
+ className: cn(
53
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
54
+ className
55
+ ),
56
+ ...props,
57
+ children: [
58
+ /* @__PURE__ */ jsx(ChartStyle, { id: chartId, config }),
59
+ children
60
+ ]
61
+ }
62
+ ) });
63
+ });
64
+ ChartContainer.displayName = "ChartContainer";
65
+ var ChartStyle = ({ id, config }) => {
66
+ const colorConfig = Object.entries(config).filter(
67
+ ([_, config2]) => config2.theme || config2.color
68
+ );
69
+ if (!colorConfig.length) {
70
+ return null;
71
+ }
72
+ return /* @__PURE__ */ jsx(
73
+ "style",
74
+ {
75
+ dangerouslySetInnerHTML: {
76
+ __html: Object.entries(config).map(([key, item]) => {
77
+ const color = item.theme || item.color;
78
+ if (color && typeof color === "string") {
79
+ return `
80
+ [data-chart=${id}] {
81
+ --color-${key}: ${color};
82
+ }
83
+ `;
84
+ }
85
+ if (color && typeof color === "object") {
86
+ return `
87
+ [data-chart=${id}] {
88
+ --color-${key}: ${color.light};
89
+ }
90
+ .dark [data-chart=${id}] {
91
+ --color-${key}: ${color.dark};
92
+ }
93
+ `;
94
+ }
95
+ return "";
96
+ }).join("\n")
97
+ }
98
+ }
99
+ );
100
+ };
101
+ var ChartTooltip = Tooltip;
102
+ var ChartTooltipContent = React.forwardRef(
103
+ ({
104
+ active,
105
+ payload,
106
+ className,
107
+ indicator = "dot",
108
+ hideLabel = false,
109
+ hideIndicator = false,
110
+ label,
111
+ labelFormatter,
112
+ labelKey,
113
+ nameKey,
114
+ color
115
+ }, ref) => {
116
+ const { config } = useChart();
117
+ const tooltipLabel = React.useMemo(() => {
118
+ if (hideLabel || !payload?.length) {
119
+ return null;
120
+ }
121
+ const [item] = payload;
122
+ const key = `${labelKey || item.dataKey || item.name || "value"}`;
123
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
124
+ const value = !labelKey && typeof label === "string" ? config[label]?.label || label : itemConfig?.label;
125
+ if (labelFormatter) {
126
+ return /* @__PURE__ */ jsx("div", { className: cn("font-medium", className), children: labelFormatter(value, payload) });
127
+ }
128
+ if (!value) {
129
+ return null;
130
+ }
131
+ return /* @__PURE__ */ jsx("div", { className: cn("font-medium", className), children: value });
132
+ }, [
133
+ label,
134
+ labelFormatter,
135
+ payload,
136
+ hideLabel,
137
+ className,
138
+ config,
139
+ labelKey
140
+ ]);
141
+ if (!active || !payload?.length) {
142
+ return null;
143
+ }
144
+ const nestLabel = payload.length === 1 && indicator !== "dot";
145
+ return /* @__PURE__ */ jsxs(
146
+ "div",
147
+ {
148
+ ref,
149
+ className: cn(
150
+ "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
151
+ className
152
+ ),
153
+ children: [
154
+ !nestLabel ? tooltipLabel : null,
155
+ /* @__PURE__ */ jsx("div", { className: "grid gap-1.5", children: payload.map((item, _index) => {
156
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
157
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
158
+ const indicatorColor = color || item.payload?.fill || item.color;
159
+ return /* @__PURE__ */ jsxs(
160
+ "div",
161
+ {
162
+ className: cn(
163
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
164
+ indicator === "dot" && "items-center"
165
+ ),
166
+ children: [
167
+ itemConfig?.icon ? /* @__PURE__ */ jsx(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx(
168
+ "div",
169
+ {
170
+ className: cn(
171
+ "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
172
+ {
173
+ "h-2.5 w-2.5": indicator === "dot",
174
+ "w-1": indicator === "line",
175
+ "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
176
+ "my-0.5": nestLabel && indicator === "dashed"
177
+ }
178
+ ),
179
+ style: {
180
+ "--color-bg": indicatorColor,
181
+ "--color-border": indicatorColor
182
+ }
183
+ }
184
+ ),
185
+ /* @__PURE__ */ jsxs(
186
+ "div",
187
+ {
188
+ className: cn(
189
+ "flex flex-1 justify-between leading-none",
190
+ nestLabel ? "items-end" : "items-center"
191
+ ),
192
+ children: [
193
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-1.5", children: [
194
+ nestLabel ? tooltipLabel : null,
195
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: itemConfig?.label || item.name })
196
+ ] }),
197
+ item.value && /* @__PURE__ */ jsx("span", { className: "font-mono font-medium tabular-nums text-foreground", children: item.value.toLocaleString() })
198
+ ]
199
+ }
200
+ )
201
+ ]
202
+ },
203
+ item.dataKey
204
+ );
205
+ }) })
206
+ ]
207
+ }
208
+ );
209
+ }
210
+ );
211
+ ChartTooltipContent.displayName = "ChartTooltipContent";
212
+ function getPayloadConfigFromPayload(config, payload, key) {
213
+ const payloadPayload = payload.payload;
214
+ let configLabelKey = key;
215
+ if (key in payload && typeof payload[key] === "string") {
216
+ configLabelKey = payload[key];
217
+ } else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === "string") {
218
+ configLabelKey = payloadPayload[key];
219
+ }
220
+ return configLabelKey in config ? config[configLabelKey] : config[key];
221
+ }
222
+
223
+ export { ChartContainer, ChartTooltip, ChartTooltipContent };
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ var chunkJAE45W2T_js = require('./chunk-JAE45W2T.js');
4
+ var chunk6TGV2DNP_js = require('./chunk-6TGV2DNP.js');
5
+ var chunkDQWHYBV2_js = require('./chunk-DQWHYBV2.js');
6
+ var lucideReact = require('lucide-react');
7
+ var react = require('react');
8
+ var sonner = require('sonner');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ var SHAKE_STYLE_ID = "newsletter-shake-keyframes";
12
+ function injectShakeKeyframes() {
13
+ if (typeof document === "undefined") return;
14
+ if (document.getElementById(SHAKE_STYLE_ID)) return;
15
+ const style = document.createElement("style");
16
+ style.id = SHAKE_STYLE_ID;
17
+ style.textContent = `
18
+ @keyframes shake {
19
+ 0%, 100% { transform: translateX(0); }
20
+ 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
21
+ 20%, 40%, 60%, 80% { transform: translateX(4px); }
22
+ }
23
+ `;
24
+ document.head.appendChild(style);
25
+ }
26
+ function NewsletterSignup({
27
+ className,
28
+ endpoint = "/api/newsletter/subscribe",
29
+ source,
30
+ placeholder = "Enter your email",
31
+ inputLabel = "Email address",
32
+ buttonLabel = "Subscribe",
33
+ submittingLabel = "Subscribing...",
34
+ successTitle = "You're subscribed!",
35
+ successDescription = "Check your email to confirm.",
36
+ errorMessage = "Something went wrong. Please try again.",
37
+ inputClassName,
38
+ buttonClassName,
39
+ successClassName
40
+ }) {
41
+ const [email, setEmail] = react.useState("");
42
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
43
+ const [submitted, setSubmitted] = react.useState(false);
44
+ const [hasError, setHasError] = react.useState(false);
45
+ react.useEffect(() => {
46
+ injectShakeKeyframes();
47
+ }, []);
48
+ const handleSubmit = async (e) => {
49
+ e.preventDefault();
50
+ if (!email) return;
51
+ setIsSubmitting(true);
52
+ setHasError(false);
53
+ try {
54
+ const response = await fetch(endpoint, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/json" },
57
+ body: JSON.stringify({ email, source })
58
+ });
59
+ if (response.ok) {
60
+ setSubmitted(true);
61
+ setEmail("");
62
+ } else {
63
+ const data = await response.json();
64
+ sonner.toast.error(data.error || errorMessage);
65
+ setHasError(true);
66
+ setTimeout(() => setHasError(false), 500);
67
+ }
68
+ } catch {
69
+ sonner.toast.error(
70
+ "Unable to connect. Please check your connection and try again."
71
+ );
72
+ setHasError(true);
73
+ setTimeout(() => setHasError(false), 500);
74
+ } finally {
75
+ setIsSubmitting(false);
76
+ }
77
+ };
78
+ if (submitted) {
79
+ return /* @__PURE__ */ jsxRuntime.jsxs(
80
+ "div",
81
+ {
82
+ className: chunkJAE45W2T_js.cx(
83
+ "flex items-center justify-center gap-3 rounded-box border border-border px-4 py-3",
84
+ className,
85
+ successClassName
86
+ ),
87
+ children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground animate-in zoom-in duration-300", children: /* @__PURE__ */ jsxRuntime.jsx(
89
+ lucideReact.Check,
90
+ {
91
+ className: "h-4 w-4 animate-in fade-in duration-500 delay-150",
92
+ strokeWidth: 3
93
+ }
94
+ ) }),
95
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-in slide-in-from-left-2 fade-in duration-300 delay-100 text-left", children: [
96
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-foreground", children: successTitle }),
97
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: successDescription })
98
+ ] })
99
+ ]
100
+ }
101
+ );
102
+ }
103
+ return /* @__PURE__ */ jsxRuntime.jsxs(
104
+ "form",
105
+ {
106
+ onSubmit: handleSubmit,
107
+ className: chunkJAE45W2T_js.cx("flex", hasError && "animate-shake", className),
108
+ style: hasError ? { animation: "shake 0.5s ease-in-out" } : void 0,
109
+ children: [
110
+ /* @__PURE__ */ jsxRuntime.jsx(
111
+ chunkDQWHYBV2_js.Input,
112
+ {
113
+ "aria-label": inputLabel,
114
+ type: "email",
115
+ placeholder,
116
+ value: email,
117
+ onChange: (e) => setEmail(e.target.value),
118
+ required: true,
119
+ className: chunkJAE45W2T_js.cx(
120
+ "flex-1 rounded-r-none border-r-0 focus-visible:z-10",
121
+ inputClassName
122
+ )
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsxRuntime.jsxs(
126
+ chunk6TGV2DNP_js.Button,
127
+ {
128
+ type: "submit",
129
+ disabled: isSubmitting || !email,
130
+ className: chunkJAE45W2T_js.cx("rounded-l-none", buttonClassName),
131
+ children: [
132
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "mr-2 h-4 w-4" }),
133
+ isSubmitting ? submittingLabel : buttonLabel
134
+ ]
135
+ }
136
+ )
137
+ ]
138
+ }
139
+ );
140
+ }
141
+
142
+ exports.NewsletterSignup = NewsletterSignup;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useScrollDirection.ts
6
+ function useScrollDirection({
7
+ threshold = 10,
8
+ topThreshold = 50
9
+ } = {}) {
10
+ const [direction, setDirection] = react.useState(null);
11
+ const [isAtTop, setIsAtTop] = react.useState(true);
12
+ const lastScrollY = react.useRef(0);
13
+ const ticking = react.useRef(false);
14
+ const updateScrollDirection = react.useCallback(() => {
15
+ const scrollY = window.scrollY;
16
+ setIsAtTop(scrollY < topThreshold);
17
+ const diff = scrollY - lastScrollY.current;
18
+ if (Math.abs(diff) >= threshold) {
19
+ setDirection(diff > 0 ? "down" : "up");
20
+ lastScrollY.current = scrollY;
21
+ }
22
+ ticking.current = false;
23
+ }, [threshold, topThreshold]);
24
+ const onScroll = react.useCallback(() => {
25
+ if (!ticking.current) {
26
+ window.requestAnimationFrame(updateScrollDirection);
27
+ ticking.current = true;
28
+ }
29
+ }, [updateScrollDirection]);
30
+ react.useEffect(() => {
31
+ lastScrollY.current = window.scrollY;
32
+ setIsAtTop(window.scrollY < topThreshold);
33
+ window.addEventListener("scroll", onScroll, { passive: true });
34
+ return () => window.removeEventListener("scroll", onScroll);
35
+ }, [onScroll, topThreshold]);
36
+ return { direction, isAtTop };
37
+ }
38
+
39
+ exports.useScrollDirection = useScrollDirection;