repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | "use client" |
| #2 | |
| #3 | import * as React from "react" |
| #4 | import * as RechartsPrimitive from "recharts" |
| #5 | |
| #6 | import { cn } from "@/lib/utils" |
| #7 | |
| #8 | // Format: { THEME_NAME: CSS_SELECTOR } |
| #9 | const THEMES = { light: "", dark: ".dark" } as const |
| #10 | |
| #11 | export type ChartConfig = { |
| #12 | [k in string]: { |
| #13 | label?: React.ReactNode |
| #14 | icon?: React.ComponentType |
| #15 | } & ( |
| #16 | | { color?: string; theme?: never } |
| #17 | | { color?: never; theme: Record<keyof typeof THEMES, string> } |
| #18 | ) |
| #19 | } |
| #20 | |
| #21 | type ChartContextProps = { |
| #22 | config: ChartConfig |
| #23 | } |
| #24 | |
| #25 | const ChartContext = React.createContext<ChartContextProps | null>(null) |
| #26 | |
| #27 | function useChart() { |
| #28 | const context = React.useContext(ChartContext) |
| #29 | |
| #30 | if (!context) { |
| #31 | throw new Error("useChart must be used within a <ChartContainer />") |
| #32 | } |
| #33 | |
| #34 | return context |
| #35 | } |
| #36 | |
| #37 | const ChartContainer = React.forwardRef< |
| #38 | HTMLDivElement, |
| #39 | React.ComponentProps<"div"> & { |
| #40 | config: ChartConfig |
| #41 | children: React.ComponentProps< |
| #42 | typeof RechartsPrimitive.ResponsiveContainer |
| #43 | >["children"] |
| #44 | } |
| #45 | >(({ id, className, children, config, ...props }, ref) => { |
| #46 | const uniqueId = React.useId() |
| #47 | const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` |
| #48 | |
| #49 | return ( |
| #50 | <ChartContext.Provider value={{ config }}> |
| #51 | <div |
| #52 | data-chart={chartId} |
| #53 | ref={ref} |
| #54 | className={cn( |
| #55 | "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", |
| #56 | className |
| #57 | )} |
| #58 | {...props} |
| #59 | > |
| #60 | <ChartStyle id={chartId} config={config} /> |
| #61 | <RechartsPrimitive.ResponsiveContainer> |
| #62 | {children} |
| #63 | </RechartsPrimitive.ResponsiveContainer> |
| #64 | </div> |
| #65 | </ChartContext.Provider> |
| #66 | ) |
| #67 | }) |
| #68 | ChartContainer.displayName = "Chart" |
| #69 | |
| #70 | const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { |
| #71 | const colorConfig = Object.entries(config).filter( |
| #72 | ([_, config]) => config.theme || config.color |
| #73 | ) |
| #74 | |
| #75 | if (!colorConfig.length) { |
| #76 | return null |
| #77 | } |
| #78 | |
| #79 | return ( |
| #80 | <style |
| #81 | dangerouslySetInnerHTML={{ |
| #82 | __html: Object.entries(THEMES) |
| #83 | .map( |
| #84 | ([theme, prefix]) => ` |
| #85 | ${prefix} [data-chart=${id}] { |
| #86 | ${colorConfig |
| #87 | .map(([key, itemConfig]) => { |
| #88 | const color = |
| #89 | itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || |
| #90 | itemConfig.color |
| #91 | return color ? ` --color-${key}: ${color};` : null |
| #92 | }) |
| #93 | .join("\n")} |
| #94 | } |
| #95 | ` |
| #96 | ) |
| #97 | .join("\n"), |
| #98 | }} |
| #99 | /> |
| #100 | ) |
| #101 | } |
| #102 | |
| #103 | const ChartTooltip = RechartsPrimitive.Tooltip |
| #104 | |
| #105 | const ChartTooltipContent = React.forwardRef< |
| #106 | HTMLDivElement, |
| #107 | React.ComponentProps<typeof RechartsPrimitive.Tooltip> & |
| #108 | React.ComponentProps<"div"> & { |
| #109 | hideLabel?: boolean |
| #110 | hideIndicator?: boolean |
| #111 | indicator?: "line" | "dot" | "dashed" |
| #112 | nameKey?: string |
| #113 | labelKey?: string |
| #114 | } |
| #115 | >( |
| #116 | ( |
| #117 | { |
| #118 | active, |
| #119 | payload, |
| #120 | className, |
| #121 | indicator = "dot", |
| #122 | hideLabel = false, |
| #123 | hideIndicator = false, |
| #124 | label, |
| #125 | labelFormatter, |
| #126 | labelClassName, |
| #127 | formatter, |
| #128 | color, |
| #129 | nameKey, |
| #130 | labelKey, |
| #131 | }, |
| #132 | ref |
| #133 | ) => { |
| #134 | const { config } = useChart() |
| #135 | |
| #136 | const tooltipLabel = React.useMemo(() => { |
| #137 | if (hideLabel || !payload?.length) { |
| #138 | return null |
| #139 | } |
| #140 | |
| #141 | const [item] = payload |
| #142 | const key = `${labelKey || item.dataKey || item.name || "value"}` |
| #143 | const itemConfig = getPayloadConfigFromPayload(config, item, key) |
| #144 | const value = |
| #145 | !labelKey && typeof label === "string" |
| #146 | ? config[label as keyof typeof config]?.label || label |
| #147 | : itemConfig?.label |
| #148 | |
| #149 | if (labelFormatter) { |
| #150 | return ( |
| #151 | <div className={cn("font-medium", labelClassName)}> |
| #152 | {labelFormatter(value, payload)} |
| #153 | </div> |
| #154 | ) |
| #155 | } |
| #156 | |
| #157 | if (!value) { |
| #158 | return null |
| #159 | } |
| #160 | |
| #161 | return <div className={cn("font-medium", labelClassName)}>{value}</div> |
| #162 | }, [ |
| #163 | label, |
| #164 | labelFormatter, |
| #165 | payload, |
| #166 | hideLabel, |
| #167 | labelClassName, |
| #168 | config, |
| #169 | labelKey, |
| #170 | ]) |
| #171 | |
| #172 | if (!active || !payload?.length) { |
| #173 | return null |
| #174 | } |
| #175 | |
| #176 | const nestLabel = payload.length === 1 && indicator !== "dot" |
| #177 | |
| #178 | return ( |
| #179 | <div |
| #180 | ref={ref} |
| #181 | className={cn( |
| #182 | "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", |
| #183 | className |
| #184 | )} |
| #185 | > |
| #186 | {!nestLabel ? tooltipLabel : null} |
| #187 | <div className="grid gap-1.5"> |
| #188 | {payload.map((item, index) => { |
| #189 | const key = `${nameKey || item.name || item.dataKey || "value"}` |
| #190 | const itemConfig = getPayloadConfigFromPayload(config, item, key) |
| #191 | const indicatorColor = color || item.payload.fill || item.color |
| #192 | |
| #193 | return ( |
| #194 | <div |
| #195 | key={item.dataKey} |
| #196 | className={cn( |
| #197 | "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground", |
| #198 | indicator === "dot" && "items-center" |
| #199 | )} |
| #200 | > |
| #201 | {formatter && item?.value !== undefined && item.name ? ( |
| #202 | formatter(item.value, item.name, item, index, item.payload) |
| #203 | ) : ( |
| #204 | <> |
| #205 | {itemConfig?.icon ? ( |
| #206 | <itemConfig.icon /> |
| #207 | ) : ( |
| #208 | !hideIndicator && ( |
| #209 | <div |
| #210 | className={cn( |
| #211 | "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]", |
| #212 | { |
| #213 | "h-2.5 w-2.5": indicator === "dot", |
| #214 | "w-1": indicator === "line", |
| #215 | "w-0 border-[1.5px] border-dashed bg-transparent": |
| #216 | indicator === "dashed", |
| #217 | "my-0.5": nestLabel && indicator === "dashed", |
| #218 | } |
| #219 | )} |
| #220 | style={ |
| #221 | { |
| #222 | "--color-bg": indicatorColor, |
| #223 | "--color-border": indicatorColor, |
| #224 | } as React.CSSProperties |
| #225 | } |
| #226 | /> |
| #227 | ) |
| #228 | )} |
| #229 | <div |
| #230 | className={cn( |
| #231 | "flex flex-1 justify-between leading-none", |
| #232 | nestLabel ? "items-end" : "items-center" |
| #233 | )} |
| #234 | > |
| #235 | <div className="grid gap-1.5"> |
| #236 | {nestLabel ? tooltipLabel : null} |
| #237 | <span className="text-muted-foreground"> |
| #238 | {itemConfig?.label || item.name} |
| #239 | </span> |
| #240 | </div> |
| #241 | {item.value && ( |
| #242 | <span className="font-mono font-medium tabular-nums text-foreground"> |
| #243 | {item.value.toLocaleString()} |
| #244 | </span> |
| #245 | )} |
| #246 | </div> |
| #247 | </> |
| #248 | )} |
| #249 | </div> |
| #250 | ) |
| #251 | })} |
| #252 | </div> |
| #253 | </div> |
| #254 | ) |
| #255 | } |
| #256 | ) |
| #257 | ChartTooltipContent.displayName = "ChartTooltip" |
| #258 | |
| #259 | const ChartLegend = RechartsPrimitive.Legend |
| #260 | |
| #261 | const ChartLegendContent = React.forwardRef< |
| #262 | HTMLDivElement, |
| #263 | React.ComponentProps<"div"> & |
| #264 | Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & { |
| #265 | hideIcon?: boolean |
| #266 | nameKey?: string |
| #267 | } |
| #268 | >( |
| #269 | ( |
| #270 | { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey }, |
| #271 | ref |
| #272 | ) => { |
| #273 | const { config } = useChart() |
| #274 | |
| #275 | if (!payload?.length) { |
| #276 | return null |
| #277 | } |
| #278 | |
| #279 | return ( |
| #280 | <div |
| #281 | ref={ref} |
| #282 | className={cn( |
| #283 | "flex items-center justify-center gap-4", |
| #284 | verticalAlign === "top" ? "pb-3" : "pt-3", |
| #285 | className |
| #286 | )} |
| #287 | > |
| #288 | {payload.map((item) => { |
| #289 | const key = `${nameKey || item.dataKey || "value"}` |
| #290 | const itemConfig = getPayloadConfigFromPayload(config, item, key) |
| #291 | |
| #292 | return ( |
| #293 | <div |
| #294 | key={item.value} |
| #295 | className={cn( |
| #296 | "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground" |
| #297 | )} |
| #298 | > |
| #299 | {itemConfig?.icon && !hideIcon ? ( |
| #300 | <itemConfig.icon /> |
| #301 | ) : ( |
| #302 | <div |
| #303 | className="h-2 w-2 shrink-0 rounded-[2px]" |
| #304 | style={{ |
| #305 | backgroundColor: item.color, |
| #306 | }} |
| #307 | /> |
| #308 | )} |
| #309 | {itemConfig?.label} |
| #310 | </div> |
| #311 | ) |
| #312 | })} |
| #313 | </div> |
| #314 | ) |
| #315 | } |
| #316 | ) |
| #317 | ChartLegendContent.displayName = "ChartLegend" |
| #318 | |
| #319 | // Helper to extract item config from a payload. |
| #320 | function getPayloadConfigFromPayload( |
| #321 | config: ChartConfig, |
| #322 | payload: unknown, |
| #323 | key: string |
| #324 | ) { |
| #325 | if (typeof payload !== "object" || payload === null) { |
| #326 | return undefined |
| #327 | } |
| #328 | |
| #329 | const payloadPayload = |
| #330 | "payload" in payload && |
| #331 | typeof payload.payload === "object" && |
| #332 | payload.payload !== null |
| #333 | ? payload.payload |
| #334 | : undefined |
| #335 | |
| #336 | let configLabelKey: string = key |
| #337 | |
| #338 | if ( |
| #339 | key in payload && |
| #340 | typeof payload[key as keyof typeof payload] === "string" |
| #341 | ) { |
| #342 | configLabelKey = payload[key as keyof typeof payload] as string |
| #343 | } else if ( |
| #344 | payloadPayload && |
| #345 | key in payloadPayload && |
| #346 | typeof payloadPayload[key as keyof typeof payloadPayload] === "string" |
| #347 | ) { |
| #348 | configLabelKey = payloadPayload[ |
| #349 | key as keyof typeof payloadPayload |
| #350 | ] as string |
| #351 | } |
| #352 | |
| #353 | return configLabelKey in config |
| #354 | ? config[configLabelKey] |
| #355 | : config[key as keyof typeof config] |
| #356 | } |
| #357 | |
| #358 | export { |
| #359 | ChartContainer, |
| #360 | ChartTooltip, |
| #361 | ChartTooltipContent, |
| #362 | ChartLegend, |
| #363 | ChartLegendContent, |
| #364 | ChartStyle, |
| #365 | } |
| #366 |