mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
Swatches component and theme selection dropdown base
This commit is contained in:
parent
2ef356938c
commit
3ae5128281
10 changed files with 292 additions and 6 deletions
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -337,6 +337,7 @@ export const FxParamTypeMapping = Object.freeze({
|
|||
color: 'Color',
|
||||
json: 'Json',
|
||||
code: 'Code',
|
||||
colorSwatches: 'ColorSwatches',
|
||||
toggle: 'Toggle',
|
||||
select: 'Select',
|
||||
alignButtons: 'AlignButtons',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export const textinputConfig = {
|
|||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export const textinputConfig = {
|
|||
accordian: 'field',
|
||||
},
|
||||
accentColor: {
|
||||
type: 'color',
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Accent',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
|
||||
accordian: 'field',
|
||||
|
|
|
|||
Loading…
Reference in a new issue