Skip to content

Commit 31ae615

Browse files
authored
feat: add area chart options to theme builder (#2967)
1 parent a63cb04 commit 31ae615

File tree

7 files changed

+191
-83
lines changed

7 files changed

+191
-83
lines changed

demo/ts/components/theme-builder/color-picker.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type ColorPickerProps = {
88
id: string;
99
onColorChange: (color: string) => void;
1010
showColorName?: boolean;
11+
className?: string;
1112
};
1213

1314
const ColorPicker = ({
@@ -16,6 +17,7 @@ const ColorPicker = ({
1617
id,
1718
onColorChange,
1819
showColorName = false,
20+
className,
1921
}: ColorPickerProps) => {
2022
const [isPickerOpen, setIsPickerOpen] = React.useState(false);
2123

@@ -26,7 +28,7 @@ const ColorPicker = ({
2628
};
2729

2830
return (
29-
<fieldset>
31+
<fieldset className={className}>
3032
{label && (
3133
<label className="block mb-1 text-sm text-gray-900 dark:text-white font-bold">
3234
{label}

demo/ts/components/theme-builder/color-scale-options.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const ColorScaleOptions = ({
5959
label="Color Scale"
6060
className="mb-5"
6161
/>
62-
<div className="flex flex-wrap gap-3 mb-5">
62+
<div className="flex flex-wrap gap-3">
6363
{palette?.[activeColorScale as string]?.map((color, i) => (
6464
<ColorPicker
6565
key={i}

demo/ts/components/theme-builder/config-mapper.tsx

Lines changed: 103 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import ColorPicker from "./color-picker";
77
import ColorScaleOptions from "./color-scale-options";
88
import { getConfigValue } from "./utils";
99

10-
const ConfigMapper = ({
10+
const ControlComponent = ({
11+
type,
12+
field,
1113
themeConfig,
12-
activeColorScale,
1314
updateThemeConfig,
15+
activeColorScale,
1416
handleColorScaleChange,
17+
className,
1518
}) => {
1619
const handleColorChange = ({ newColor, index, colorScale }) => {
1720
const updatedColors = themeConfig?.palette?.[colorScale]?.map((color, i) =>
@@ -20,6 +23,91 @@ const ConfigMapper = ({
2023
updateThemeConfig(`palette.${colorScale}`, updatedColors);
2124
};
2225

26+
const handleChange = (newValue) => {
27+
updateThemeConfig(field.path, newValue);
28+
};
29+
30+
const configValue = getConfigValue(themeConfig, field.path);
31+
switch (type) {
32+
case "colorScale":
33+
return (
34+
<ColorScaleOptions
35+
palette={themeConfig?.palette}
36+
activeColorScale={activeColorScale}
37+
onColorChange={handleColorChange}
38+
onColorScaleChange={handleColorScaleChange}
39+
/>
40+
);
41+
case "section":
42+
return (
43+
<section className="mb-6">
44+
<h3 className="text-lg text-secondary font-bold mb-4">
45+
{field.label}
46+
</h3>
47+
{field.fields.map((subField, i) => (
48+
<ControlComponent
49+
key={subField.label + i}
50+
type={subField.type}
51+
field={subField}
52+
themeConfig={themeConfig}
53+
updateThemeConfig={updateThemeConfig}
54+
activeColorScale={activeColorScale}
55+
handleColorScaleChange={handleColorScaleChange}
56+
className={className}
57+
/>
58+
))}
59+
</section>
60+
);
61+
case "slider":
62+
return (
63+
<Slider
64+
id={field.label}
65+
key={field.label}
66+
label={field.label}
67+
value={configValue as number}
68+
unit={field.unit}
69+
onChange={handleChange}
70+
min={field.min}
71+
max={field.max}
72+
step={field.step}
73+
className={className}
74+
/>
75+
);
76+
case "select":
77+
return (
78+
<Select
79+
id={field.label}
80+
key={field.label}
81+
label={field.label}
82+
value={configValue as string}
83+
onChange={handleChange}
84+
options={field.options}
85+
className={className}
86+
/>
87+
);
88+
case "colorPicker":
89+
return (
90+
<ColorPicker
91+
id={field.label}
92+
key={field.label}
93+
label={field.label}
94+
color={configValue as string}
95+
onColorChange={handleChange}
96+
className={className}
97+
showColorName
98+
/>
99+
);
100+
default:
101+
return null;
102+
}
103+
};
104+
105+
const ConfigMapper = ({
106+
themeConfig,
107+
activeColorScale,
108+
updateThemeConfig,
109+
handleColorScaleChange,
110+
}) => {
23111
return (
24112
<>
25113
{optionsConfig.map((section, index) => (
@@ -29,62 +117,19 @@ const ConfigMapper = ({
29117
id={section.title}
30118
defaultOpen={index === 0}
31119
>
32-
{section.fields.map((field) => {
33-
if (field.type === "colorScale") {
34-
return (
35-
<ColorScaleOptions
36-
key={field.label}
37-
activeColorScale={activeColorScale}
38-
palette={themeConfig?.palette}
39-
onColorChange={handleColorChange}
40-
onColorScaleChange={handleColorScaleChange}
41-
/>
42-
);
43-
}
44-
const configValue = getConfigValue(themeConfig, field.path);
45-
if (field.type === "slider") {
46-
return (
47-
<Slider
48-
id={field.label}
49-
key={field.label}
50-
label={field.label}
51-
value={configValue as number}
52-
unit={field.unit}
53-
onChange={(newValue) =>
54-
updateThemeConfig(field.path, newValue)
55-
}
56-
/>
57-
);
58-
}
59-
if (field.type === "select") {
60-
return (
61-
<Select
62-
id={field.label}
63-
key={field.label}
64-
label={field.label}
65-
value={configValue as string}
66-
options={field.options}
67-
onChange={(newValue) =>
68-
updateThemeConfig(field.path, newValue)
69-
}
70-
/>
71-
);
72-
}
73-
if (field.type === "colorPicker") {
74-
return (
75-
<ColorPicker
76-
id={field.label}
77-
key={field.label}
78-
label={field.label}
79-
color={configValue as string}
80-
onColorChange={(newColor) =>
81-
updateThemeConfig(field.path, newColor)
82-
}
83-
showColorName
84-
/>
85-
);
86-
}
87-
return null;
120+
{section.fields.map((field, i) => {
121+
return (
122+
<ControlComponent
123+
key={field.label + i}
124+
type={field.type}
125+
field={field}
126+
themeConfig={themeConfig}
127+
updateThemeConfig={updateThemeConfig}
128+
activeColorScale={activeColorScale}
129+
handleColorScaleChange={handleColorScaleChange}
130+
className="mb-4"
131+
/>
132+
);
88133
})}
89134
</Accordion>
90135
))}

demo/ts/components/theme-builder/index.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const ThemeBuilder = () => {
112112

113113
return (
114114
<div className="flex flex-row flex-wrap items-start justify-start w-full">
115-
<aside className="relative flex flex-col h-lvh w-[350px] border-r border-gray-200">
115+
<aside className="relative flex flex-col h-full w-[380px] border-r border-gray-200">
116116
<div className="grow overflow-y-auto p-4 pb-[100px]">
117117
<h2 className="mb-0 text-lg font-bold">Customize Your Theme</h2>
118118
<p className="text-sm mb-4 text-gray-300">
@@ -147,7 +147,7 @@ const ThemeBuilder = () => {
147147
</Button>
148148
</footer>
149149
</aside>
150-
<main className="flex-1 flex flex-col items-center">
150+
<main className="flex-1 flex flex-col items-center overflow-y-auto h-full">
151151
{customThemeConfig && (
152152
<div className="max-w-screen-xl w-full py-4 px-10">
153153
<h2 className="text-xl font-bold mb-4">Example Charts</h2>
@@ -190,6 +190,21 @@ const ThemeBuilder = () => {
190190
</VictoryStack>
191191
</VictoryChart>
192192
</div>
193+
<div>
194+
<h3 className="text-base font-bold mb-3">Area Chart</h3>
195+
<VictoryChart
196+
theme={customThemeConfig}
197+
domainPadding={20}
198+
style={chartStyle}
199+
>
200+
<VictoryAxis label="X Axis" />
201+
<VictoryAxis dependentAxis label="Y Axis" />
202+
<VictoryArea
203+
data={sampleStackData}
204+
labels={({ datum }) => datum.y}
205+
/>
206+
</VictoryChart>
207+
</div>
193208
</div>
194209
</div>
195210
)}

demo/ts/components/theme-builder/options-config.ts

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
1+
const getBaseLabelsConfig = (basePath: string) => [
2+
{
3+
type: "slider",
4+
label: "Font Size",
5+
min: 10,
6+
max: 24,
7+
unit: "px",
8+
path: `${basePath}.fontSize`,
9+
},
10+
{
11+
type: "slider",
12+
label: "Padding",
13+
min: 0,
14+
max: 50,
15+
unit: "px",
16+
path: `${basePath}.padding`,
17+
},
18+
{
19+
type: "colorPicker",
20+
label: "Fill",
21+
path: `${basePath}.fill`,
22+
},
23+
];
24+
125
const optionsConfig = [
226
{
327
type: "section",
4-
title: "Color Options",
28+
title: "Palette",
529
fields: [
630
{
731
type: "colorScale",
@@ -11,28 +35,44 @@ const optionsConfig = [
1135
},
1236
{
1337
type: "section",
14-
title: "Axis Label Options",
38+
title: "Axis Labels",
39+
fields: getBaseLabelsConfig("axis.style.axisLabel"),
40+
},
41+
{
42+
type: "section",
43+
title: "Area Chart",
1544
fields: [
1645
{
17-
type: "slider",
18-
label: "Font Size",
19-
min: 10,
20-
max: 24,
21-
unit: "px",
22-
path: "axis.style.axisLabel.fontSize",
23-
},
24-
{
25-
type: "slider",
26-
label: "Padding",
27-
min: 0,
28-
max: 50,
29-
unit: "px",
30-
path: "axis.style.axisLabel.padding",
46+
type: "section",
47+
label: "Data",
48+
fields: [
49+
{
50+
type: "slider",
51+
label: "Fill Opacity",
52+
min: 0,
53+
max: 1,
54+
step: 0.1,
55+
path: "area.style.data.fillOpacity",
56+
},
57+
{
58+
type: "slider",
59+
label: "Stroke Width",
60+
min: 0,
61+
max: 5,
62+
unit: "px",
63+
path: "area.style.data.strokeWidth",
64+
},
65+
{
66+
type: "colorPicker",
67+
label: "Fill",
68+
path: "area.style.data.fill",
69+
},
70+
],
3171
},
3272
{
33-
type: "colorPicker",
34-
label: "Fill",
35-
path: "axis.style.axisLabel.fill",
73+
type: "section",
74+
label: "Labels",
75+
fields: getBaseLabelsConfig("area.style.labels"),
3676
},
3777
],
3878
},

demo/ts/components/theme-builder/slider.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ type SliderProps = {
88
onChange?: (value: number) => void;
99
min?: number;
1010
max?: number;
11+
step?: number;
12+
className?: string;
1113
};
1214

1315
const Slider = ({
1416
label,
1517
id,
1618
value,
17-
unit = "px",
19+
unit,
1820
onChange,
1921
min,
2022
max,
23+
step = 1,
24+
className,
2125
}: SliderProps) => {
2226
const handleChange = (event) => {
2327
const newValue = event.target.value;
@@ -27,7 +31,7 @@ const Slider = ({
2731
};
2832

2933
return (
30-
<div className="my-4">
34+
<div className={className}>
3135
<label
3236
htmlFor={id}
3337
className="block mb-1 text-sm font-medium text-gray-900 dark:text-white"
@@ -43,6 +47,7 @@ const Slider = ({
4347
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
4448
min={min}
4549
max={max}
50+
step={step}
4651
/>
4752
</div>
4853
);

0 commit comments

Comments
 (0)