Swatches component and theme selection dropdown base

This commit is contained in:
Shaurya Sharma 2025-03-04 01:44:42 +05:30
parent 2ef356938c
commit 3ae5128281
10 changed files with 292 additions and 6 deletions

View file

@ -15,6 +15,9 @@ export const Color = ({
outerWidth = '142px',
component,
styleDefinition,
componentType = 'color',
CustomOptionList = () => {},
SwatchesToggle = () => {},
}) => {
value = component == 'Button' ? computeColor(styleDefinition, value, meta) : value;
const [showPicker, setShowPicker] = useState(false);
@ -68,9 +71,11 @@ export const Color = ({
const ColorPicker = () => {
return (
<>
{showPicker && (
{SwatchesToggle()}
{showPicker && componentType === 'swatches' && CustomOptionList()}
{showPicker && componentType === 'color' && (
<div>
<div style={coverStyles} onClick={() => setShowPicker(false)} />
{/* <div style={coverStyles} onClick={() => setShowPicker(false)} /> */}
<div style={pickerStyle}>
<SketchPicker
onFocus={() => setShowPicker(true)}

View file

@ -0,0 +1,82 @@
import React, { useState } from 'react';
import ToggleGroup from '@/ToolJetUI/SwitchGroup/ToggleGroup';
import ToggleGroupItem from '@/ToolJetUI/SwitchGroup/ToggleGroupItem';
import cx from 'classnames';
import { Color } from './Color';
import CheckIcon from '@/components/ui/Checkbox/CheckboxUtils/CheckIcon';
export const ColorSwatches = ({
value,
onChange,
pickerStyle = {},
cyLabel,
asBoxShadowPopover = true,
meta,
outerWidth = '142px',
component,
styleDefinition,
}) => {
const [componentType, setComponentType] = useState('color');
return (
<Color
value={value}
onChange={onChange}
pickerStyle={pickerStyle}
cyLabel={cyLabel}
asBoxShadowPopover={asBoxShadowPopover}
meta={meta}
outerWidth={outerWidth}
component={component}
styleDefinition={styleDefinition}
componentType={componentType}
SwatchesToggle={() => (
<>
<SwatchesToggle value={componentType} onChange={setComponentType} />
</>
)}
CustomOptionList={() => (
<div style={{ padding: '8px' }}>
<CustomOption />
<CustomOption />
<CustomOption />
<CustomOption />
</div>
)}
/>
);
};
const SwatchesToggle = ({ value, onChange }) => {
return (
<div className={cx('codebuilder-color-swatches-wrapper')}>
<div className={cx('codebuilder-color-swatches')}>
<ToggleGroup
onValueChange={(value) => {
onChange(value);
}}
defaultValue={value}
>
<ToggleGroupItem key={'swatches'} value={'swatches'}>
Swatches
</ToggleGroupItem>
<ToggleGroupItem key={'color'} value={'color'}>
Color picker
</ToggleGroupItem>
</ToggleGroup>
</div>
</div>
);
};
const CustomOption = () => {
return (
<div className="codebuilder-color-swatches-options">
<div className="d-flex align-items-center">
<CheckIcon size="large" fill="#4368E3" />
<div className="color-icon" />
<span style={{ marginLeft: '5px' }}>Test</span>
</div>
</div>
);
};

View file

@ -18,9 +18,11 @@ import { NumberInput } from '../CodeBuilder/Elements/NumberInput';
import { Datepicker } from '../CodeBuilder/Elements/Datepicker';
import TableRowHeightInput from '../CodeBuilder/Elements/TableRowHeightInput';
import { TimePicker } from '../CodeBuilder/Elements/TimePicker';
import { ColorSwatches } from '../CodeBuilder/Elements/ColorSwatches';
const AllElements = {
Color,
ColorSwatches,
Json,
Toggle,
Select,

View file

@ -337,6 +337,7 @@ export const FxParamTypeMapping = Object.freeze({
color: 'Color',
json: 'Json',
code: 'Code',
colorSwatches: 'ColorSwatches',
toggle: 'Toggle',
select: 'Select',
alignButtons: 'AlignButtons',

View file

@ -0,0 +1,131 @@
import React from 'react';
import Select from '@/_ui/Select';
import CheckMark from '@/_ui/Icon/bulkIcons/CheckMark';
import { components } from 'react-select';
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
const ThemeSelect = ({ darkMode }) => {
const customSelectStyles = {
control: (provided) => ({
...provided,
width: '158px',
height: '32px',
minHeight: '32px',
}),
input: (provided) => ({
...provided,
width: '150px',
height: 'auto',
padding: '0px',
}),
valueContainer: (provided, _state) => ({
...provided,
fontSize: '12px',
height: '100%',
}),
menu: (provided) => ({
...provided,
width: '220px',
right: '0',
left: 'auto',
}),
menuList: (provided) => ({
...provided,
width: '220px',
textAlign: 'left',
overflowY: 'auto', // Enable scrolling if needed
scrollbarWidth: 'none', // Hide scrollbar for Firefox
borderRadius: '8px',
}),
option: (provided, state) => ({
...provided,
backgroundColor: state.isFocused
? '#f0f0f0' // Hover color
: state.isSelected
? '#e6e6e6' // Selected background color
: 'white',
color: state.isSelected ? '#333' : 'black', // Adjust text color for selected state
padding: '0px',
paddingLeft: '20px',
position: 'relative',
}),
};
const CustomOption = (props) => {
const { data, isSelected } = props;
return (
<components.Option {...props}>
<div
style={{
display: 'flex',
alignItems: 'center', // Ensures vertical alignment
gap: '10px', // Space between icon and text
height: '30px',
}}
>
{isSelected && (
<CheckMark fill="transparent" fillIcon={'var(--primary-brand)'} className="datepicker-select-check" />
)}
<div className="color-icon" />
<span style={{ fontSize: '12px', marginLeft: '5px', color: darkMode ? '#fff' : '#000' }}>{data.label}</span>
</div>
</components.Option>
);
};
const CustomMenuList = (props) => {
return (
<components.MenuList {...props}>
<div style={{ marginTop: '14px', marginBottom: '8px' }}>
<span className="theme-custom-menu-list-header">On your workspace</span>
</div>
{props.children}
<div
style={{
display: 'flex',
justifyContent: 'center',
padding: '8px',
borderTop: '1px solid #ccc',
height: '46px',
}}
>
<ButtonSolid
onClick={() => {}}
variant="tertiary"
leftIcon="addrectangle"
fill="var(--primary-brand)"
iconWidth="16"
className="tj-text-xsm theme-create-btn"
>
Create a new theme
</ButtonSolid>
</div>
</components.MenuList>
);
};
return (
<div className="d-flex theme-dropdown-wrapper mb-3">
<div className="d-flex align-items-center ">
<p className="tj-text-xsm color-slate12 w-full m-auto">Theme</p>
</div>
<Select
options={[
{ name: 'Authorization code', value: 'authorization_code' },
{ name: 'Client credentials', value: 'client_credentials' },
]}
value={'authorization_code'}
onChange={(value) => {}}
width={'100%'}
useMenuPortal={true}
styles={customSelectStyles}
useCustomStyles={true}
components={{ Option: CustomOption, MenuList: CustomMenuList }}
/>
</div>
);
};
export default ThemeSelect;

View file

@ -7,6 +7,7 @@ import AppExport from './AppExport';
import useStore from '@/AppBuilder/_stores/store';
import { shallow } from 'zustand/shallow';
import AppModeToggle from './AppModeToggle';
import ThemeSelect from './ThemeSelect';
const GlobalSettings = ({ darkMode }) => {
const shouldFreeze = useStore((state) => state.getShouldFreeze());
@ -25,6 +26,7 @@ const GlobalSettings = ({ darkMode }) => {
<div className="tj-text-xsm color-slate12 ">
<CanvasSettings darkMode={darkMode} />
<AppModeToggle darkMode={darkMode} />
<ThemeSelect darkMode={darkMode} />
<AppExport darkMode={darkMode} />
</div>
</div>

View file

@ -144,7 +144,7 @@ export const textinputConfig = {
accordian: 'field',
},
accentColor: {
type: 'color',
type: 'colorSwatches',
displayName: 'Accent',
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
accordian: 'field',

View file

@ -18562,4 +18562,67 @@ section.ai-message-prompt-input-wrapper {
margin-left: 8px;
flex-grow: 1;
}
}
.codebuilder-color-swatches-wrapper {
min-width: 231.333px;
width: 100%;
height: 48px;
padding: 8px;
.codebuilder-color-swatches {
display: flex;
padding: 2px;
flex-wrap: wrap;
.ToggleGroup {
width: 100%;
height: 100%;
}
}
}
.codebuilder-color-swatches-options {
width:100%;
height:30px;
padding: 6px 8px;
border-radius: 6px;
&:hover {
background-color: #f0f1f2 !important;
}
.color-icon {
width: 18px;
height: 18px;
border-radius: 4px;
border: 1.5px solid #CCD1D5;
background-color: #0091FF;
}
}
.theme-dropdown-wrapper {
gap: 75px;
height: 32px;
margin-bottom: 20px !important;
justify-content: space-between;
}
.theme-custom-menu-list-header {
margin: 16px 14px 0px 16px !important;
font-size: 12px;
}
.theme-create-btn {
width: 100%;
margin-bottom: 8px;
height:32px;
color:#000;
border: 1px solid var(--Border-brand-weak, #97AEFC);
}

View file

@ -1,6 +1,6 @@
import React from 'react';
const CheckIcon = ({ size }) => {
const CheckIcon = ({ size, fill = 'white' }) => {
const className = size === 'large' ? 'tw-h-[20px] tw-w-[20px]' : 'tw-h-[16px] tw-w-[16px]';
return (
<svg
@ -15,7 +15,7 @@ const CheckIcon = ({ size }) => {
fillRule="evenodd"
clipRule="evenodd"
d="M8.93064 0.811811C9.20532 1.03656 9.24581 1.44146 9.02106 1.71616L4.64307 7.12414C3.98209 8.00969 3.34866 7.75601 2.80188 7.27755L1.05248 5.74684C0.785368 5.5131 0.758301 5.10709 0.992027 4.83998C1.22575 4.57286 1.63177 4.54579 1.89888 4.77952L3.64828 6.31027L8.02628 0.902247C8.25102 0.627539 8.6559 0.58705 8.93064 0.811811Z"
fill="white"
fill={fill}
/>
</svg>
);

View file

@ -144,7 +144,7 @@ export const textinputConfig = {
accordian: 'field',
},
accentColor: {
type: 'color',
type: 'colorSwatches',
displayName: 'Accent',
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
accordian: 'field',