diff --git a/apps/client/app/app.css b/apps/client/app/app.css index 79df160..b075dba 100644 --- a/apps/client/app/app.css +++ b/apps/client/app/app.css @@ -135,3 +135,21 @@ body { @apply bg-background text-foreground; } } + +@layer base { + :root { + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + } + + .dark { + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + } +} diff --git a/apps/client/app/components/edit-volume-dialog.tsx b/apps/client/app/components/edit-volume-dialog.tsx index ee64646..2ca4405 100644 --- a/apps/client/app/components/edit-volume-dialog.tsx +++ b/apps/client/app/components/edit-volume-dialog.tsx @@ -1,9 +1,9 @@ import { useMutation } from "@tanstack/react-query"; import { useId } from "react"; import { toast } from "sonner"; -import type { GetVolumeResponse } from "~/api-client"; import { updateVolumeMutation } from "~/api-client/@tanstack/react-query.gen"; import { parseError } from "~/lib/errors"; +import type { Volume } from "../lib/types"; import { CreateVolumeForm } from "./create-volume-form"; import { Button } from "./ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "./ui/dialog"; @@ -11,7 +11,7 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D type Props = { open: boolean; setOpen: (open: boolean) => void; - initialValues?: Partial; + initialValues?: Partial; }; export const EditVolumeDialog = ({ open, setOpen, initialValues }: Props) => { diff --git a/apps/client/app/components/ui/chart.tsx b/apps/client/app/components/ui/chart.tsx new file mode 100644 index 0000000..d0d0984 --- /dev/null +++ b/apps/client/app/components/ui/chart.tsx @@ -0,0 +1,355 @@ +import * as React from "react" +import * as RechartsPrimitive from "recharts" + +import { cn } from "~/lib/utils" + +// Format: { THEME_NAME: CSS_SELECTOR } +const THEMES = { light: "", dark: ".dark" } as const + +export type ChartConfig = { + [k in string]: { + label?: React.ReactNode + icon?: React.ComponentType + } & ( + | { color?: string; theme?: never } + | { color?: never; theme: Record } + ) +} + +type ChartContextProps = { + config: ChartConfig +} + +const ChartContext = React.createContext(null) + +function useChart() { + const context = React.useContext(ChartContext) + + if (!context) { + throw new Error("useChart must be used within a ") + } + + return context +} + +function ChartContainer({ + id, + className, + children, + config, + ...props +}: React.ComponentProps<"div"> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"] +}) { + const uniqueId = React.useId() + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + + return ( + +
+ + + {children} + +
+
+ ) +} + +const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { + const colorConfig = Object.entries(config).filter( + ([, config]) => config.theme || config.color + ) + + if (!colorConfig.length) { + return null + } + + return ( +