Changes to color controls
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,7 +9,6 @@ npm-debug.log*
|
||||
|
||||
# Ignore build files
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Ignore .env files (for sensitive data like API keys)
|
||||
.env
|
||||
|
||||
112
blocks/bar-graph/build/block.json
Normal file
112
blocks/bar-graph/build/block.json
Normal file
@ -0,0 +1,112 @@
|
||||
{
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2,
|
||||
"name": "lcp/bar-graph",
|
||||
"version": "0.1.0",
|
||||
"title": "LCP Bar Graph",
|
||||
"category": "widgets",
|
||||
"icon": "chart-bar",
|
||||
"description": "Display data in a bar graph format.",
|
||||
"supports": {
|
||||
"html": false
|
||||
},
|
||||
"textdomain": "lcp",
|
||||
"editorScript": "file:./index.js",
|
||||
"editorStyle": "file:./index.css",
|
||||
"style": "file:./style-index.css",
|
||||
"viewScript": "file:./view.js",
|
||||
"attributes": {
|
||||
"chartColorSource": {
|
||||
"type": "string",
|
||||
"default": "default"
|
||||
},
|
||||
"chartCustomColors": {
|
||||
"type": "array",
|
||||
"default": []
|
||||
},
|
||||
"showBarValues": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"chartHeight": {
|
||||
"type": "string",
|
||||
"default": "400px"
|
||||
},
|
||||
"chartWidth": {
|
||||
"type": "string",
|
||||
"default": "100%"
|
||||
},
|
||||
"chartTitle": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"displayChartTitle": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"allowDownload": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"downloadMaxWidth": {
|
||||
"type": "string",
|
||||
"default": "2000px"
|
||||
},
|
||||
"showSorting": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"showFiltering": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"chartData": {
|
||||
"type": "object",
|
||||
"default": {}
|
||||
},
|
||||
"dataSource": {
|
||||
"type": "string",
|
||||
"default": "manual_json"
|
||||
},
|
||||
"barColor": {
|
||||
"type": "string",
|
||||
"default": "#0073aa"
|
||||
},
|
||||
"barOpacity": {
|
||||
"type": "number",
|
||||
"default": 1
|
||||
},
|
||||
"backgroundColor": {
|
||||
"type": "string",
|
||||
"default": "#ffffff"
|
||||
},
|
||||
"showGridX": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"showGridY": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"gridColor": {
|
||||
"type": "string",
|
||||
"default": "#e0e0e0"
|
||||
},
|
||||
"gridWidth": {
|
||||
"type": "number",
|
||||
"default": 1
|
||||
},
|
||||
"xAxisLabel": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"yAxisLabel": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"gridOpacity": {
|
||||
"type": "number",
|
||||
"default": 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
1
blocks/bar-graph/build/index-rtl.css
Normal file
1
blocks/bar-graph/build/index-rtl.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-todo-list{border:1px dotted red}.wp-block-lcp-bar-graph{margin:1em 0}.wp-block-lcp-bar-graph .lcp-bar-graph-container{overflow:visible;width:100%}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg{overflow:visible}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .bar{transition:opacity .2s ease}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .bar:hover{cursor:pointer}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .grid line{stroke-opacity:.1}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .domain,.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tick line{stroke:#666}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tick text{fill:#666;font-size:12px}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tooltip{pointer-events:none}.wp-block-lcp-bar-graph .lcp-bar-graph-placeholder{font-size:1.2em;padding:2em;text-align:center}.lcp-data-selector .components-base-control{margin-bottom:1.5em}.lcp-data-selector .lcp-data-selector-error{background-color:#f8d7da;border-right:4px solid #cc1818;margin-top:.5em;padding:.5em}
|
||||
1
blocks/bar-graph/build/index.asset.php
Normal file
1
blocks/bar-graph/build/index.asset.php
Normal file
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '62449dbdc80e118c522c');
|
||||
1
blocks/bar-graph/build/index.css
Normal file
1
blocks/bar-graph/build/index.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-todo-list{border:1px dotted red}.wp-block-lcp-bar-graph{margin:1em 0}.wp-block-lcp-bar-graph .lcp-bar-graph-container{overflow:visible;width:100%}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg{overflow:visible}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .bar{transition:opacity .2s ease}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .bar:hover{cursor:pointer}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .grid line{stroke-opacity:.1}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .domain,.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tick line{stroke:#666}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tick text{fill:#666;font-size:12px}.wp-block-lcp-bar-graph .lcp-bar-graph-container svg .tooltip{pointer-events:none}.wp-block-lcp-bar-graph .lcp-bar-graph-placeholder{font-size:1.2em;padding:2em;text-align:center}.lcp-data-selector .components-base-control{margin-bottom:1.5em}.lcp-data-selector .lcp-data-selector-error{background-color:#f8d7da;border-left:4px solid #cc1818;margin-top:.5em;padding:.5em}
|
||||
1
blocks/bar-graph/build/index.js
Normal file
1
blocks/bar-graph/build/index.js
Normal file
File diff suppressed because one or more lines are too long
1
blocks/bar-graph/build/style-index-rtl.css
Normal file
1
blocks/bar-graph/build/style-index-rtl.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-todo-list{background-color:#21759b;color:#fff;padding:2px}
|
||||
1
blocks/bar-graph/build/style-index.css
Normal file
1
blocks/bar-graph/build/style-index.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-todo-list{background-color:#21759b;color:#fff;padding:2px}
|
||||
1
blocks/bar-graph/build/view.asset.php
Normal file
1
blocks/bar-graph/build/view.asset.php
Normal file
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '7ca23fe6db2e4bfa97aa');
|
||||
1
blocks/bar-graph/build/view.js
Normal file
1
blocks/bar-graph/build/view.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello World! (from create-block-todo-list block)");
|
||||
@ -16,6 +16,14 @@
|
||||
"style": "file:./style-index.css",
|
||||
"viewScript": "file:./view.js",
|
||||
"attributes": {
|
||||
"chartColorSource": {
|
||||
"type": "string",
|
||||
"default": "default"
|
||||
},
|
||||
"chartCustomColors": {
|
||||
"type": "array",
|
||||
"default": []
|
||||
},
|
||||
"showBarValues": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
|
||||
@ -13,7 +13,11 @@ const BarGraph = ({
|
||||
gridWidth,
|
||||
showBarValues,
|
||||
xAxisLabel,
|
||||
yAxisLabel
|
||||
yAxisLabel,
|
||||
colorSource,
|
||||
defaultBarColor,
|
||||
customColors,
|
||||
barOpacity
|
||||
}) => {
|
||||
const svgRef = useRef();
|
||||
const containerRef = useRef();
|
||||
@ -80,6 +84,22 @@ const BarGraph = ({
|
||||
.domain([0, d3.max(chartData, d => d.value)])
|
||||
.range([innerHeight, 0]);
|
||||
|
||||
// Get color for a datapoint based on color source
|
||||
const getColor = (datapoint) => {
|
||||
switch (colorSource) {
|
||||
case 'singleColor':
|
||||
return defaultBarColor;
|
||||
case 'customColors':
|
||||
const customColor = customColors.find(
|
||||
c => c.dataset === datapoint.dataset && c.label === datapoint.label
|
||||
);
|
||||
return customColor ? customColor.color : datapoint.color;
|
||||
case 'default':
|
||||
default:
|
||||
return datapoint.color;
|
||||
}
|
||||
};
|
||||
|
||||
// Add X grid
|
||||
if (showGridX) {
|
||||
g.append('g')
|
||||
@ -116,7 +136,8 @@ const BarGraph = ({
|
||||
.attr('y', d => yScale(d.value))
|
||||
.attr('width', xScale.bandwidth())
|
||||
.attr('height', d => innerHeight - yScale(d.value))
|
||||
.attr('fill', d => d.color);
|
||||
.attr('fill', d => getColor(d))
|
||||
.style('opacity', barOpacity);
|
||||
|
||||
// Add bar values
|
||||
if (showBarValues) {
|
||||
@ -163,7 +184,7 @@ const BarGraph = ({
|
||||
.text(yAxisLabel);
|
||||
}
|
||||
|
||||
}, [data, width, height, title, showGridX, showGridY, gridColor, gridWidth, showBarValues, xAxisLabel, yAxisLabel]);
|
||||
}, [data, width, height, title, showGridX, showGridY, gridColor, gridWidth, showBarValues, xAxisLabel, yAxisLabel, colorSource, defaultBarColor, customColors, barOpacity]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
116
blocks/bar-graph/src/components/ColorControls.js
Normal file
116
blocks/bar-graph/src/components/ColorControls.js
Normal file
@ -0,0 +1,116 @@
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
ColorPicker,
|
||||
SelectControl,
|
||||
Button,
|
||||
Popover
|
||||
} from '@wordpress/components';
|
||||
import { useState } from '@wordpress/element';
|
||||
|
||||
const ColorControls = ({
|
||||
data,
|
||||
colorSource,
|
||||
singleColor,
|
||||
customColors,
|
||||
onColorSourceChange,
|
||||
onSingleColorChange,
|
||||
onCustomColorChange
|
||||
}) => {
|
||||
const [activePopover, setActivePopover] = useState(null);
|
||||
|
||||
// Get all datapoints from all datasets
|
||||
const getAllDatapoints = () => {
|
||||
const datapoints = [];
|
||||
Object.entries(data).forEach(([dataset, items]) => {
|
||||
items.forEach(item => {
|
||||
datapoints.push({
|
||||
dataset,
|
||||
label: item.label,
|
||||
value: item.value
|
||||
});
|
||||
});
|
||||
});
|
||||
return datapoints;
|
||||
};
|
||||
|
||||
const getCustomColor = (dataset, label) => {
|
||||
const colorEntry = customColors.find(c => c.dataset === dataset && c.label === label);
|
||||
return colorEntry ? colorEntry.color : '#FF6384';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="lcp-color-controls">
|
||||
<SelectControl
|
||||
label={__('Color Source', 'lcp')}
|
||||
value={colorSource}
|
||||
options={[
|
||||
{ label: __('Default Colors', 'lcp'), value: 'default' },
|
||||
{ label: __('Single Color', 'lcp'), value: 'singleColor' },
|
||||
{ label: __('Custom Colors', 'lcp'), value: 'customColors' }
|
||||
]}
|
||||
onChange={onColorSourceChange}
|
||||
/>
|
||||
|
||||
{colorSource === 'singleColor' && (
|
||||
<div className="components-base-control">
|
||||
<label className="components-base-control__label">
|
||||
{__('Bar Color', 'lcp')}
|
||||
</label>
|
||||
<ColorPicker
|
||||
color={singleColor}
|
||||
onChangeComplete={(color) => onSingleColorChange(color.hex)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{colorSource === 'customColors' && (
|
||||
<div className="custom-colors-grid" style={{ marginTop: '10px' }}>
|
||||
{getAllDatapoints().map((datapoint, index) => (
|
||||
<div
|
||||
key={`${datapoint.dataset}-${datapoint.label}`}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '8px',
|
||||
gap: '8px'
|
||||
}}
|
||||
>
|
||||
<span style={{ flex: 1 }}>{datapoint.label}</span>
|
||||
<Button
|
||||
onClick={() => setActivePopover(index)}
|
||||
style={{
|
||||
backgroundColor: getCustomColor(datapoint.dataset, datapoint.label),
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
borderRadius: '50%',
|
||||
padding: 0,
|
||||
border: '1px solid #ddd'
|
||||
}}
|
||||
/>
|
||||
{activePopover === index && (
|
||||
<Popover
|
||||
onClose={() => setActivePopover(null)}
|
||||
>
|
||||
<div style={{ padding: '12px' }}>
|
||||
<ColorPicker
|
||||
color={getCustomColor(datapoint.dataset, datapoint.label)}
|
||||
onChangeComplete={(color) => {
|
||||
onCustomColorChange(
|
||||
datapoint.dataset,
|
||||
datapoint.label,
|
||||
color.hex
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorControls;
|
||||
@ -11,9 +11,11 @@ import {
|
||||
ToggleControl,
|
||||
TabPanel,
|
||||
TextControl,
|
||||
Button
|
||||
Button,
|
||||
Popover
|
||||
} from '@wordpress/components';
|
||||
|
||||
import {useState} from '@wordpress/element';
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
@ -21,6 +23,7 @@ import './editor.scss';
|
||||
import LCPDataSelector from '../../../components/LCPDataSelector';
|
||||
import BarGraph from './components/BarGraph';
|
||||
import LCPDimensionControl from '../../../components/LCPDimensionControl';
|
||||
import ColorControls from './components/ColorControls';
|
||||
|
||||
export default function Edit({ attributes, setAttributes }) {
|
||||
const {
|
||||
@ -43,8 +46,9 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
showGridX,
|
||||
gridWidth,
|
||||
xAxisLabel,
|
||||
yAxisLabel
|
||||
} = attributes;
|
||||
yAxisLabel,
|
||||
chartColorSource,
|
||||
chartCustomColors } = attributes;
|
||||
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
@ -60,6 +64,21 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
});
|
||||
};
|
||||
|
||||
const handleCustomColorChange = (dataset, label, color) => {
|
||||
const existingColors = [...chartCustomColors];
|
||||
const existingIndex = existingColors.findIndex(
|
||||
c => c.dataset === dataset && c.label === label
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
existingColors[existingIndex].color = color;
|
||||
} else {
|
||||
existingColors.push({ dataset, label, color });
|
||||
}
|
||||
|
||||
setAttributes({ chartCustomColors: existingColors });
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
// Get the SVG element
|
||||
const svg = document.querySelector('.bar-graph svg');
|
||||
@ -103,6 +122,33 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
// Grid Color Popover
|
||||
const [isGridColorPopoverOpen, setIsGridColorPopoverOpen] = useState(false);
|
||||
|
||||
// Toggle the popover visibility
|
||||
const toggleGridColorPopover = () => {
|
||||
setIsGridColorPopoverOpen(!isGridColorPopoverOpen);
|
||||
};
|
||||
|
||||
// Handle color change
|
||||
const onGridColorChange = (newColor) => {
|
||||
setAttributes({ gridColor: newColor });
|
||||
};
|
||||
|
||||
// Grid Color Popover
|
||||
const [isBackgroundColorPopoverOpen, setIsBackgroundColorPopoverOpen] = useState(false);
|
||||
|
||||
// Toggle the background popover visibility
|
||||
const toggleBackgroundColorPopover = () => {
|
||||
setIsBackgroundColorPopoverOpen(!isBackgroundColorPopoverOpen);
|
||||
};
|
||||
|
||||
// Handle color change
|
||||
const onBackgroundColorChange = (newColor) => {
|
||||
setAttributes({ backgroundColor: newColor });
|
||||
};
|
||||
|
||||
|
||||
// Debug log to check chartData
|
||||
console.log('Chart data:', chartData);
|
||||
|
||||
@ -167,15 +213,65 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
/>
|
||||
</PanelBody>
|
||||
<PanelBody title="Appearance">
|
||||
<div className="components-base-control">
|
||||
<label className="components-base-control__label">
|
||||
{__('Bar Color', 'lcp')}
|
||||
</label>
|
||||
<ColorPicker
|
||||
color={barColor}
|
||||
onChangeComplete={(color) => setAttributes({ barColor: color.hex })}
|
||||
/>
|
||||
<div className="grid-color-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px' }}>
|
||||
<span>Grid Color</span>
|
||||
<Button
|
||||
className="grid-color-button"
|
||||
onClick={toggleGridColorPopover}
|
||||
style={{
|
||||
backgroundColor: gridColor,
|
||||
width: '26px',
|
||||
height: '26px',
|
||||
borderRadius: '50%',
|
||||
border: 'none',
|
||||
}}
|
||||
></Button>
|
||||
{isGridColorPopoverOpen && (
|
||||
<Popover
|
||||
position="bottom center"
|
||||
onClose={toggleGridColorPopover} // Close the popover when clicked outside
|
||||
>
|
||||
<ColorPicker
|
||||
color={gridColor}
|
||||
onChangeComplete={(color) => onGridColorChange(color.hex)} // Update color
|
||||
/>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
<div className="background-color-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px' }}>
|
||||
<span>Background Color</span>
|
||||
<Button
|
||||
className="background-color-button"
|
||||
onClick={toggleBackgroundColorPopover}
|
||||
style={{
|
||||
backgroundColor: backgroundColor,
|
||||
width: '26px',
|
||||
height: '26px',
|
||||
borderRadius: '50%',
|
||||
border: '1px solid #ccc',
|
||||
}}
|
||||
></Button>
|
||||
{isBackgroundColorPopoverOpen && (
|
||||
<Popover
|
||||
position="bottom center"
|
||||
onClose={toggleBackgroundColorPopover} // Close the popover when clicked outside
|
||||
>
|
||||
<ColorPicker
|
||||
color={backgroundColor}
|
||||
onChangeComplete={(color) => onBackgroundColorChange(color.hex)} // Update color
|
||||
/>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
<ColorControls
|
||||
data={chartData}
|
||||
colorSource={chartColorSource}
|
||||
singleColor={barColor}
|
||||
customColors={chartCustomColors}
|
||||
onColorSourceChange={(value) => setAttributes({ chartColorSource: value })}
|
||||
onSingleColorChange={(color) => setAttributes({ barColor: color })}
|
||||
onCustomColorChange={handleCustomColorChange}
|
||||
/>
|
||||
<RangeControl
|
||||
label={__('Bar Opacity', 'lcp')}
|
||||
value={barOpacity}
|
||||
@ -230,6 +326,12 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
color={gridColor}
|
||||
onChangeComplete={(color) => setAttributes({ gridColor: color.hex })}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<RangeControl
|
||||
label={__('Grid Width', 'lcp')}
|
||||
@ -317,6 +419,8 @@ export default function Edit({ attributes, setAttributes }) {
|
||||
showBarValues={showBarValues}
|
||||
xAxisLabel={xAxisLabel}
|
||||
yAxisLabel={yAxisLabel}
|
||||
colorSource={chartColorSource}
|
||||
customColors={chartCustomColors}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user