create-freakpunch 0.0.0-stage → 0.2.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 (216) hide show
  1. package/README.md +24 -3
  2. package/bin/create-freakpunch.mjs +227 -0
  3. package/files/README.md +19 -0
  4. package/files/app.config.ts +50 -0
  5. package/files/locales.ts +10 -0
  6. package/files/registry.ts +17 -0
  7. package/package.json +23 -6
  8. package/template/.dockerignore +17 -0
  9. package/template/.oxlintrc.json +9 -0
  10. package/template/AGENTS.md +6 -0
  11. package/template/BACKEND.md +108 -0
  12. package/template/CLAUDE.md +297 -0
  13. package/template/Dockerfile +19 -0
  14. package/template/_gitignore +26 -0
  15. package/template/components.json +27 -0
  16. package/template/design/COMPONENTS.md +145 -0
  17. package/template/design/DESIGN.md +212 -0
  18. package/template/design/PATTERNS.md +110 -0
  19. package/template/index.html +25 -0
  20. package/template/nginx.conf +32 -0
  21. package/template/package-lock.json +6484 -0
  22. package/template/package.json +51 -0
  23. package/template/public/favicon.svg +1 -0
  24. package/template/public/robots.txt +2 -0
  25. package/template/src/app.config.ts +50 -0
  26. package/template/src/app.roles.ts +24 -0
  27. package/template/src/components/ui/alert-dialog.tsx +181 -0
  28. package/template/src/components/ui/avatar.tsx +116 -0
  29. package/template/src/components/ui/badge.tsx +57 -0
  30. package/template/src/components/ui/breadcrumb.tsx +130 -0
  31. package/template/src/components/ui/button.tsx +58 -0
  32. package/template/src/components/ui/calendar.tsx +277 -0
  33. package/template/src/components/ui/card.tsx +99 -0
  34. package/template/src/components/ui/chart.tsx +370 -0
  35. package/template/src/components/ui/checkbox.tsx +28 -0
  36. package/template/src/components/ui/combobox.tsx +329 -0
  37. package/template/src/components/ui/command.tsx +191 -0
  38. package/template/src/components/ui/dialog.tsx +162 -0
  39. package/template/src/components/ui/dropdown-menu.tsx +271 -0
  40. package/template/src/components/ui/empty.tsx +103 -0
  41. package/template/src/components/ui/field.tsx +236 -0
  42. package/template/src/components/ui/input-group.tsx +263 -0
  43. package/template/src/components/ui/input.tsx +45 -0
  44. package/template/src/components/ui/kbd.tsx +31 -0
  45. package/template/src/components/ui/label.tsx +17 -0
  46. package/template/src/components/ui/pagination.tsx +134 -0
  47. package/template/src/components/ui/popover.tsx +87 -0
  48. package/template/src/components/ui/radio-group.tsx +35 -0
  49. package/template/src/components/ui/select.tsx +204 -0
  50. package/template/src/components/ui/separator.tsx +25 -0
  51. package/template/src/components/ui/sheet.tsx +139 -0
  52. package/template/src/components/ui/sidebar.tsx +741 -0
  53. package/template/src/components/ui/skeleton.tsx +13 -0
  54. package/template/src/components/ui/sonner.tsx +78 -0
  55. package/template/src/components/ui/spinner.tsx +42 -0
  56. package/template/src/components/ui/switch.tsx +29 -0
  57. package/template/src/components/ui/table.tsx +121 -0
  58. package/template/src/components/ui/tabs.tsx +191 -0
  59. package/template/src/components/ui/textarea.tsx +17 -0
  60. package/template/src/components/ui/toggle-group.tsx +94 -0
  61. package/template/src/components/ui/toggle.tsx +48 -0
  62. package/template/src/components/ui/tooltip.tsx +91 -0
  63. package/template/src/core/api/demo.ts +8 -0
  64. package/template/src/core/api/http.ts +76 -0
  65. package/template/src/core/api/mock.ts +88 -0
  66. package/template/src/core/api/rest.ts +67 -0
  67. package/template/src/core/api/types.ts +21 -0
  68. package/template/src/core/audit/audit.service.ts +94 -0
  69. package/template/src/core/audit/hooks.ts +19 -0
  70. package/template/src/core/auth/auth-store.ts +52 -0
  71. package/template/src/core/auth/auth.service.ts +86 -0
  72. package/template/src/core/auth/can.tsx +39 -0
  73. package/template/src/core/auth/dev-role-switcher.tsx +64 -0
  74. package/template/src/core/auth/local-credentials.ts +46 -0
  75. package/template/src/core/auth/permissions.ts +115 -0
  76. package/template/src/core/auth/require-auth.tsx +16 -0
  77. package/template/src/core/auth/require-permission.tsx +24 -0
  78. package/template/src/core/auth/roles.ts +9 -0
  79. package/template/src/core/auth/types.ts +20 -0
  80. package/template/src/core/auth/use-auth.ts +19 -0
  81. package/template/src/core/company/company.service.ts +94 -0
  82. package/template/src/core/company/hooks.ts +40 -0
  83. package/template/src/core/company/password-policy.ts +40 -0
  84. package/template/src/core/company/types.ts +46 -0
  85. package/template/src/core/company/use-app-name.ts +7 -0
  86. package/template/src/core/components/button-link.tsx +14 -0
  87. package/template/src/core/components/confirm-dialog.tsx +116 -0
  88. package/template/src/core/components/data-table/data-table.tsx +297 -0
  89. package/template/src/core/components/data-table/features.ts +24 -0
  90. package/template/src/core/components/data-table/table-header-cell.tsx +13 -0
  91. package/template/src/core/components/data-table/toolbar.tsx +100 -0
  92. package/template/src/core/components/data-table/use-list-url-state.ts +108 -0
  93. package/template/src/core/components/date-picker.tsx +71 -0
  94. package/template/src/core/components/file-attachments.tsx +84 -0
  95. package/template/src/core/components/form-error.tsx +9 -0
  96. package/template/src/core/components/form-page.tsx +93 -0
  97. package/template/src/core/components/image-upload.tsx +86 -0
  98. package/template/src/core/components/page.tsx +75 -0
  99. package/template/src/core/components/phone-input.tsx +58 -0
  100. package/template/src/core/components/search-select.tsx +57 -0
  101. package/template/src/core/components/segmented.tsx +41 -0
  102. package/template/src/core/components/states.tsx +97 -0
  103. package/template/src/core/components/status-badge.tsx +26 -0
  104. package/template/src/core/components/user-avatar.tsx +23 -0
  105. package/template/src/core/config/runtime.ts +16 -0
  106. package/template/src/core/config/types.ts +37 -0
  107. package/template/src/core/i18n/i18n.ts +69 -0
  108. package/template/src/core/i18n/i18next.d.ts +12 -0
  109. package/template/src/core/i18n/keys.ts +37 -0
  110. package/template/src/core/i18n/language-switcher.tsx +45 -0
  111. package/template/src/core/i18n/types.ts +17 -0
  112. package/template/src/core/i18n/use-format.ts +31 -0
  113. package/template/src/core/layout/app-shell.tsx +50 -0
  114. package/template/src/core/layout/app-sidebar.tsx +285 -0
  115. package/template/src/core/layout/command-menu.tsx +117 -0
  116. package/template/src/core/layout/top-bar.tsx +100 -0
  117. package/template/src/core/lib/csv.ts +27 -0
  118. package/template/src/core/lib/format.ts +87 -0
  119. package/template/src/core/lib/phone.ts +50 -0
  120. package/template/src/core/lib/storage.ts +27 -0
  121. package/template/src/core/modules/lazy-page.ts +9 -0
  122. package/template/src/core/modules/navigation.ts +39 -0
  123. package/template/src/core/modules/types.ts +55 -0
  124. package/template/src/core/notifications/hooks.ts +84 -0
  125. package/template/src/core/notifications/notification-center.tsx +251 -0
  126. package/template/src/core/notifications/notifications.service.ts +132 -0
  127. package/template/src/core/notifications/types.ts +70 -0
  128. package/template/src/core/preferences/preferences-store.ts +70 -0
  129. package/template/src/core/setup/setup-gate.tsx +20 -0
  130. package/template/src/core/setup/setup.service.ts +101 -0
  131. package/template/src/core/theme/brand-context.tsx +53 -0
  132. package/template/src/core/theme/brand.ts +29 -0
  133. package/template/src/core/theme/theme-context.tsx +62 -0
  134. package/template/src/core/theme/theme-options.ts +8 -0
  135. package/template/src/core/theme/theme-toggle.tsx +45 -0
  136. package/template/src/core/users/hooks.ts +51 -0
  137. package/template/src/core/users/types.ts +37 -0
  138. package/template/src/core/users/users.service.ts +167 -0
  139. package/template/src/hooks/use-mobile.ts +19 -0
  140. package/template/src/index.css +321 -0
  141. package/template/src/lib/utils.ts +1 -0
  142. package/template/src/locales/en/account.ts +180 -0
  143. package/template/src/locales/en/auth.ts +18 -0
  144. package/template/src/locales/en/common.ts +151 -0
  145. package/template/src/locales/en/company.ts +380 -0
  146. package/template/src/locales/en/dashboard.ts +46 -0
  147. package/template/src/locales/en/errors.ts +18 -0
  148. package/template/src/locales/en/notifications.ts +43 -0
  149. package/template/src/locales/en/settings.ts +25 -0
  150. package/template/src/locales/en/setup.ts +45 -0
  151. package/template/src/locales/index.ts +58 -0
  152. package/template/src/locales/tr/account.ts +184 -0
  153. package/template/src/locales/tr/auth.ts +22 -0
  154. package/template/src/locales/tr/common.ts +154 -0
  155. package/template/src/locales/tr/company.ts +384 -0
  156. package/template/src/locales/tr/dashboard.ts +50 -0
  157. package/template/src/locales/tr/errors.ts +22 -0
  158. package/template/src/locales/tr/notifications.ts +47 -0
  159. package/template/src/locales/tr/settings.ts +29 -0
  160. package/template/src/locales/tr/setup.ts +49 -0
  161. package/template/src/main.tsx +16 -0
  162. package/template/src/modules/locales.ts +10 -0
  163. package/template/src/modules/registry.ts +17 -0
  164. package/template/src/pages/dashboard/dashboard-page.tsx +55 -0
  165. package/template/src/pages/dashboard/quick-actions.tsx +37 -0
  166. package/template/src/pages/login-page.tsx +152 -0
  167. package/template/src/pages/no-access-page.tsx +11 -0
  168. package/template/src/pages/not-found-page.tsx +61 -0
  169. package/template/src/pages/settings/account/account.service.ts +128 -0
  170. package/template/src/pages/settings/account/components/mock-qr.tsx +50 -0
  171. package/template/src/pages/settings/account/components/password-strength.tsx +38 -0
  172. package/template/src/pages/settings/account/components/two-factor-dialog.tsx +140 -0
  173. package/template/src/pages/settings/account/hooks.ts +73 -0
  174. package/template/src/pages/settings/account/notifications-page.tsx +103 -0
  175. package/template/src/pages/settings/account/preferences-page.tsx +157 -0
  176. package/template/src/pages/settings/account/profile-page.tsx +242 -0
  177. package/template/src/pages/settings/account/security-page.tsx +364 -0
  178. package/template/src/pages/settings/account/types.ts +37 -0
  179. package/template/src/pages/settings/company/audit-log-page.tsx +126 -0
  180. package/template/src/pages/settings/company/branding-page.tsx +278 -0
  181. package/template/src/pages/settings/company/components/invite-dialog.tsx +106 -0
  182. package/template/src/pages/settings/company/components/read-only-notice.tsx +13 -0
  183. package/template/src/pages/settings/company/danger-zone-page.tsx +127 -0
  184. package/template/src/pages/settings/company/general-page.tsx +234 -0
  185. package/template/src/pages/settings/company/integrations/api-keys-panel.tsx +170 -0
  186. package/template/src/pages/settings/company/integrations/hooks.ts +37 -0
  187. package/template/src/pages/settings/company/integrations/integrations-page.tsx +57 -0
  188. package/template/src/pages/settings/company/integrations/integrations.service.ts +153 -0
  189. package/template/src/pages/settings/company/integrations/settings-forms.tsx +299 -0
  190. package/template/src/pages/settings/company/integrations/webhooks-panel.tsx +179 -0
  191. package/template/src/pages/settings/company/modules-page.tsx +65 -0
  192. package/template/src/pages/settings/company/roles-page.tsx +116 -0
  193. package/template/src/pages/settings/company/security-policies-page.tsx +164 -0
  194. package/template/src/pages/settings/company/users-page.tsx +262 -0
  195. package/template/src/pages/settings/settings-layout.tsx +57 -0
  196. package/template/src/pages/settings/settings-nav.ts +69 -0
  197. package/template/src/pages/settings/settings-routes.tsx +49 -0
  198. package/template/src/pages/setup-page.tsx +387 -0
  199. package/template/src/providers.tsx +68 -0
  200. package/template/src/router.tsx +59 -0
  201. package/template/tools/check-design.mjs +73 -0
  202. package/template/tools/new-module.mjs +90 -0
  203. package/template/tools/templates/module/api/__id__.mock.ts.tpl +17 -0
  204. package/template/tools/templates/module/api/__id__.service.ts.tpl +51 -0
  205. package/template/tools/templates/module/hooks.ts.tpl +57 -0
  206. package/template/tools/templates/module/index.ts.tpl +44 -0
  207. package/template/tools/templates/module/locales/en.ts.tpl +51 -0
  208. package/template/tools/templates/module/locales/tr.ts.tpl +55 -0
  209. package/template/tools/templates/module/pages/__id__-detail-page.tsx.tpl +103 -0
  210. package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -0
  211. package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -0
  212. package/template/tools/templates/module/types.ts.tpl +32 -0
  213. package/template/tsconfig.app.json +32 -0
  214. package/template/tsconfig.json +12 -0
  215. package/template/tsconfig.node.json +23 -0
  216. package/template/vite.config.ts +47 -0
