diff --git a/components/retroui/charts/StackedBarChart.tsx b/components/retroui/charts/StackedBarChart.tsx new file mode 100644 index 0000000..32c4367 --- /dev/null +++ b/components/retroui/charts/StackedBarChart.tsx @@ -0,0 +1,182 @@ +"use client" + +import { cn } from "@/lib/utils" +import React from "react" +import { + Bar, + BarChart as RechartsBarChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, + Legend, +} from "recharts" + +interface StackedBarChartProps extends React.HTMLAttributes { + data: Record[] + index: string + categories: string[] + strokeColors?: string[] + fillColors?: string[] + tooltipBgColor?: string + tooltipBorderColor?: string + gridColor?: string + valueFormatter?: (value: number) => string + showGrid?: boolean + showTooltip?: boolean + showLegend?: boolean + alignment?: "vertical" | "horizontal" + className?: string +} + +const StackedBarChart = React.forwardRef( + ( + { + data = [], + index, + categories = [], + strokeColors = ["var(--foreground)"], + fillColors = ["var(--primary)", "var(--secondary)", "var(--accent)"], + tooltipBgColor = "var(--background)", + tooltipBorderColor = "var(--border)", + gridColor = "var(--muted)", + valueFormatter = (value: number) => value.toString(), + showGrid = true, + showTooltip = true, + showLegend = true, + alignment = "vertical", + className, + ...props + }, + ref + ) => { + return ( +
+ + + {showGrid && ( + + )} + + {alignment === "horizontal" ? ( + <> + + + + + ) : ( + <> + + + + + )} + + {showTooltip && ( + { + if (!active || !payload?.length) return null + + return ( +
+
+
+ + {index} + + + {label} + +
+
+ {payload.map((entry, idx) => ( +
+
+
+ + {entry.dataKey} + +
+ + {entry.value != null ? valueFormatter(entry.value as number) : '-'} + +
+ ))} +
+
+
+ ) + }} + /> + )} + + {showLegend && ( + + )} + + {categories.map((category, i) => { + const fillColor = fillColors[i % fillColors.length] + const strokeColor = strokeColors[i % strokeColors.length] || strokeColors[0] + + return ( + + ) + })} + + +
+ ) + } +) + +StackedBarChart.displayName = "StackedBarChart" + +export { StackedBarChart, type StackedBarChartProps } diff --git a/config/components.ts b/config/components.ts index 0128975..301410a 100644 --- a/config/components.ts +++ b/config/components.ts @@ -60,6 +60,10 @@ export const componentConfig: { name: "barChart", filePath: "components/retroui/charts/BarChart.tsx", }, + stackedBarChart: { + name: "stackedBarChart", + filePath: "components/retroui/charts/StackedBarChart.tsx", + }, carousel: { name: "carousel", filePath: "components/retroui/Carousel.tsx", @@ -260,6 +264,26 @@ export const componentConfig: { () => import("@/preview/charts/bar-chart-style-horizontal"), ), }, + "stacked-bar-chart-style-default": { + name: "stacked-bar-chart-style-default", + filePath: "preview/charts/stacked-bar-chart-style-default.tsx", + preview: lazy(() => import("@/preview/charts/stacked-bar-chart-style-default")), + }, + "stacked-bar-chart-style-horizontal": { + name: "stacked-bar-chart-style-horizontal", + filePath: "preview/charts/stacked-bar-chart-style-horizontal.tsx", + preview: lazy(() => import("@/preview/charts/stacked-bar-chart-style-horizontal")), + }, + "stacked-bar-chart-style-no-legend": { + name: "stacked-bar-chart-style-no-legend", + filePath: "preview/charts/stacked-bar-chart-style-no-legend.tsx", + preview: lazy(() => import("@/preview/charts/stacked-bar-chart-style-no-legend")), + }, + "stacked-bar-chart-style-formatted": { + name: "stacked-bar-chart-style-formatted", + filePath: "preview/charts/stacked-bar-chart-style-formatted.tsx", + preview: lazy(() => import("@/preview/charts/stacked-bar-chart-style-formatted")), + }, "button-style-default": { name: "button-style-default", filePath: "preview/components/button-style-default.tsx", diff --git a/config/navigation.ts b/config/navigation.ts index 070f7bb..d36cd60 100644 --- a/config/navigation.ts +++ b/config/navigation.ts @@ -97,6 +97,7 @@ export const navConfig: INavigationConfig = { title: "Chart", children: [ { title: "Bar Chart", href: `${chartsRoute}/bar-chart` }, + { title: "Stacked Bar Chart", href: `${chartsRoute}/stacked-bar-chart` }, { title: "Line Chart", href: `${chartsRoute}/line-chart` }, { title: "Area Chart", href: `${chartsRoute}/area-chart` }, { title: "Pie Chart", href: `${chartsRoute}/pie-chart` }, diff --git a/content/docs/charts/stacked-bar-chart.mdx b/content/docs/charts/stacked-bar-chart.mdx new file mode 100644 index 0000000..25214ae --- /dev/null +++ b/content/docs/charts/stacked-bar-chart.mdx @@ -0,0 +1,160 @@ +--- +title: Stacked Bar Chart +description: A customizable stacked bar chart component to visualize comparative data across categories with support for stacking, custom colors, and horizontal alignment. 📊 +lastUpdated: 03 Dec, 2025 +links: + source: https://github.com/Logging-Studio/RetroUI/blob/main/components/retroui/charts/StackedBarChart.tsx +--- + + +
+
+ +## Installation + + + + + +#### 1. Install dependencies: + +```sh +npm install recharts +``` + +
+ +#### 2. Copy the code 👇 into your project: + + + +
+
+ +
+
+ +## Examples + +### Default + + +
+
+ +### Horizontal Alignment + + +
+
+ +### Without Legend + + +
+
+ +### With Formatted Values + + +
+
+ +## API Reference + + + + + Prop + Type + Default + Description + + + + + data + `Record[]` + `[]` + Array of data objects to display + + + index + `string` + - + Key for the x-axis (category) data + + + categories + `string[]` + `[]` + Array of keys for the data values to stack in bars + + + alignment + `"vertical" | "horizontal"` + `"vertical"` + Orientation of the bars + + + strokeColors + `string[]` + `["var(--foreground)"]` + Array of stroke colors for the bars + + + fillColors + `string[]` + `["var(--primary)", "var(--secondary)", "var(--accent)"]` + Array of fill colors for the stacked bars + + + tooltipBgColor + `string` + `"var(--background)"` + Background color for tooltips + + + tooltipBorderColor + `string` + `"var(--border)"` + Border color for tooltips + + + gridColor + `string` + `"var(--muted)"` + Color for the grid lines + + + valueFormatter + `(value: number) => string` + `(value) => value.toString()` + Function to format values + + + showGrid + `boolean` + `true` + Whether to show grid lines + + + showTooltip + `boolean` + `true` + Whether to show tooltips on hover + + + showLegend + `boolean` + `true` + Whether to show the legend for categories + + + className + `string` + - + Additional CSS classes + + +
\ No newline at end of file diff --git a/preview/charts/stacked-bar-chart-style-default.tsx b/preview/charts/stacked-bar-chart-style-default.tsx new file mode 100644 index 0000000..c89bd03 --- /dev/null +++ b/preview/charts/stacked-bar-chart-style-default.tsx @@ -0,0 +1,21 @@ +import { StackedBarChart } from "@/components/retroui/charts/StackedBarChart"; + +const data = [ + { name: 'Jan', sales: 12, marketing: 9, support: 5 }, + { name: 'Feb', sales: 32, marketing: 19, support: 8 }, + { name: 'Mar', sales: 19, marketing: 8, support: 12 }, + { name: 'Apr', sales: 35, marketing: 14, support: 6 }, + { name: 'May', sales: 40, marketing: 12, support: 9 }, + { name: 'Jun', sales: 25, marketing: 5, support: 15 } +]; + +export default function StackedBarChartStyleDefault() { + return ( + + ) +} diff --git a/preview/charts/stacked-bar-chart-style-formatted.tsx b/preview/charts/stacked-bar-chart-style-formatted.tsx new file mode 100644 index 0000000..bf379c8 --- /dev/null +++ b/preview/charts/stacked-bar-chart-style-formatted.tsx @@ -0,0 +1,23 @@ +import { StackedBarChart } from "@/components/retroui/charts/StackedBarChart"; + +const data = [ + { name: 'Mon', active: 4000, inactive: 2400, pending: 1400 }, + { name: 'Tue', active: 3000, inactive: 1398, pending: 2210 }, + { name: 'Wed', active: 2000, inactive: 9800, pending: 2290 }, + { name: 'Thu', active: 2780, inactive: 3908, pending: 2000 }, + { name: 'Fri', active: 1890, inactive: 4800, pending: 2181 }, + { name: 'Sat', active: 2390, inactive: 3800, pending: 2500 }, + { name: 'Sun', active: 3490, inactive: 4300, pending: 2100 } +]; + +export default function StackedBarChartStyleFormatted() { + return ( + `${(value / 1000).toFixed(1)}k`} + /> + ) +} diff --git a/preview/charts/stacked-bar-chart-style-horizontal.tsx b/preview/charts/stacked-bar-chart-style-horizontal.tsx new file mode 100644 index 0000000..daba6ed --- /dev/null +++ b/preview/charts/stacked-bar-chart-style-horizontal.tsx @@ -0,0 +1,21 @@ +import { StackedBarChart } from "@/components/retroui/charts/StackedBarChart"; + +const data = [ + { category: 'Q1', revenue: 400, expenses: 240, profit: 160 }, + { category: 'Q2', revenue: 300, expenses: 139, profit: 161 }, + { category: 'Q3', revenue: 200, expenses: 100, profit: 100 }, + { category: 'Q4', revenue: 500, expenses: 300, profit: 200 } +]; + +export default function StackedBarChartStyleHorizontal() { + return ( + + ) +} diff --git a/preview/charts/stacked-bar-chart-style-no-legend.tsx b/preview/charts/stacked-bar-chart-style-no-legend.tsx new file mode 100644 index 0000000..e38982a --- /dev/null +++ b/preview/charts/stacked-bar-chart-style-no-legend.tsx @@ -0,0 +1,22 @@ +import { StackedBarChart } from "@/components/retroui/charts/StackedBarChart"; + +const data = [ + { month: 'Jan', product_a: 45, product_b: 32, product_c: 23 }, + { month: 'Feb', product_a: 52, product_b: 41, product_c: 18 }, + { month: 'Mar', product_a: 38, product_b: 29, product_c: 31 }, + { month: 'Apr', product_a: 61, product_b: 38, product_c: 25 }, + { month: 'May', product_a: 55, product_b: 45, product_c: 20 }, + { month: 'Jun', product_a: 48, product_b: 36, product_c: 28 } +]; + +export default function StackedBarChartStyleNoLegend() { + return ( + + ) +} diff --git a/public/r/stacked-bar-chart.json b/public/r/stacked-bar-chart.json new file mode 100644 index 0000000..b7ab2f6 --- /dev/null +++ b/public/r/stacked-bar-chart.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "stacked-bar-chart", + "type": "registry:component", + "title": "Stacked Bar Chart", + "description": "Beautiful stacked bar chart for data visualization with retro styling", + "dependencies": [ + "recharts" + ], + "files": [ + { + "path": "components/retroui/charts/StackedBarChart.tsx", + "content": "\"use client\"\n\nimport { cn } from \"@/lib/utils\"\nimport React from \"react\"\nimport {\n Bar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n Legend,\n} from \"recharts\"\n\ninterface StackedBarChartProps extends React.HTMLAttributes {\n data: Record[]\n index: string\n categories: string[]\n strokeColors?: string[]\n fillColors?: string[]\n tooltipBgColor?: string\n tooltipBorderColor?: string\n gridColor?: string\n valueFormatter?: (value: number) => string\n showGrid?: boolean\n showTooltip?: boolean\n showLegend?: boolean\n alignment?: \"vertical\" | \"horizontal\"\n className?: string\n}\n\nconst StackedBarChart = React.forwardRef(\n (\n {\n data = [],\n index,\n categories = [],\n strokeColors = [\"var(--foreground)\"],\n fillColors = [\"var(--primary)\", \"var(--secondary)\", \"var(--accent)\"],\n tooltipBgColor = \"var(--background)\",\n tooltipBorderColor = \"var(--border)\",\n gridColor = \"var(--muted)\",\n valueFormatter = (value: number) => value.toString(),\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n alignment = \"vertical\",\n className,\n ...props\n },\n ref\n ) => {\n return (\n
\n \n \n {showGrid && (\n \n )}\n\n {alignment === \"horizontal\" ? (\n <>\n \n\n \n \n ) : (\n <>\n \n\n \n \n )}\n\n {showTooltip && (\n {\n if (!active || !payload?.length) return null\n\n return (\n \n
\n
\n \n {index}\n \n \n {label}\n \n
\n
\n {payload.map((entry, idx) => (\n
\n
\n \n \n {entry.dataKey}\n \n
\n \n {valueFormatter(entry.value as number)}\n \n
\n ))}\n
\n
\n
\n )\n }}\n />\n )}\n\n {showLegend && (\n \n )}\n\n {categories.map((category, index) => {\n const fillColor = fillColors[index % fillColors.length]\n const strokeColor = strokeColors[index % strokeColors.length] || strokeColors[0]\n\n return (\n \n )\n })}\n
\n
\n
\n )\n }\n)\n\nStackedBarChart.displayName = \"StackedBarChart\"\n\nexport { StackedBarChart, type StackedBarChartProps }\n", + "type": "registry:component", + "target": "components/retroui/charts/StackedBarChart.tsx" + } + ] +} \ No newline at end of file