-
Notifications
You must be signed in to change notification settings - Fork 510
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: Percentage field color customization (#692)
* feat(percentage-c11n): convert to table cell * feat(percentage-c11n): add logic to default configs * feat(percentage-c11n): add color picker to settings * feat(percentage-c11n): change default colors * feat(percentage-c11n): fix button text color * feat(percentage-c11n): add labels to settings * feat(percentage-c11n): add preview section * feat(percentage-c11n): fix cache issues with debouncing * feat(percentage-c11n): add width responsiveness to color picker * feat(percentage-c11n): fix responsiveness issues * feat(percentage-c11n): add checkbox, refactor a little * feat(percentage-c11n): convert data type to array * feat(percentage-c11n): refactor config states * feat(percentage-c11n): fix defaults * feat(percentage-c11n): add basic cell without bg * feat(percentage-c11n): remove collapse * feat(percentage-c11n): refactor checkStates * feat(percentage-c11n): add grid layout * feat(percentage-c11n): chore conventions * feat(percentage-c11n): add default theme color to sidedrawer * remove redundant fragment Co-authored-by: Sidney Alcantara <sidney@sidney.me> * fix text color in preview Co-authored-by: Sidney Alcantara <sidney@sidney.me> * fix: change state to derived state Co-authored-by: Sidney Alcantara <sidney@sidney.me> * fix: review suggestions * fix: remove redundant change call Co-authored-by: Sidney Alcantara <sidney@sidney.me> * fix(percentage-c11n): remove redundant dependencies Co-authored-by: Shams <shams.mosowi@gmail.com> Co-authored-by: Sidney Alcantara <sidney@sidney.me>
- Loading branch information
1 parent
6db708a
commit db7b3eb
Showing
7 changed files
with
341 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { useState, useRef, MutableRefObject, useLayoutEffect } from "react"; | ||
import { Box, useTheme } from "@mui/material"; | ||
|
||
import { Color, ColorPicker } from "react-color-palette"; | ||
|
||
const useResponsiveWidth = (): [ | ||
width: number, | ||
setRef: MutableRefObject<HTMLElement | null> | ||
] => { | ||
const ref = useRef(null); | ||
const [width, setWidth] = useState(0); | ||
|
||
useLayoutEffect(() => { | ||
if (!ref || !ref.current) { | ||
return; | ||
} | ||
const resizeObserver = new ResizeObserver((targets) => { | ||
const { width: currentWidth } = targets[0].contentRect; | ||
setWidth(currentWidth); | ||
}); | ||
|
||
resizeObserver.observe(ref.current); | ||
|
||
return () => { | ||
resizeObserver.disconnect(); | ||
}; | ||
}, []); | ||
|
||
return [width, ref]; | ||
}; | ||
|
||
export interface IColorPickerProps { | ||
value: Color; | ||
onChangeComplete: (color: Color) => void; | ||
disabled?: boolean; | ||
} | ||
|
||
export default function ColorPickerInput({ | ||
value, | ||
onChangeComplete, | ||
disabled = false, | ||
}: IColorPickerProps) { | ||
const [localValue, setLocalValue] = useState(value); | ||
const [width, setRef] = useResponsiveWidth(); | ||
const theme = useTheme(); | ||
|
||
return ( | ||
<Box | ||
ref={setRef} | ||
sx={[ | ||
{ | ||
padding: theme.spacing(1.5), | ||
paddingTop: theme.spacing(1), | ||
transitionDuration: 0, | ||
"& .rcp": { | ||
border: "none", | ||
"& .rcp-saturation": { | ||
borderRadius: theme.spacing(0.5), | ||
}, | ||
"& .rcp-body": { | ||
boxSizing: "unset", | ||
}, | ||
}, | ||
}, | ||
]} | ||
> | ||
<ColorPicker | ||
width={width} | ||
height={150} | ||
color={localValue} | ||
onChange={(color) => setLocalValue(color)} | ||
onChangeComplete={onChangeComplete} | ||
/> | ||
</Box> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,21 @@ | ||
import { IBasicCellProps } from "@src/components/fields/types"; | ||
|
||
import { useTheme } from "@mui/material"; | ||
import { resultColorsScale } from "@src/utils/color"; | ||
|
||
export default function Percentage({ value }: IBasicCellProps) { | ||
const theme = useTheme(); | ||
|
||
if (typeof value === "number") | ||
return ( | ||
<> | ||
<div | ||
style={{ | ||
backgroundColor: resultColorsScale(value).toHex(), | ||
|
||
position: "absolute", | ||
top: 0, | ||
right: 0, | ||
bottom: 0, | ||
left: 0, | ||
opacity: 0.5, | ||
|
||
zIndex: 0, | ||
}} | ||
/> | ||
<div | ||
style={{ | ||
textAlign: "right", | ||
color: theme.palette.text.primary, | ||
|
||
position: "relative", | ||
zIndex: 1, | ||
}} | ||
> | ||
{Math.round(value * 100)}% | ||
</div> | ||
</> | ||
); | ||
|
||
return null; | ||
const percentage = typeof value === "number" ? value : 0; | ||
return ( | ||
<div | ||
style={{ | ||
textAlign: "right", | ||
color: theme.palette.text.primary, | ||
position: "relative", | ||
zIndex: 1, | ||
}} | ||
> | ||
{Math.round(percentage * 100)}% | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import { useState } from "react"; | ||
|
||
import { | ||
Box, | ||
Checkbox, | ||
Grid, | ||
InputLabel, | ||
MenuItem, | ||
TextField, | ||
Typography, | ||
useTheme, | ||
} from "@mui/material"; | ||
import ColorPickerInput from "@src/components/ColorPickerInput"; | ||
import { ISettingsProps } from "@src/components/fields/types"; | ||
|
||
import { Color, toColor } from "react-color-palette"; | ||
import { fieldSx } from "@src/components/SideDrawer/utils"; | ||
import { resultColorsScale, defaultColors } from "@src/utils/color"; | ||
|
||
const colorLabels: { [key: string]: string } = { | ||
0: "Start", | ||
1: "Middle", | ||
2: "End", | ||
}; | ||
|
||
export default function Settings({ onChange, config }: ISettingsProps) { | ||
const colors: string[] = config.colors ?? defaultColors; | ||
|
||
const [checkStates, setCheckStates] = useState<boolean[]>( | ||
colors.map(Boolean) | ||
); | ||
|
||
const onCheckboxChange = (index: number, checked: boolean) => { | ||
onChange("colors")( | ||
colors.map((value: any, idx: number) => | ||
index === idx ? (checked ? value || defaultColors[idx] : null) : value | ||
) | ||
); | ||
setCheckStates( | ||
checkStates.map((value, idx) => (index === idx ? checked : value)) | ||
); | ||
}; | ||
|
||
const handleColorChange = (index: number, color: Color): void => { | ||
onChange("colors")( | ||
colors.map((value, idx) => (index === idx ? color.hex : value)) | ||
); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Grid container> | ||
{checkStates.map((checked: boolean, index: number) => { | ||
const colorHex = colors[index]; | ||
return ( | ||
<Grid | ||
xs={12} | ||
md={4} | ||
item | ||
sx={{ | ||
display: "flex", | ||
alignItems: "end", | ||
justifyContent: "center", | ||
}} | ||
> | ||
<Checkbox | ||
checked={checked} | ||
sx={[ | ||
fieldSx, | ||
{ | ||
width: "auto", | ||
boxShadow: "none", | ||
backgroundColor: "inherit", | ||
"&:hover": { | ||
backgroundColor: "inherit", | ||
}, | ||
}, | ||
]} | ||
onChange={() => onCheckboxChange(index, !checked)} | ||
/> | ||
<TextField | ||
select | ||
label={colorLabels[index]} | ||
value={1} | ||
fullWidth | ||
disabled={!checkStates[index]} | ||
> | ||
<MenuItem value={1} sx={{ display: "none" }}> | ||
{checked && ( | ||
<Box sx={{ display: "flex", alignItems: "center" }}> | ||
<Box | ||
sx={{ | ||
backgroundColor: colorHex, | ||
width: 15, | ||
height: 15, | ||
mr: 1.5, | ||
boxShadow: (theme) => | ||
`0 0 0 1px ${theme.palette.divider} inset`, | ||
borderRadius: 0.5, | ||
opacity: 0.5, | ||
}} | ||
/> | ||
<Box>{colorHex}</Box> | ||
</Box> | ||
)} | ||
</MenuItem> | ||
{colorHex && ( | ||
<div> | ||
<ColorPickerInput | ||
value={toColor("hex", colorHex)} | ||
onChangeComplete={(color) => | ||
handleColorChange(index, color) | ||
} | ||
disabled={!checkStates[index]} | ||
/> | ||
</div> | ||
)} | ||
</TextField> | ||
</Grid> | ||
); | ||
})} | ||
</Grid> | ||
<Preview colors={config.colors} /> | ||
</> | ||
); | ||
} | ||
|
||
const Preview = ({ colors }: { colors: any }) => { | ||
const theme = useTheme(); | ||
return ( | ||
<InputLabel> | ||
Preview: | ||
<Box | ||
sx={{ | ||
display: "flex", | ||
textAlign: "center", | ||
}} | ||
> | ||
{[0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1].map((value) => { | ||
return ( | ||
<Box | ||
sx={{ | ||
position: "relative", | ||
width: "100%", | ||
padding: "0.5rem 0", | ||
color: theme.palette.text.primary, | ||
}} | ||
> | ||
<Box | ||
key={value} | ||
sx={{ | ||
position: "absolute", | ||
inset: 0, | ||
backgroundColor: resultColorsScale( | ||
value, | ||
colors, | ||
theme.palette.background.paper | ||
).toHex(), | ||
opacity: 0.5, | ||
}} | ||
/> | ||
<Typography style={{ position: "relative", zIndex: 1 }}> | ||
{Math.floor(value * 100)}% | ||
</Typography> | ||
</Box> | ||
); | ||
})} | ||
</Box> | ||
</InputLabel> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { IHeavyCellProps } from "@src/components/fields/types"; | ||
|
||
import { useTheme } from "@mui/material"; | ||
import { resultColorsScale } from "@src/utils/color"; | ||
|
||
export default function Percentage({ column, value }: IHeavyCellProps) { | ||
const theme = useTheme(); | ||
const { colors } = (column as any).config; | ||
|
||
const percentage = typeof value === "number" ? value : 0; | ||
return ( | ||
<> | ||
<div | ||
style={{ | ||
backgroundColor: resultColorsScale( | ||
percentage, | ||
colors, | ||
theme.palette.background.paper | ||
).toHex(), | ||
position: "absolute", | ||
top: 0, | ||
right: 0, | ||
bottom: 0, | ||
left: 0, | ||
opacity: 0.5, | ||
zIndex: 0, | ||
}} | ||
/> | ||
<div | ||
style={{ | ||
textAlign: "right", | ||
color: theme.palette.text.primary, | ||
position: "relative", | ||
zIndex: 1, | ||
}} | ||
> | ||
{Math.round(percentage * 100)}% | ||
</div> | ||
</> | ||
); | ||
} |
Oops, something went wrong.