@@ -0,0 +1,370 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "@/lib/utils"
5
+ import * as RechartsPrimitive from "recharts"
6
+ import type { TooltipValueType } from "recharts"
7
+
8
+ // Format: { THEME_NAME: CSS_SELECTOR }
9
+ const THEMES = { light: "", dark: ".dark" } as const
10
+
11
+ const INITIAL_DIMENSION = { width: 320, height: 200 } as const
12
+ type TooltipNameType = number | string
13
+
14
+ export type ChartConfig = Record<
15
+ string,
16
+ {
17
+ label?: React.ReactNode
18
+ icon?: React.ComponentType
19
+ } & (
20
+ | { color?: string; theme?: never }
21
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
22
+ )
23
+ >
24
+
25
+ type ChartContextProps = {
26
+ config: ChartConfig
27
+ }
28
+
29
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
30
+
31
+ function useChart() {
32
+ const context = React.useContext(ChartContext)
33
+
34
+ if (!context) {
35
+ throw new Error("useChart must be used within a <ChartContainer />")
36
+ }
37
+
38
+ return context
39
+ }
40
+
41
+ function ChartContainer({
42
+ id,
43
+ className,
44
+ children,
45
+ config,
46
+ initialDimension = INITIAL_DIMENSION,
47
+ ...props
48
+ }: React.ComponentProps<"div"> & {
49
+ config: ChartConfig
50
+ children: React.ComponentProps<
51
+ typeof RechartsPrimitive.ResponsiveContainer
52
+ >["children"]
53
+ initialDimension?: {
54
+ width: number
55
+ height: number
56
+ }
57
+ }) {
58
+ const uniqueId = React.useId()
59
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`
60
+
61
+ return (
62
+ <ChartContext.Provider value={{ config }}>
63
+ <div
64
+ data-slot="chart"
65
+ data-chart={chartId}
66
+ className={cn(
67
+ "flex aspect-video justify-center text-2xs [&_.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-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-fill-2 [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-fill-2 [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
68
+ className
69
+ )}
70
+ {...props}
71
+ >
72
+ <ChartStyle id={chartId} config={config} />
73
+ <RechartsPrimitive.ResponsiveContainer
74
+ initialDimension={initialDimension}
75
+ >
76
+ {children}
77
+ </RechartsPrimitive.ResponsiveContainer>
78
+ </div>
79
+ </ChartContext.Provider>
80
+ )
81
+ }
82
+
83
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
84
+ const colorConfig = Object.entries(config).filter(
85
+ ([, config]) => config.theme ?? config.color
86
+ )
87
+
88
+ if (!colorConfig.length) {
89
+ return null
90
+ }
91
+
92
+ return (
93
+ <style
94
+ dangerouslySetInnerHTML={{
95
+ __html: Object.entries(THEMES)
96
+ .map(
97
+ ([theme, prefix]) => `
98
+ ${prefix} [data-chart=${id}] {
99
+ ${colorConfig
100
+ .map(([key, itemConfig]) => {
101
+ const color =
102
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
103
+ itemConfig.color
104
+ return color ? ` --color-${key}: ${color};` : null
105
+ })
106
+ .join("\n")}
107
+ }
108
+ `
109
+ )
110
+ .join("\n"),
111
+ }}
112
+ />
113
+ )
114
+ }
115
+
116
+ const ChartTooltip = RechartsPrimitive.Tooltip
117
+
118
+ function ChartTooltipContent({
119
+ active,
120
+ payload,
121
+ className,
122
+ indicator = "dot",
123
+ hideLabel = false,
124
+ hideIndicator = false,
125
+ label,
126
+ labelFormatter,
127
+ labelClassName,
128
+ formatter,
129
+ color,
130
+ nameKey,
131
+ labelKey,
132
+ }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
133
+ React.ComponentProps<"div"> & {
134
+ hideLabel?: boolean
135
+ hideIndicator?: boolean
136
+ indicator?: "line" | "dot" | "dashed"
137
+ nameKey?: string
138
+ labelKey?: string
139
+ } & Omit<
140
+ RechartsPrimitive.DefaultTooltipContentProps<
141
+ TooltipValueType,
142
+ TooltipNameType
143
+ >,
144
+ "accessibilityLayer"
145
+ >) {
146
+ const { config } = useChart()
147
+
148
+ const tooltipLabel = React.useMemo(() => {
149
+ if (hideLabel || !payload?.length) {
150
+ return null
151
+ }
152
+
153
+ const [item] = payload
154
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`
155
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
156
+ const value =
157
+ !labelKey && typeof label === "string"
158
+ ? (config[label]?.label ?? label)
159
+ : itemConfig?.label
160
+
161
+ if (labelFormatter) {
162
+ return (
163
+ <div className={cn("font-medium", labelClassName)}>
164
+ {labelFormatter(value, payload)}
165
+ </div>
166
+ )
167
+ }
168
+
169
+ if (!value) {
170
+ return null
171
+ }
172
+
173
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
174
+ }, [
175
+ label,
176
+ labelFormatter,
177
+ payload,
178
+ hideLabel,
179
+ labelClassName,
180
+ config,
181
+ labelKey,
182
+ ])
183
+
184
+ if (!active || !payload?.length) {
185
+ return null
186
+ }
187
+
188
+ const nestLabel = payload.length === 1 && indicator !== "dot"
189
+
190
+ return (
191
+ <div
192
+ className={cn(
193
+ "grid min-w-32 items-start gap-2 rounded-xl bg-popover px-2.5 py-2 text-2xs text-popover-foreground shadow-(--shadow-popover) ring-1 ring-border",
194
+ className
195
+ )}
196
+ >
197
+ {!nestLabel ? tooltipLabel : null}
198
+ <div className="grid gap-2">
199
+ {payload
200
+ .filter((item) => item.type !== "none")
201
+ .map((item, index) => {
202
+ const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
203
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
204
+ const indicatorColor = color ?? item.payload?.fill ?? item.color
205
+
206
+ return (
207
+ <div
208
+ key={index}
209
+ className={cn(
210
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
211
+ indicator === "dot" && "items-center"
212
+ )}
213
+ >
214
+ {formatter && item?.value !== undefined && item.name ? (
215
+ formatter(item.value, item.name, item, index, item.payload)
216
+ ) : (
217
+ <>
218
+ {itemConfig?.icon ? (
219
+ <itemConfig.icon />
220
+ ) : (
221
+ !hideIndicator && (
222
+ <div
223
+ className={cn(
224
+ "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
225
+ {
226
+ "h-2.5 w-2.5": indicator === "dot",
227
+ "w-1": indicator === "line",
228
+ "w-0 border-[1.5px] border-dashed bg-transparent":
229
+ indicator === "dashed",
230
+ "my-0.5": nestLabel && indicator === "dashed",
231
+ }
232
+ )}
233
+ style={
234
+ {
235
+ "--color-bg": indicatorColor,
236
+ "--color-border": indicatorColor,
237
+ } as React.CSSProperties
238
+ }
239
+ />
240
+ )
241
+ )}
242
+ <div
243
+ className={cn(
244
+ "flex flex-1 justify-between gap-2 leading-4",
245
+ nestLabel ? "items-end" : "items-center"
246
+ )}
247
+ >
248
+ <div className="grid gap-2">
249
+ {nestLabel ? tooltipLabel : null}
250
+ <span>{itemConfig?.label ?? item.name}</span>
251
+ </div>
252
+ {item.value != null && (
253
+ <span className="font-mono text-foreground tabular-nums">
254
+ {typeof item.value === "number"
255
+ ? item.value.toLocaleString()
256
+ : String(item.value)}
257
+ </span>
258
+ )}
259
+ </div>
260
+ </>
261
+ )}
262
+ </div>
263
+ )
264
+ })}
265
+ </div>
266
+ </div>
267
+ )
268
+ }
269
+
270
+ const ChartLegend = RechartsPrimitive.Legend
271
+
272
+ function ChartLegendContent({
273
+ className,
274
+ hideIcon = false,
275
+ payload,
276
+ verticalAlign = "bottom",
277
+ nameKey,
278
+ }: React.ComponentProps<"div"> & {
279
+ hideIcon?: boolean
280
+ nameKey?: string
281
+ } & RechartsPrimitive.DefaultLegendContentProps) {
282
+ const { config } = useChart()
283
+
284
+ if (!payload?.length) {
285
+ return null
286
+ }
287
+
288
+ return (
289
+ <div
290
+ className={cn(
291
+ "flex items-center justify-center gap-4",
292
+ verticalAlign === "top" ? "pb-3" : "pt-3",
293
+ className
294
+ )}
295
+ >
296
+ {payload
297
+ .filter((item) => item.type !== "none")
298
+ .map((item, index) => {
299
+ const key = `${nameKey ?? item.dataKey ?? "value"}`
300
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
301
+
302
+ return (
303
+ <div
304
+ key={index}
305
+ className={cn(
306
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
307
+ )}
308
+ >
309
+ {itemConfig?.icon && !hideIcon ? (
310
+ <itemConfig.icon />
311
+ ) : (
312
+ <div
313
+ className="h-2 w-2 shrink-0 rounded-[2px]"
314
+ style={{
315
+ backgroundColor: item.color,
316
+ }}
317
+ />
318
+ )}
319
+ {itemConfig?.label}
320
+ </div>
321
+ )
322
+ })}
323
+ </div>
324
+ )
325
+ }
326
+
327
+ function getPayloadConfigFromPayload(
328
+ config: ChartConfig,
329
+ payload: unknown,
330
+ key: string
331
+ ) {
332
+ if (typeof payload !== "object" || payload === null) {
333
+ return undefined
334
+ }
335
+
336
+ const payloadPayload =
337
+ "payload" in payload &&
338
+ typeof payload.payload === "object" &&
339
+ payload.payload !== null
340
+ ? payload.payload
341
+ : undefined
342
+
343
+ let configLabelKey: string = key
344
+
345
+ if (
346
+ key in payload &&
347
+ typeof payload[key as keyof typeof payload] === "string"
348
+ ) {
349
+ configLabelKey = payload[key as keyof typeof payload] as string
350
+ } else if (
351
+ payloadPayload &&
352
+ key in payloadPayload &&
353
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
354
+ ) {
355
+ configLabelKey = payloadPayload[
356
+ key as keyof typeof payloadPayload
357
+ ] as string
358
+ }
359
+
360
+ return configLabelKey in config ? config[configLabelKey] : config[key]
361
+ }
362
+
363
+ export {
364
+ ChartContainer,
365
+ ChartTooltip,
366
+ ChartTooltipContent,
367
+ ChartLegend,
368
+ ChartLegendContent,
369
+ ChartStyle,
370
+ }
@@ -0,0 +1,28 @@
1
+ "use client"
2
+
3
+ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
4
+ import { cn } from "@/lib/utils"
5
+ import { CheckIcon, MinusIcon } from "lucide-react"
6
+
7
+ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
8
+ return (
9
+ <CheckboxPrimitive.Root
10
+ data-slot="checkbox"
11
+ className={cn(
12
+ "peer group/checkbox relative flex size-4 shrink-0 items-center justify-center rounded-[5px] border border-transparent bg-fill-3 transition-shadow outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-transparent after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 dark:aria-invalid:aria-checked:border-primary data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground data-indeterminate:text-muted-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary data-checked:focus-visible:border-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
13
+ className
14
+ )}
15
+ {...props}
16
+ >
17
+ <CheckboxPrimitive.Indicator
18
+ data-slot="checkbox-indicator"
19
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
20
+ >
21
+ <CheckIcon className="group-data-indeterminate/checkbox:hidden" />
22
+ <MinusIcon className="hidden group-data-indeterminate/checkbox:block" />
23
+ </CheckboxPrimitive.Indicator>
24
+ </CheckboxPrimitive.Root>
25
+ )
26
+ }
27
+
28
+ export { Checkbox }