From d8981256117d54a5f70dd7237c3c225e64c580d4 Mon Sep 17 00:00:00 2001 From: Dominik Stumpf Date: Thu, 18 Jul 2024 22:44:48 +0200 Subject: [PATCH 01/87] feat: add chart and start profile page --- package.json | 2 + src/app/(marketing)/profile/page.tsx | 69 +++++- src/app/globals.css | 12 + src/v2/components/ui/Chart.tsx | 351 +++++++++++++++++++++++++++ 4 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 src/v2/components/ui/Chart.tsx diff --git a/package.json b/package.json index 8346d65f69..e03e195ed6 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "jotai": "^2.7.0", "js-confetti": "^0.11.0", "lexical": "^0.12.0", + "lucide-react": "^0.408.0", "mini-svg-data-uri": "^1.4.4", "next": "^14.2.4", "next-themes": "^0.3.0", @@ -109,6 +110,7 @@ "react-markdown": "^8.0.7", "react-papaparse": "^4.4.0", "react-window": "^1.8.8", + "recharts": "^2.12.7", "remark-gfm": "^4.0.0", "slugify": "^1.6.5", "swr": "^2.2.4", diff --git a/src/app/(marketing)/profile/page.tsx b/src/app/(marketing)/profile/page.tsx index 50f5e2c58a..59704faa69 100644 --- a/src/app/(marketing)/profile/page.tsx +++ b/src/app/(marketing)/profile/page.tsx @@ -1,5 +1,72 @@ +"use client" + +import { Layout } from "@/components/Layout" +import { Avatar, AvatarFallback } from "@/components/ui/Avatar" +import { ChartConfig, ChartContainer } from "@/components/ui/Chart" +import { PolarGrid, PolarRadiusAxis, RadialBar, RadialBarChart } from "recharts" + +const chartData = [{ browser: "safari", visitors: 200, fill: "hsl(var(--primary))" }] + +const chartConfig = { + visitors: { + label: "Visitors", + }, + safari: { + label: "Safari", + color: "hsl(var(--chart-2))", + }, +} satisfies ChartConfig + const Page = () => { - return <>profile + return ( + + + + +
+ + + +
+
+ + + + + + + + + # + +
+

+ Maximillian Xiaohua Longname +

+
@stephaniexixo11
+

+ This is a description that perfectly matches the 80 character description + limit. +

+
+
+ + ) } // biome-ignore lint/style/noDefaultExport: page route diff --git a/src/app/globals.css b/src/app/globals.css index 474ecd15ab..28da18b552 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -112,6 +112,12 @@ --md: 768px; --lg: 1024px; --xl: 1280px; + + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; } :root[data-theme="dark"] { @@ -207,6 +213,12 @@ --polygonid-active: 262 81% 77%; --farcaster-hover: 239 75% 75%; --farcaster-active: 238 76% 81%; + + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; } } diff --git a/src/v2/components/ui/Chart.tsx b/src/v2/components/ui/Chart.tsx new file mode 100644 index 0000000000..642228c89c --- /dev/null +++ b/src/v2/components/ui/Chart.tsx @@ -0,0 +1,351 @@ +"use client" + +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 ( +