setShowPicker(false)} /> */}
setShowPicker(true)}
diff --git a/frontend/src/AppBuilder/CodeBuilder/Elements/ColorSwatches.jsx b/frontend/src/AppBuilder/CodeBuilder/Elements/ColorSwatches.jsx
new file mode 100644
index 0000000000..17bc178862
--- /dev/null
+++ b/frontend/src/AppBuilder/CodeBuilder/Elements/ColorSwatches.jsx
@@ -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 (
+ (
+ <>
+
+ >
+ )}
+ CustomOptionList={() => (
+
+
+
+
+
+
+ )}
+ />
+ );
+};
+
+const SwatchesToggle = ({ value, onChange }) => {
+ return (
+
+
+ {
+ onChange(value);
+ }}
+ defaultValue={value}
+ >
+
+ Swatches
+
+
+ Color picker
+
+
+
+
+ );
+};
+
+const CustomOption = () => {
+ return (
+
+ );
+};
diff --git a/frontend/src/AppBuilder/CodeEditor/DynamicFxTypeRenderer.jsx b/frontend/src/AppBuilder/CodeEditor/DynamicFxTypeRenderer.jsx
index 20b196476d..2e2d17d4af 100644
--- a/frontend/src/AppBuilder/CodeEditor/DynamicFxTypeRenderer.jsx
+++ b/frontend/src/AppBuilder/CodeEditor/DynamicFxTypeRenderer.jsx
@@ -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,
diff --git a/frontend/src/AppBuilder/CodeEditor/utils.js b/frontend/src/AppBuilder/CodeEditor/utils.js
index 03473a629f..73d11e6f62 100644
--- a/frontend/src/AppBuilder/CodeEditor/utils.js
+++ b/frontend/src/AppBuilder/CodeEditor/utils.js
@@ -337,6 +337,7 @@ export const FxParamTypeMapping = Object.freeze({
color: 'Color',
json: 'Json',
code: 'Code',
+ colorSwatches: 'ColorSwatches',
toggle: 'Toggle',
select: 'Select',
alignButtons: 'AlignButtons',
diff --git a/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/ThemeSelect.jsx b/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/ThemeSelect.jsx
new file mode 100644
index 0000000000..74817c21c6
--- /dev/null
+++ b/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/ThemeSelect.jsx
@@ -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 (
+
+
+ {isSelected && (
+
+ )}
+
+
{data.label}
+
+
+ );
+ };
+
+ const CustomMenuList = (props) => {
+ return (
+
+
+ On your workspace
+
+ {props.children}
+
+ {}}
+ variant="tertiary"
+ leftIcon="addrectangle"
+ fill="var(--primary-brand)"
+ iconWidth="16"
+ className="tj-text-xsm theme-create-btn"
+ >
+ Create a new theme
+
+
+
+ );
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default ThemeSelect;
diff --git a/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/index.jsx b/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/index.jsx
index 869677928c..8a86b705d9 100644
--- a/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/index.jsx
+++ b/frontend/src/AppBuilder/LeftSidebar/GlobalSettings/index.jsx
@@ -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 }) => {
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
index 15a52ea306..83efe72b87 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
@@ -144,7 +144,7 @@ export const textinputConfig = {
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
accordian: 'field',
diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss
index c999eaa525..e9836529b8 100644
--- a/frontend/src/_styles/theme.scss
+++ b/frontend/src/_styles/theme.scss
@@ -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);
}
\ No newline at end of file
diff --git a/frontend/src/components/ui/Checkbox/CheckboxUtils/CheckIcon.jsx b/frontend/src/components/ui/Checkbox/CheckboxUtils/CheckIcon.jsx
index 3d3dcd846d..6cd3e33c9c 100644
--- a/frontend/src/components/ui/Checkbox/CheckboxUtils/CheckIcon.jsx
+++ b/frontend/src/components/ui/Checkbox/CheckboxUtils/CheckIcon.jsx
@@ -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 (
);
diff --git a/server/src/modules/apps/services/widget-config/textinput.js b/server/src/modules/apps/services/widget-config/textinput.js
index 15a52ea306..83efe72b87 100644
--- a/server/src/modules/apps/services/widget-config/textinput.js
+++ b/server/src/modules/apps/services/widget-config/textinput.js
@@ -144,7 +144,7 @@ export const textinputConfig = {
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
accordian: 'field',