diff --git a/apps/web/app/components/Gravatar.tsx b/apps/web/app/components/Gravatar.tsx index 7c6d8b593..c84f8a63e 100644 --- a/apps/web/app/components/Gravatar.tsx +++ b/apps/web/app/components/Gravatar.tsx @@ -3,19 +3,21 @@ import CryptoJS from "crypto-js"; import { AvatarImage } from "./ui/avatar"; type GravatarProps = { - email: string; + email: string | undefined; size?: number; className?: string; }; export const Gravatar = ({ email, size = 200, className = "" }: GravatarProps) => { - const hash = CryptoJS.MD5(email.toLowerCase().trim()).toString(); + const defaultGravatarHash = "27205e5c51cb03f862138b22bcb5dc20f94a342e744ff6df1b8dc8af3c865109"; + + const hash = email ? CryptoJS.MD5(email.toLowerCase().trim()).toString() : defaultGravatarHash; const gravatarUrl = `https://www.gravatar.com/avatar/${hash}?s=${size}&d=mp`; return ( ; + +function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) { + return ( +
, + NextMonthButton: ({ ...props }) =>
, + }} + {...props} + /> + ); +} +Calendar.displayName = "Calendar"; + +export { Calendar }; diff --git a/apps/web/app/components/ui/chart.tsx b/apps/web/app/components/ui/chart.tsx new file mode 100644 index 000000000..6a21c68de --- /dev/null +++ b/apps/web/app/components/ui/chart.tsx @@ -0,0 +1,363 @@ +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 +} + +const ChartContainer = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"] + } +>(({ id, className, children, config, ...props }, ref) => { + const uniqueId = React.useId() + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + + return ( + +
+ + + {children} + +
+
+ ) +}) +ChartContainer.displayName = "Chart" + +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 ( +