Design
llms.txt digitalcrew.tech

Analytics

ChartContainer

The shell every Crew OS chart sits in: it wraps a Recharts 2 chart in a ResponsiveContainer, turns a config object into per-series colour variables and styles axes, grid, tooltip and legend with the theme tokens.

Crew OSAnalyticsDigitalCrew.ChartContainer
ChartContainer · liveOpen

Guidelines#

Use it for analytics cards: activity over time (area, line), volume by stage or channel (bar), shares (pie, radial).

What you provide: config (required), a map from each dataKey to { label, icon?, color } or { label, theme: { light, dark } }; each entry becomes --color-<key>, so series use stroke="var(--color-sent)". theme colours switch on a .dark ancestor. Build the chart from Recharts primitives (in this bundle: DC.Recharts.AreaChart, Area, BarChart, Bar, LineChart, XAxis, CartesianGrid, …). Add ChartTooltip with content={<ChartTooltipContent />} (indicator: dot default, line, dashed; hideLabel, hideIndicator, nameKey, labelKey, formatter) and ChartLegend with ChartLegendContent.

Anatomy: the container defaults to aspect-video and text-xs, so give it a height (h-[240px] w-full). Tick labels are fill-muted-foreground; the default grid stroke becomes border/50; the cursor is border. The tooltip is a bg-background card, rounded-lg, border-border/50, px-2.5 py-1.5, shadow-xl, at least 128px wide, values in font-mono tabular-nums. Legend swatches are 8px squares with 2px corners, 16px apart.

Don't hard-code hex values in series (go through config), or add a second y-axis.

Facts#

GroupAnalytics
ProductCrew OS
Globalwindow.DigitalCrew.ChartContainer
Sourcedigitalcrew-orchestrator: components/ui/chart.tsx
Import in the appimport { ChartContainer } from "@/components/ui/chart";

API#

TypeScript declarations emitted from components/ui/chart.tsx (the module also exports ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent).

declare const THEMES: {
    readonly light: "";
    readonly dark: ".dark";
};
export type ChartConfig = {
    [k in string]: {
        label?: React.ReactNode;
        icon?: React.ComponentType;
    } & ({
        color?: string;
        theme?: never;
    } | {
        color?: never;
        theme: Record<keyof typeof THEMES, string>;
    });
};
declare function ChartContainer({ id, className, children, config, ...props }: React.ComponentProps<"div"> & {
    config: ChartConfig;
    children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>["children"];
}): any;
declare const ChartStyle: ({ id, config }: {
    id: string;
    config: ChartConfig;
}) => any;
declare const ChartTooltip: typeof RechartsPrimitive.Tooltip;
declare function ChartTooltipContent({ active, payload, className, indicator, hideLabel, hideIndicator, label, labelFormatter, labelClassName, formatter, color, nameKey, labelKey, }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> & React.ComponentProps<"div"> & {
    hideLabel?: boolean;
    hideIndicator?: boolean;
    indicator?: "line" | "dot" | "dashed";
    nameKey?: string;
    labelKey?: string;
}): any;
declare const ChartLegend: typeof RechartsPrimitive.Legend;
declare function ChartLegendContent({ className, hideIcon, payload, verticalAlign, nameKey, }: React.ComponentProps<"div"> & Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
    hideIcon?: boolean;
    nameKey?: string;
}): any;
export { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle, };

Example#

The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.

<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons, R = DC.Recharts;
  var data = [
    { day: "Mon", sent: 412, replies: 31 },
    { day: "Tue", sent: 468, replies: 42 },
    { day: "Wed", sent: 455, replies: 38 },
    { day: "Thu", sent: 520, replies: 57 },
    { day: "Fri", sent: 498, replies: 49 },
    { day: "Sat", sent: 120, replies: 9 },
    { day: "Sun", sent: 96, replies: 14 }
  ];
  var config = {
    sent: { label: "Emails sent", color: "var(--chart-1)" },
    replies: { label: "Replies", color: "var(--chart-2)" }
  };
  function App() {
    return h("div", { className: "grid gap-3" },
      h("div", null,
        h("p", { className: "text-sm font-medium" }, "Outbound activity"),
        h("p", { className: "text-muted-foreground text-xs" }, "Q3 CFO outreach, last 7 days")),
      h(DC.ChartContainer, { config: config, className: "h-[240px] w-full" },
        h(R.AreaChart, { data: data, margin: { left: 4, right: 12, top: 8 } },
          h(R.CartesianGrid, { vertical: false }),
          h(R.XAxis, { dataKey: "day", tickLine: false, axisLine: false, tickMargin: 8 }),
          h(R.YAxis, { tickLine: false, axisLine: false, width: 32 }),
          h(DC.ChartTooltip, { defaultIndex: 3, content: h(DC.ChartTooltipContent, { indicator: "line" }) }),
          h(R.Area, { dataKey: "sent", type: "monotone", stroke: "var(--color-sent)", strokeWidth: 2, fill: "var(--color-sent)", fillOpacity: 0.12 }),
          h(R.Area, { dataKey: "replies", type: "monotone", stroke: "var(--color-replies)", strokeWidth: 2, fill: "var(--color-replies)", fillOpacity: 0.2 }),
          h(DC.ChartLegend, { content: h(DC.ChartLegendContent) }))));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>