Skip to content

Commit

Permalink
feat: add area chart options to theme builder (#2967)
Browse files Browse the repository at this point in the history
  • Loading branch information
ramenhog authored Nov 14, 2024
1 parent a63cb04 commit 31ae615
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 83 deletions.
4 changes: 3 additions & 1 deletion demo/ts/components/theme-builder/color-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type ColorPickerProps = {
id: string;
onColorChange: (color: string) => void;
showColorName?: boolean;
className?: string;
};

const ColorPicker = ({
Expand All @@ -16,6 +17,7 @@ const ColorPicker = ({
id,
onColorChange,
showColorName = false,
className,
}: ColorPickerProps) => {
const [isPickerOpen, setIsPickerOpen] = React.useState(false);

Expand All @@ -26,7 +28,7 @@ const ColorPicker = ({
};

return (
<fieldset>
<fieldset className={className}>
{label && (
<label className="block mb-1 text-sm text-gray-900 dark:text-white font-bold">
{label}
Expand Down
2 changes: 1 addition & 1 deletion demo/ts/components/theme-builder/color-scale-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const ColorScaleOptions = ({
label="Color Scale"
className="mb-5"
/>
<div className="flex flex-wrap gap-3 mb-5">
<div className="flex flex-wrap gap-3">
{palette?.[activeColorScale as string]?.map((color, i) => (
<ColorPicker
key={i}
Expand Down
161 changes: 103 additions & 58 deletions demo/ts/components/theme-builder/config-mapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import ColorPicker from "./color-picker";
import ColorScaleOptions from "./color-scale-options";
import { getConfigValue } from "./utils";

const ConfigMapper = ({
const ControlComponent = ({
type,
field,
themeConfig,
activeColorScale,
updateThemeConfig,
activeColorScale,
handleColorScaleChange,
className,
}) => {
const handleColorChange = ({ newColor, index, colorScale }) => {
const updatedColors = themeConfig?.palette?.[colorScale]?.map((color, i) =>
Expand All @@ -20,6 +23,91 @@ const ConfigMapper = ({
updateThemeConfig(`palette.${colorScale}`, updatedColors);
};

const handleChange = (newValue) => {
updateThemeConfig(field.path, newValue);
};

const configValue = getConfigValue(themeConfig, field.path);
switch (type) {
case "colorScale":
return (
<ColorScaleOptions
palette={themeConfig?.palette}
activeColorScale={activeColorScale}
onColorChange={handleColorChange}
onColorScaleChange={handleColorScaleChange}
/>
);
case "section":
return (
<section className="mb-6">
<h3 className="text-lg text-secondary font-bold mb-4">
{field.label}
</h3>
{field.fields.map((subField, i) => (
<ControlComponent
key={subField.label + i}
type={subField.type}
field={subField}
themeConfig={themeConfig}
updateThemeConfig={updateThemeConfig}
activeColorScale={activeColorScale}
handleColorScaleChange={handleColorScaleChange}
className={className}
/>
))}
</section>
);
case "slider":
return (
<Slider
id={field.label}
key={field.label}
label={field.label}
value={configValue as number}
unit={field.unit}
onChange={handleChange}
min={field.min}
max={field.max}
step={field.step}
className={className}
/>
);
case "select":
return (
<Select
id={field.label}
key={field.label}
label={field.label}
value={configValue as string}
onChange={handleChange}
options={field.options}
className={className}
/>
);
case "colorPicker":
return (
<ColorPicker
id={field.label}
key={field.label}
label={field.label}
color={configValue as string}
onColorChange={handleChange}
className={className}
showColorName
/>
);
default:
return null;
}
};

const ConfigMapper = ({
themeConfig,
activeColorScale,
updateThemeConfig,
handleColorScaleChange,
}) => {
return (
<>
{optionsConfig.map((section, index) => (
Expand All @@ -29,62 +117,19 @@ const ConfigMapper = ({
id={section.title}
defaultOpen={index === 0}
>
{section.fields.map((field) => {
if (field.type === "colorScale") {
return (
<ColorScaleOptions
key={field.label}
activeColorScale={activeColorScale}
palette={themeConfig?.palette}
onColorChange={handleColorChange}
onColorScaleChange={handleColorScaleChange}
/>
);
}
const configValue = getConfigValue(themeConfig, field.path);
if (field.type === "slider") {
return (
<Slider
id={field.label}
key={field.label}
label={field.label}
value={configValue as number}
unit={field.unit}
onChange={(newValue) =>
updateThemeConfig(field.path, newValue)
}
/>
);
}
if (field.type === "select") {
return (
<Select
id={field.label}
key={field.label}
label={field.label}
value={configValue as string}
options={field.options}
onChange={(newValue) =>
updateThemeConfig(field.path, newValue)
}
/>
);
}
if (field.type === "colorPicker") {
return (
<ColorPicker
id={field.label}
key={field.label}
label={field.label}
color={configValue as string}
onColorChange={(newColor) =>
updateThemeConfig(field.path, newColor)
}
showColorName
/>
);
}
return null;
{section.fields.map((field, i) => {
return (
<ControlComponent
key={field.label + i}
type={field.type}
field={field}
themeConfig={themeConfig}
updateThemeConfig={updateThemeConfig}
activeColorScale={activeColorScale}
handleColorScaleChange={handleColorScaleChange}
className="mb-4"
/>
);
})}
</Accordion>
))}
Expand Down
19 changes: 17 additions & 2 deletions demo/ts/components/theme-builder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const ThemeBuilder = () => {

return (
<div className="flex flex-row flex-wrap items-start justify-start w-full">
<aside className="relative flex flex-col h-lvh w-[350px] border-r border-gray-200">
<aside className="relative flex flex-col h-full w-[380px] border-r border-gray-200">
<div className="grow overflow-y-auto p-4 pb-[100px]">
<h2 className="mb-0 text-lg font-bold">Customize Your Theme</h2>
<p className="text-sm mb-4 text-gray-300">
Expand Down Expand Up @@ -147,7 +147,7 @@ const ThemeBuilder = () => {
</Button>
</footer>
</aside>
<main className="flex-1 flex flex-col items-center">
<main className="flex-1 flex flex-col items-center overflow-y-auto h-full">
{customThemeConfig && (
<div className="max-w-screen-xl w-full py-4 px-10">
<h2 className="text-xl font-bold mb-4">Example Charts</h2>
Expand Down Expand Up @@ -190,6 +190,21 @@ const ThemeBuilder = () => {
</VictoryStack>
</VictoryChart>
</div>
<div>
<h3 className="text-base font-bold mb-3">Area Chart</h3>
<VictoryChart
theme={customThemeConfig}
domainPadding={20}
style={chartStyle}
>
<VictoryAxis label="X Axis" />
<VictoryAxis dependentAxis label="Y Axis" />
<VictoryArea
data={sampleStackData}
labels={({ datum }) => datum.y}
/>
</VictoryChart>
</div>
</div>
</div>
)}
Expand Down
78 changes: 59 additions & 19 deletions demo/ts/components/theme-builder/options-config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
const getBaseLabelsConfig = (basePath: string) => [
{
type: "slider",
label: "Font Size",
min: 10,
max: 24,
unit: "px",
path: `${basePath}.fontSize`,
},
{
type: "slider",
label: "Padding",
min: 0,
max: 50,
unit: "px",
path: `${basePath}.padding`,
},
{
type: "colorPicker",
label: "Fill",
path: `${basePath}.fill`,
},
];

const optionsConfig = [
{
type: "section",
title: "Color Options",
title: "Palette",
fields: [
{
type: "colorScale",
Expand All @@ -11,28 +35,44 @@ const optionsConfig = [
},
{
type: "section",
title: "Axis Label Options",
title: "Axis Labels",
fields: getBaseLabelsConfig("axis.style.axisLabel"),
},
{
type: "section",
title: "Area Chart",
fields: [
{
type: "slider",
label: "Font Size",
min: 10,
max: 24,
unit: "px",
path: "axis.style.axisLabel.fontSize",
},
{
type: "slider",
label: "Padding",
min: 0,
max: 50,
unit: "px",
path: "axis.style.axisLabel.padding",
type: "section",
label: "Data",
fields: [
{
type: "slider",
label: "Fill Opacity",
min: 0,
max: 1,
step: 0.1,
path: "area.style.data.fillOpacity",
},
{
type: "slider",
label: "Stroke Width",
min: 0,
max: 5,
unit: "px",
path: "area.style.data.strokeWidth",
},
{
type: "colorPicker",
label: "Fill",
path: "area.style.data.fill",
},
],
},
{
type: "colorPicker",
label: "Fill",
path: "axis.style.axisLabel.fill",
type: "section",
label: "Labels",
fields: getBaseLabelsConfig("area.style.labels"),
},
],
},
Expand Down
9 changes: 7 additions & 2 deletions demo/ts/components/theme-builder/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ type SliderProps = {
onChange?: (value: number) => void;
min?: number;
max?: number;
step?: number;
className?: string;
};

const Slider = ({
label,
id,
value,
unit = "px",
unit,
onChange,
min,
max,
step = 1,
className,
}: SliderProps) => {
const handleChange = (event) => {
const newValue = event.target.value;
Expand All @@ -27,7 +31,7 @@ const Slider = ({
};

return (
<div className="my-4">
<div className={className}>
<label
htmlFor={id}
className="block mb-1 text-sm font-medium text-gray-900 dark:text-white"
Expand All @@ -43,6 +47,7 @@ const Slider = ({
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
min={min}
max={max}
step={step}
/>
</div>
);
Expand Down
Loading

0 comments on commit 31ae615

Please sign in to comment.