Skip to content

Commit

Permalink
feat: generate option controls from config
Browse files Browse the repository at this point in the history
  • Loading branch information
ramenhog committed Nov 6, 2024
1 parent 5060d37 commit 8f09539
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 5 deletions.
43 changes: 43 additions & 0 deletions demo/ts/components/theme-builder/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import clsx from "clsx";
import { FaChevronDown } from "react-icons/fa";

const Accordion = ({ id, title, children }) => {
const [isOpen, setIsOpen] = React.useState(false);

const toggleAccordion = () => {
setIsOpen(!isOpen);
};

return (
<div id={id} className="group">
<h2 id={`${id}-heading`}>
<button
type="button"
className={clsx(
"flex items-center justify-between w-full px-5 py-3 text-sm font-bold rtl:text-right text-gray-500 border border-b-0 border-gray-200 gap-3 group-last:border-b",
{ "group-last:border-b-0": isOpen },
)}
aria-expanded="true"
aria-controls={`${id}-body`}
onClick={toggleAccordion}
>
<span>{title}</span>
<FaChevronDown
className={clsx("w-3 h-3 shrink-0", { "rotate-180 ": isOpen })}
/>
</button>
</h2>
<div
id={`${id}-body`}
className={isOpen ? "block" : "hidden"}
aria-labelledby={`${id}-heading`}
>
<div className="p-5 border border-b-0 border-gray-200 group-last:border-b">
{children}
</div>
</div>
</div>
);
};
export default Accordion;
65 changes: 65 additions & 0 deletions demo/ts/components/theme-builder/config-mapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from "react";
import optionsConfig from "./options-config";
import Accordion from "./accordion";
import Select from "./select";
import Slider from "./slider";
import ColorPicker from "./color-picker";

const ConfigMapper = ({
activeColorScale,
handleColorScaleChange,
handleLabelConfigChange,
}) => {
return (
<>
{optionsConfig.map((section) => (
<Accordion key={section.title} title={section.title} id={section.title}>
{section.fields.map((field) => {
if (field.type === "colorScale") {
return (
<Select
key={field.label}
id="color-scale-select"
value={activeColorScale}
onChange={handleColorScaleChange}
options={field.options}
label={field.label}
/>
);
}
if (field.type === "slider") {
return (
<Slider
id={field.label}
key={field.label}
label={field.label}
defaultValue={field.default}
unit={field.unit}
onChange={(value) =>
handleLabelConfigChange({ [field.label]: value })
}
/>
);
}
if (field.type === "colorPicker") {
return (
<ColorPicker
id={field.label}
key={field.label}
label={field.label}
color={field.default}
onColorChange={(color) =>
handleLabelConfigChange({ [field.label]: color })
}
/>
);
}
return null;
})}
</Accordion>
))}
</>
);
};

export default ConfigMapper;
18 changes: 15 additions & 3 deletions demo/ts/components/theme-builder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Button from "./button";

import "./tailwind.css";
import LabelOptions from "./label-options";
import ConfigMapper from "./config-mapper";

export type ThemeOption = {
name: string;
Expand Down Expand Up @@ -139,7 +140,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-[300px] border-r border-gray-200">
<aside className="relative flex flex-col h-lvh w-[350px] 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 All @@ -155,15 +156,26 @@ const ThemeBuilder = () => {
{customThemeConfig && (
<section>
<h2 className="text-lg font-bold mb-4">Customization Options</h2>
<ConfigMapper
activeColorScale={activeColorScale}
handleColorScaleChange={handleColorScaleChange}
handleLabelConfigChange={handleLabelConfigChange}
/>
</section>
)}
{false && (
<section>
<h2 className="text-lg font-bold mb-4">Customization Options</h2>
<h3 className="text-lg font-bold mb-4">Color Options</h3>
<ColorScaleOptions
activeColorScale={activeColorScale}
palette={customThemeConfig.palette}
palette={customThemeConfig?.palette}
onColorChange={handleColorChange}
onColorScaleChange={handleColorScaleChange}
/>
<LabelOptions
labelConfig={
customThemeConfig.axis?.style?.axisLabel as LabelProps
customThemeConfig?.axis?.style?.axisLabel as LabelProps
}
onLabelConfigChange={handleLabelConfigChange}
/>
Expand Down
43 changes: 43 additions & 0 deletions demo/ts/components/theme-builder/options-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const optionsConfig = [
{
type: "section",
title: "Color Options",
fields: [
{
type: "colorScale",
label: "Color Scale",
options: ["Qualitative", "Sequential", "Diverging"],
default: "Qualitative",
},
],
},
{
type: "section",
title: "Axis Label Options",
fields: [
{
type: "slider",
label: "Font Size",
min: 10,
max: 24,
default: 12,
unit: "px",
},
{
type: "slider",
label: "Padding",
min: 0,
max: 50,
default: 35,
unit: "px",
},
{
type: "colorPicker",
label: "Fill",
default: "#292929",
},
],
},
];

export default optionsConfig;
4 changes: 2 additions & 2 deletions demo/ts/components/theme-builder/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type SelectProps = {

const Select = ({ id, label, options, value, onChange }: SelectProps) => {
return (
<div className="relative w-full mb-5">
<div className="relative w-full">
{label && (
<label htmlFor={id} className="block mb-1 text-sm font-bold">
<label htmlFor={id} className="block mb-1 text-sm">
{label}
</label>
)}
Expand Down

0 comments on commit 8f09539

Please sign in to comment.