diff --git a/apps/widget/src/components/Common/Container/Container.tsx b/apps/widget/src/components/Common/Container/Container.tsx index 10567f9e8..93f4232a5 100644 --- a/apps/widget/src/components/Common/Container/Container.tsx +++ b/apps/widget/src/components/Common/Container/Container.tsx @@ -8,7 +8,7 @@ import { useEffect, useState, PropsWithChildren, useMemo } from 'react'; import { ApiService } from '@api'; import { Provider } from '../Provider'; import { MessageHandlerDataType } from '@types'; -import { ParentWindow, deepMerge } from '@util'; +import { ParentWindow, deepMerge, getContrastingTextColor, getSecondaryTextColor, isColorDark } from '@util'; import { WIDGET_TEXTS, isObject } from '@impler/client'; import { API_URL, colors, mantineConfig, variables } from '@config'; import { IWidgetShowPayload, WidgetEventTypesEnum } from '@impler/shared'; @@ -89,6 +89,11 @@ export function Container({ children }: PropsWithChildren<{}>) { } const primaryColor = secondaryPayload.appearance?.primaryColor ?? secondaryPayload.primaryColor ?? colors.primary; + const backgroundColor = secondaryPayload.appearance?.widget?.backgroundColor ?? colors.white; + + // Dynamic text colors based on background + const textColor = getContrastingTextColor(backgroundColor); + const secondaryTextColor = getSecondaryTextColor(backgroundColor); const primaryButtonConfig = secondaryPayload.appearance?.primaryButtonConfig; const secondaryButtonConfig = secondaryPayload.appearance?.secondaryButtonConfig; @@ -139,10 +144,15 @@ export function Container({ children }: PropsWithChildren<{}>) { //common '--border-radius': secondaryPayload.appearance?.borderRadius || '0.25rem', - '--label-color': '#868e96', + '--label-color': secondaryTextColor, '--error-color': '#f03e3e', - '--border-color': colors.lightDeem, - '--background-color': secondaryPayload.appearance?.widget?.backgroundColor ?? colors.white, + '--border-color': isColorDark(backgroundColor) ? '#444' : colors.lightDeem, + '--background-color': backgroundColor, + '--text-color': textColor, + '--secondary-text-color': secondaryTextColor, + + // Table-specific hover colors (much more subtle) + '--table-hover-background': primaryColorShades[2], // stepper '--stepper-background': '#f1f3f5', @@ -156,7 +166,6 @@ export function Container({ children }: PropsWithChildren<{}>) { '--stepper-progress-border-color': primaryColor, '--stepper-border-radius': '0px', '--stepper-color': '#666', - // button //Primary Button Variables @@ -169,16 +178,19 @@ export function Container({ children }: PropsWithChildren<{}>) { // Secondary Button Variables '--button-secondary-color': secondaryButtonConfig?.textColor ?? primaryColor, - '--button-secondary-background': secondaryButtonConfig?.backgroundColor ?? colors.white, - '--button-secondary-background-hover': secondaryButtonConfig?.hoverBackground ?? primaryColorShades?.[0], + '--button-secondary-background': + secondaryButtonConfig?.backgroundColor ?? (isColorDark(backgroundColor) ? '#4a4a4a' : colors.white), + '--button-secondary-background-hover': + secondaryButtonConfig?.hoverBackground ?? + (isColorDark(backgroundColor) ? '#5a5a5a' : primaryColorShades?.[0]), '--button-secondary-border-color': secondaryButtonConfig?.borderColor ?? primaryColor, '--button-secondary-border-hover': secondaryButtonConfig?.hoverBorderColor ?? primaryColor, '--button-secondary-shadow': secondaryButtonConfig?.buttonShadow ?? 'none', // counts - '--counts-background': '#f1f3f5', + '--counts-background': isColorDark(backgroundColor) ? '#3a3a3a' : '#f1f3f5', '--counts-border-radius': '2rem', - '--counts-active-background': '#ffffff', + '--counts-active-background': backgroundColor, }, '.tippy-box[data-theme~="custom"]': { color: 'black', @@ -209,7 +221,21 @@ export function Container({ children }: PropsWithChildren<{}>) { fontFamily: `${secondaryPayload.appearance?.fontFamily || 'Poppins'}, sans-serif`, globalStyles: () => ({ '*': { - color: secondaryPayload.colorScheme, // textColor + color: textColor, // Use the calculated text color + }, + body: { + backgroundColor: backgroundColor, + color: textColor, + }, + // Additional global styles for better text contrast + 'h1, h2, h3, h4, h5, h6': { + color: textColor, + }, + 'p, span, div': { + color: textColor, + }, + label: { + color: secondaryTextColor, }, }), components: { @@ -241,13 +267,6 @@ export function Container({ children }: PropsWithChildren<{}>) { }, }, - Modal: { - styles: { - content: { - backgroundColor: 'var(--background-color)', - }, - }, - }, Button: { styles: { root: { @@ -335,30 +354,225 @@ export function Container({ children }: PropsWithChildren<{}>) { }, }, + DirectEntryView: { + styles: () => ({ + root: { + backgroundColor: isColorDark(backgroundColor) ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.02)', + border: `2px dashed ${isColorDark(backgroundColor) ? '#555' : '#d1d5db'}`, + borderRadius: '8px', + padding: '24px', + transition: 'all 0.2s ease', + color: isColorDark(backgroundColor) ? '#a0a0a0' : '#6b7280', + minHeight: '200px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + + '&:hover': { + backgroundColor: isColorDark(backgroundColor) ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.04)', + borderColor: primaryColor, + transform: 'translateY(-1px)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)', + }, + + // Style any text elements inside + '& .mantine-Text-root': { + color: 'inherit', + }, + + // Style icons if present + '& svg': { + color: 'inherit', + opacity: 0.7, + }, + + // Style any buttons inside the DirectEntryView + '& button': { + '&[data-variant=filled]': { + backgroundColor: 'var(--button-primary-background)', + color: 'var(--button-primary-color)', + border: 'none', + + '&:hover': { + backgroundColor: 'var(--button-primary-background-hover)', + }, + }, + '&[data-variant=outline]': { + backgroundColor: 'var(--button-secondary-background)', + borderColor: 'var(--button-secondary-border-color)', + color: 'var(--button-secondary-color)', + + '&:hover': { + backgroundColor: 'var(--button-secondary-background-hover)', + }, + }, + }, + }, + }), + }, + // Replace your existing Dropzone styles with this: Dropzone: { - styles: { + styles: () => ({ root: { + // Use a more visible background with better contrast + backgroundColor: isColorDark(backgroundColor) + ? 'rgba(255, 255, 255, 0.05)' // Very light white overlay for dark themes + : 'rgba(0, 0, 0, 0.02)', // Very light dark overlay for light themes + + border: `2px dashed ${isColorDark(backgroundColor) ? '#555' : '#d1d5db'}`, + borderRadius: '8px', + padding: '24px', + transition: 'all 0.2s ease', + + // Text color with better contrast + color: isColorDark(backgroundColor) ? '#a0a0a0' : '#6b7280', + + // Ensure minimum contrast + minHeight: '200px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + '&[data-has-error]': { borderColor: 'var(--error-color)', + backgroundColor: isColorDark(backgroundColor) + ? 'rgba(240, 62, 62, 0.1)' + : 'rgba(240, 62, 62, 0.05)', color: 'var(--error-color)', - text: { - color: 'var(--error-color)', - }, }, + '&:hover': { - backgroundColor: 'lightgrey', + backgroundColor: isColorDark(backgroundColor) + ? 'rgba(255, 255, 255, 0.08)' // Slightly more visible on hover + : 'rgba(0, 0, 0, 0.04)', + borderColor: primaryColor, + transform: 'translateY(-1px)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)', }, - button: { + + // Style the button inside dropzone + '& button': { '&[data-variant=filled]': { backgroundColor: 'var(--button-primary-background)', - '.mantine-Button-label': { - color: 'var(--button-primary-color)', - }, + color: 'var(--button-primary-color)', + border: 'none', + '&:hover': { backgroundColor: 'var(--button-primary-background-hover)', }, }, }, + + // Style text elements inside dropzone + '& .mantine-Text-root': { + color: 'inherit', + }, + + // Style icon if present + '& svg': { + color: 'inherit', + opacity: 0.7, + }, + }, + }), + }, + + // Add these new component styles for the manual entry section: + Card: { + styles: { + root: { + backgroundColor: 'var(--background-color)', + borderColor: 'var(--border-color)', + color: 'var(--text-color)', + }, + }, + }, + Table: { + styles: (theme) => ({ + root: { + borderRadius: theme.radius.md, + overflow: 'hidden', + fontSize: theme.fontSizes.sm, + backgroundColor: 'transparent', + color: 'var(--text-color)', + }, + + thead: { + backgroundColor: 'var(--stepper-background)', + }, + + 'thead th': { + backgroundColor: 'var(--stepper-background)', + color: 'var(--text-color)', + fontWeight: 600, + borderBottom: `1px solid var(--border-color)`, + padding: '12px', + textAlign: 'left', + }, + + 'tbody td': { + color: 'var(--text-color)', + padding: '12px', + borderBottom: `1px solid var(--border-color)`, + backgroundColor: 'var(--background-color)', + }, + + 'tbody tr': { + transition: 'background-color 0.2s ease', + + '&:nth-of-type(even)': { + backgroundColor: 'var(--stepper-background)', + }, + + // Updated hover with much more subtle color + '&:hover': { + backgroundColor: 'var(--table-hover-background)', + // Ensure text remains visible + color: 'var(--text-color)', + + // Make sure all child elements maintain proper text color + '& td': { + color: 'var(--text-color)', + }, + }, + }, + + /* + * Optional: selected row style + * 'tbody tr[data-selected="true"]': { + * backgroundColor: 'var(--button-primary-background)', + * color: 'var(--button-primary-color)', + * '&:hover': { + * backgroundColor: 'var(--button-primary-background-hover)', + * }, + * }, + */ + }), + }, + Input: { + styles: { + input: { + borderColor: 'var(--border-color)', + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + '&:focus': { + borderColor: 'var(--button-primary-background)', + }, + '&::placeholder': { + color: 'var(--secondary-text-color)', + }, + }, + }, + }, + + Alert: { + styles: { + root: { + backgroundColor: primaryColorShades[0], + borderColor: primaryColorShades[2], + color: primaryColorShades[7], }, }, }, @@ -369,6 +583,234 @@ export function Container({ children }: PropsWithChildren<{}>) { }, }, }, + SegmentedControl: { + styles: (theme) => ({ + root: { + backgroundColor: theme.fn.rgba(theme.colors[theme.primaryColor][5], 0.06), + borderRadius: 'var(--border-radius)', + padding: '4px', + border: `1px solid var(--border-color)`, + }, + + control: { + borderRadius: 'calc(var(--border-radius) - 2px)', + border: 'none !important', + transition: 'all 0.2s ease', + color: 'var(--text-color) !important', + + '&:not([data-active])': { + backgroundColor: 'transparent', + color: 'var(--text-color) !important', + + '&:hover': { + backgroundColor: isColorDark(backgroundColor) + ? 'rgba(255, 255, 255, 0.05)' + : 'rgba(0, 0, 0, 0.03)', + }, + }, + + '&[data-active]': { + backgroundColor: 'var(--button-primary-background) !important', + color: 'var(--button-primary-color) !important', + boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)', + + '&:hover': { + backgroundColor: 'var(--button-primary-background-hover) !important', + }, + }, + }, + + controlActive: { + backgroundColor: 'var(--button-primary-background) !important', + color: 'var(--button-primary-color) !important', + boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)', + }, + + label: { + fontWeight: 500, + fontSize: theme.fontSizes.sm, + padding: '8px 16px', + transition: 'color 0.2s ease', + color: 'var(--text-color) !important', + }, + + labelActive: { + color: 'var(--button-primary-color) !important', + fontWeight: 600, + }, + }), + }, + + FindReplaceModal: { + styles: (theme) => ({ + root: { + borderRadius: theme.radius.md, + overflow: 'hidden', + fontSize: theme.fontSizes.sm, + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + }, + header: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + borderBottom: `1px solid var(--border-color)`, + }, + title: { + color: 'var(--text-color)', + fontWeight: 600, + }, + body: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + }, + close: { + color: 'var(--text-color)', + '&:hover': { + backgroundColor: 'var(--stepper-background)', + }, + }, + }), + }, + + // Also update your Modal component styles to ensure proper theming: + Modal: { + styles: { + content: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + }, + header: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + borderBottom: `1px solid var(--border-color)`, + }, + title: { + color: 'var(--text-color)', + fontWeight: 600, + }, + body: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + }, + close: { + color: 'var(--text-color)', + '&:hover': { + backgroundColor: 'var(--stepper-background)', + }, + }, + }, + }, + + // Add/update TextInput and Select components to use your CSS variables: + TextInput: { + styles: { + input: { + borderColor: 'var(--border-color)', + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + '&:focus': { + borderColor: 'var(--button-primary-background)', + }, + '&::placeholder': { + color: 'var(--secondary-text-color)', + }, + }, + label: { + color: 'var(--label-color)', + fontWeight: 500, + }, + }, + }, + + Select: { + styles: { + input: { + borderColor: 'var(--border-color)', + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + '&:focus': { + borderColor: 'var(--button-primary-background)', + }, + }, + label: { + color: 'var(--label-color)', + fontWeight: 500, + }, + item: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + '&:hover': { + backgroundColor: 'var(--stepper-background)', + }, + '&[data-selected]': { + backgroundColor: 'var(--button-primary-background)', + color: 'var(--button-primary-color)', + }, + }, + dropdown: { + backgroundColor: 'var(--background-color)', + borderColor: 'var(--border-color)', + }, + }, + }, + + // Add Checkbox component styling: + Checkbox: { + styles: { + input: { + borderColor: 'var(--border-color)', + backgroundColor: 'var(--background-color)', + '&:checked': { + backgroundColor: 'var(--button-primary-background)', + borderColor: 'var(--button-primary-background)', + }, + }, + label: { + color: 'var(--text-color)', + fontWeight: 500, + }, + }, + }, + + // Just add this to your Container.tsx components section + Pagination: { + styles: () => ({ + item: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + border: '1px solid var(--border-color)', + + '&[data-active="true"]': { + backgroundColor: 'var(--button-primary-background)', + color: 'var(--button-primary-color)', + border: '1px solid var(--button-primary-background)', + }, + + '&:hover:not([data-active="true"])': { + backgroundColor: 'var(--stepper-background)', + }, + }, + + control: { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + border: '1px solid var(--border-color)', + + '&:hover:not(:disabled)': { + backgroundColor: 'var(--button-primary-background)', + color: 'var(--button-primary-color)', + border: '1px solid var(--button-primary-background)', + }, + + '&:disabled': { + backgroundColor: 'var(--stepper-background)', + color: 'var(--secondary-text-color)', + opacity: 0.5, + cursor: 'not-allowed', + }, + }, + }), + }, }, colors: { // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/apps/widget/src/components/Common/Table/HandsonTable.styles.min.css b/apps/widget/src/components/Common/Table/HandsonTable.styles.min.css index 35515f14b..153eb0fdd 100644 --- a/apps/widget/src/components/Common/Table/HandsonTable.styles.min.css +++ b/apps/widget/src/components/Common/Table/HandsonTable.styles.min.css @@ -1,32 +1,51 @@ +/* Handsontable base styling with theme integration */ +.handsontable { + background-color: var(--background-color) !important; + color: var(--text-color) !important; +} .handsontable td { overflow: unset !important; border-color: var(--border-color) !important; + background-color: var(--background-color) !important; + color: var(--text-color) !important; } + .handsontable th { - background-color: var(--stepper-background) !important; - border-color: var(--border-color) !important; + background-color: '#f1f3f5'; + background-color: var(--background-color) !important; + border-color: var(--border-color) !important; + background-color: #ffcccc; + + /*Here Add*/ } + .htCore thead tr th { padding: 0.3rem !important; vertical-align: middle !important; +background-color: '#f1f3f5'; + color: var(--text-color) !important; } + .custom-cell { text-align: center; vertical-align: middle !important; padding: 5px !important; + background-color: white !important; } + .cell-value { max-width: 70%; display: inline-block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; + color: var(--text-color) !important; } .index-cell { text-align: center; vertical-align: middle !important; - background-color: #f0f0f0 !important; - color: #222 !important; + background-color: var(--background-color) !important; + color: var(--text-color) !important; padding: 5px !important; } .check-box { @@ -34,42 +53,48 @@ cursor: pointer; vertical-align: middle; } + .check-cell { height: 24px !important; cursor: pointer; text-align: center; padding: 0.5rem !important; + background-color: var(--background-color) !important; } + .check-cell .check-box { width: 15px; height: 15px; } + .check-all-cell { cursor: pointer; text-align: center; padding: 0.3rem !important; + background-color: var(--background-color) !important; } + .check-all-cell .check-box { width: 15px; height: 15px; + background-color: var(--background-color) !important; } .checkbox { display: inline-flex; position: relative; vertical-align: middle; } - + .checkbox__control { -webkit-appearance: none; appearance: none; z-index: 1; - border: 0.5px solid #51cf66; + border: 0.5px solid var(--button-primary-background); width: 15px; height: 15px; - border-radius: 0.25rem; margin: 0; cursor: pointer; - background-color: #51cf66; + background-color: var(--button-primary-background); } .checkbox__control-icon { @@ -79,22 +104,24 @@ transition: opacity 400ms ease-in-out; opacity: 0; z-index: 2; - color: #fff; - border-radius: 0.25rem; + color: var(--button-primary-color); + border-radius: var(--border-radius); } -.checkbox__control:checked + .checkbox__control-icon { +.checkbox__control:checked+.checkbox__control-icon { opacity: 1; } .list-wrapper { width: auto; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.09); - background-color: #fff; + box-shadow: 0 0 0 1px var(--border-color); + background-color: var(--background-color); visibility: hidden; z-index: 300; position: absolute; + border: 1px solid var(--border-color); } + .list-wrapper.open { visibility: visible; position: absolute; @@ -103,8 +130,8 @@ max-width: 100%; z-index: 300; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - border: 1px solid #ddd; - background: white; + border: 1px solid var(--border-color); + background: var(--background-color); overflow: hidden; box-sizing: border-box; top: 100%; @@ -112,15 +139,14 @@ margin: 0; } - .list-wrapper ul { position: fixed; height: 180px; width: 191px; - background: white; + background: var(--background-color); overflow: auto; margin-bottom: -20px; - border: 1px solid #ddd; + border: 1px solid var(--border-color); } .list-wrapper.open ul { @@ -133,6 +159,7 @@ padding: 0; border: none; position: relative; + background: var(--background-color); } .list-wrapper:hover .option:not(:hover) { @@ -145,25 +172,27 @@ z-index: 999; top: 100%; left: 0; - border: 1px solid #ddd; + border: 1px solid var(--border-color); width: 100%; + background: var(--background-color); } -/* .ht_clone_left { - box-shadow: 2px 0px 6px 0px rgb(0 0 0 / 20%); -} */ - .dd-searchbox { padding: 0.5rem; - background-color: #fff; - color: #000; - border: none; + background-color: var(--background-color); + color: var(--text-color); + border: 1px solid var(--border-color); outline: none; width: 100%; min-width: min-content; max-width: 100%; box-sizing: border-box; text-overflow: ellipsis; + border-radius: var(--border-radius); + } + + .dd-searchbox:focus { + border-color: var(--button-primary-background); } .option { @@ -172,21 +201,30 @@ padding: 0.5rem; list-style: none; width: 100%; + background-color: var(--background-color); + color: var(--text-color); + transition: background-color 0.2s ease; } .option:hover, .option:focus { - background-color: #d3d3d3 !important; + background-color: var(--table-hover-background) !important; + color: var(--text-color) !important; } .option.selected { overflow: hidden; width: 100%; font-weight: 600; - background-color: #f6f6f6 !important; -} + background-color: var(--stepper-background) !important; + color: var(--text-color); + } + + .option.highlighted { + background-color: var(--table-hover-background) !important; + color: var(--text-color) !important; + } .input-wrapper { - /* max-width: 100%; */ width: inherit; display: flex; flex-wrap: wrap; @@ -195,29 +233,181 @@ max-width: fit-content; box-sizing: border-box; position: relative; + background-color: var(--background-color); } + .item { display: flex; cursor: pointer; align-items: center; - border-radius: 10px; + border-radius: var(--border-radius); padding: 0.0225rem 0.15rem; - background-color: #e7eaee; - border: 1px solid #dbdfe6; -} + background-color: var(--stepper-background); + border: 1px solid var(--border-color); + color: var(--text-color); + transition: all 0.2s ease; + } + + .item:hover { + background-color: var(--table-hover-background); + } .item svg { height: 20px; width: 20px; - transition: background-color 400ms ease-in-out; + transition: color 400ms ease-in-out; } + .item:hover svg { color: red; } + .items { gap: 2px; display: flex; flex-wrap: wrap; } -li.option.highlighted { - background-color: #d3d3d3 !important; +/* Additional Handsontable specific overrides */ +.handsontable .htCore { + background-color: var(--background-color) !important; +} + +.handsontable .htCore .htInvalid, +.handsontable .htCore .error-cell, +.handsontable td.htInvalid, +.handsontable td.error-cell, +.handsontable td.custom-cell.error-cell { + background-color: #fdebeb !important; + color: #c62828 !important; +} + +.handsontable .htCore .htWarning, +.handsontable .htCore .warning-cell, +.handsontable td.htWarning, +.handsontable td.warning-cell, +.handsontable td.custom-cell.warning-cell { + background-color: #fff3e0 !important; + color: #ef6c00 !important; + border: 1px solid #ff9800 !important; +} + +.handsontable .htCore .htSelected { + background-color: var(--button-primary-background) !important; + color: var(--button-primary-color) !important; +} + +.handsontable .htCore .htCurrentCell { + border: 2px solid var(--button-primary-background) !important; +} + +.handsontable .custom-cell.error-cell { + background-color: #ffebeb !important; + color: var(--text-color) !important; +} + +.handsontable .custom-cell.warning-cell { + background-color: #ffda6b !important; + color: var(--text-color) !important; + border: 1px solid #ffc107 !important; +} + +.handsontable .custom-cell.updated-cell { + background-color: #ffda6b !important; +} + +.handsontable .custom-cell.updated-cell.error-cell { + background-color: #ffda6b !important; + color: var(--text-color) !important; +} + +.handsontable .htCore .htInvalid, +.handsontable .htCore .error-cell, +.handsontable td.htInvalid, +.handsontable td.error-cell, +.handsontable td.custom-cell.error-cell { + background-color: #ffebeb !important; + color: var(--text-color) !important; +} + +.handsontable .htCore .htWarning, +.handsontable .htCore .warning-cell, +.handsontable td.htWarning, +.handsontable td.warning-cell, +.handsontable td.custom-cell.warning-cell { + background-color: #ffda6b !important; + color: var(--text-color) !important; + border: 1px solid #ffc107 !important; +} + + + + +@media (prefers-color-scheme: dark) { + + .handsontable .htCore .htInvalid, + .handsontable .htCore .error-cell, + .handsontable td.htInvalid, + .handsontable td.error-cell, + .handsontable td.custom-cell.error-cell { + background-color: #ffebeb !important; + color: var(--text-color) !important; + } + + .handsontable .htCore .htWarning, + .handsontable .htCore .warning-cell, + .handsontable td.htWarning, + .handsontable td.warning-cell, + .handsontable td.custom-cell.warning-cell { + background-color: #ffda6b !important; + color: var(--text-color) !important; + border: 1px solid #ffc107 !important; + } + + .handsontable .custom-cell.updated-cell { + background-color: #ffda6b !important; + } +} + +/* Handsontable scrollbars */ +.handsontable .wtHolder::-webkit-scrollbar { + width: 7px; + height: 7px; +} + +.handsontable .wtHolder::-webkit-scrollbar-track { + box-shadow: inset 0 0 3px var(--border-color); + border-radius: 10px; +} + +.handsontable .wtHolder::-webkit-scrollbar-thumb { + background: var(--button-primary-background); + border-radius: 10px; +} + +.handsontable .ht_clone_left th, +.handsontable .ht_clone_top th { + background-color: var(--background-color) !important; + color: var(--text-color) !important; + border-color: var(--border-color) !important; + + + /*Here add*/ +} + + +/* Context menu theming */ +.htContextMenu { + background-color: var(--background-color) !important; + border: 1px solid var(--border-color) !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.htContextMenu tbody tr td { + background-color: var(--background-color) !important; + color: var(--text-color) !important; + border-color: var(--border-color) !important; +} + +.htContextMenu tbody tr:hover td { + background-color: var(--button-secondary-background-hover) !important; + color: var(--text-color) !important; } \ No newline at end of file diff --git a/apps/widget/src/components/Common/Table/Table.tsx b/apps/widget/src/components/Common/Table/Table.tsx index a38c3d7a2..8934605f6 100644 --- a/apps/widget/src/components/Common/Table/Table.tsx +++ b/apps/widget/src/components/Common/Table/Table.tsx @@ -49,7 +49,7 @@ const createErrorSvg = memoize(() => { errorSvg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); errorSvg.setAttribute('viewBox', '-2 -2 24 24'); errorSvg.setAttribute('width', '20'); - errorSvg.setAttribute('fill', 'currentColor'); + errorSvg.setAttribute('fill', 'var(--error-color)'); const errorSvgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); errorSvgPath.setAttribute( 'd', @@ -76,9 +76,13 @@ Handsontable.renderers.registerRenderer( const hasWarnings = sourceData.warnings?.[name]; const isUpdated = sourceData.updated?.[name]; + // Reset classes first TD.className = 'custom-cell'; TD.ariaLabel = ''; + // Remove any inline background styles + TD.style.backgroundColor = ''; + let fieldValue = sourceData.record?.[name] ?? null; if (typeof fieldValue === 'string' && fieldValue.length > name.length + 20) { @@ -101,29 +105,30 @@ Handsontable.renderers.registerRenderer( if (fieldValue !== null) valueSpan.textContent = fieldValue; TD.appendChild(valueSpan); + // Apply CSS classes instead of inline styles if (isUpdated) { + TD.classList.add('updated-cell'); errorSvg.setAttribute('style', memoizedStyles.errorUpdated); if (hasError) { + TD.classList.add('error-cell'); TD.appendChild(errorSvg); } - TD.style.backgroundColor = '#ffda5b'; } else if (hasError) { + TD.classList.add('error-cell'); errorSvg.setAttribute('style', memoizedStyles.errorOnly); TD.appendChild(errorSvg); - TD.style.backgroundColor = '#fdebeb'; } else if (hasWarnings) { + TD.classList.add('warning-cell'); TD.ariaLabel = hasWarnings; TD.dataset.cooltipzDir = row < 5 ? 'bottom' : 'top'; TD.dataset.cooltipzSize = 'fit'; errorSvg.setAttribute('style', hasWarnings ? memoizedStyles.warningOnly : memoizedStyles.errorUpdated); TD.appendChild(errorSvg); - TD.style.backgroundColor = '#ffda5b'; } return TD; } ); - Handsontable.renderers.registerRenderer( 'check', // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars diff --git a/apps/widget/src/components/widget/Phases/Phase3/Phase3.tsx b/apps/widget/src/components/widget/Phases/Phase3/Phase3.tsx index 22f0e0a0e..f341805dd 100644 --- a/apps/widget/src/components/widget/Phases/Phase3/Phase3.tsx +++ b/apps/widget/src/components/widget/Phases/Phase3/Phase3.tsx @@ -128,7 +128,7 @@ export function Phase3(props: IPhase3Props) { onClick={() => setShowDeleteConfirmModal(true)} > {texts.COMMON.DELETE} - + {numberFormatter(selectedRowsRef.current.size)} diff --git a/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.styles.tsx b/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.styles.tsx new file mode 100644 index 000000000..760e890dc --- /dev/null +++ b/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.styles.tsx @@ -0,0 +1,106 @@ +import { createStyles, MantineTheme } from '@mantine/core'; + +export const useStyles = createStyles((theme: MantineTheme) => ({ + modal: { + backgroundColor: 'var(--background-color)', + borderRadius: theme.radius.md, + boxShadow: theme.shadows.md, + padding: theme.spacing.xl, + color: 'var(--text-color)', + }, + + header: { + marginBottom: '1rem', + color: 'var(--text-color)', + }, + + title: { + color: 'var(--text-color)', + fontWeight: 600, + fontSize: theme.fontSizes.xl, + }, + + label: { + color: 'var(--label-color)', + fontWeight: 500, + fontSize: theme.fontSizes.lg, + }, + + input: { + color: 'var(--text-color)', + backgroundColor: 'var(--background-color)', + borderColor: 'var(--border-color)', + + '&::placeholder': { + color: 'var(--secondary-text-color)', + }, + + '&:focus': { + borderColor: 'var(--button-primary-background)', + }, + }, + + select: { + '& .mantine-Select-input': { + color: 'var(--text-color)', + backgroundColor: 'var(--background-color)', + borderColor: 'var(--border-color)', + }, + + '& .mantine-Select-label': { + color: 'var(--label-color)', + fontWeight: 500, + fontSize: theme.fontSizes.lg, + }, + + '& .mantine-Select-dropdown': { + backgroundColor: 'var(--background-color)', + borderColor: 'var(--border-color)', + }, + + '& .mantine-Select-item': { + backgroundColor: 'var(--background-color)', + color: 'var(--text-color)', + + '&:hover': { + backgroundColor: 'var(--stepper-background)', + }, + + '&[data-selected]': { + backgroundColor: 'var(--button-primary-background)', + color: 'var(--button-primary-color)', + }, + }, + }, + + checkbox: { + '& .mantine-Checkbox-input': { + borderColor: 'var(--border-color)', + backgroundColor: 'var(--background-color)', + + '&:checked': { + backgroundColor: 'var(--button-primary-background)', + borderColor: 'var(--button-primary-background)', + }, + }, + + '& .mantine-Checkbox-label': { + color: 'var(--text-color)', + fontWeight: 500, + fontSize: theme.fontSizes.lg, + }, + }, + + // Additional utility classes for consistent theming + text: { + color: 'var(--text-color)', + }, + + secondaryText: { + color: 'var(--secondary-text-color)', + }, + + labelText: { + color: 'var(--label-color)', + }, +})); diff --git a/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.tsx b/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.tsx index 0da0cad29..7f2af38ef 100644 --- a/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.tsx +++ b/apps/widget/src/components/widget/modals/FindReplace/FindReplaceModal.tsx @@ -10,6 +10,7 @@ import { Button } from '@ui/Button'; import { Select } from '@ui/Select'; import { useAPIState } from '@store/api.context'; import { useAppState } from '@store/app.context'; +import { useStyles } from './FindReplaceModal.styles'; interface IFindReplaceModalProps { opened: boolean; @@ -22,6 +23,7 @@ interface IFindReplaceModalProps { } export function FindReplaceModal(props: IFindReplaceModalProps) { + const { classes } = useStyles(); const { api } = useAPIState(); const { uploadInfo } = useAppState(); const [modifiedCount, setModifiedCount] = useState(); @@ -60,11 +62,11 @@ export function FindReplaceModal(props: IFindReplaceModalProps) {
replaceData(data))}> diff --git a/apps/widget/src/design-system/MappingItem/MappingItem.style.ts b/apps/widget/src/design-system/MappingItem/MappingItem.style.ts index fd38859c2..9f1e6021e 100644 --- a/apps/widget/src/design-system/MappingItem/MappingItem.style.ts +++ b/apps/widget/src/design-system/MappingItem/MappingItem.style.ts @@ -1,5 +1,4 @@ import { createStyles, MantineTheme } from '@mantine/core'; -import { colors } from '../../config/colors.config'; const getRootStyles = (theme: MantineTheme): React.CSSProperties => ({ justifyContent: 'space-between', @@ -28,7 +27,6 @@ const getSelectionRootStyles = (): React.CSSProperties => ({ const getHeadingStyles = (theme: MantineTheme) => ({ padding: theme.spacing.xs, - backgroundColor: colors.light, display: 'flex', alignItems: 'center', width: '50%', @@ -53,6 +51,7 @@ export const getSelectStyles = (theme: MantineTheme, height: number): React.CSSP border: 'none', height: height, cursor: 'pointer', + backgroundColor: 'var(--background-color)', }); export const getSelectRootStyles = (): React.CSSProperties => ({ @@ -66,6 +65,7 @@ export const getStatusTextStyles = (theme: MantineTheme): React.CSSProperties => [`@media (max-width: ${theme.breakpoints.md}px)`]: { flexDirection: 'row-reverse', }, + color: 'var(--label-color)', }); export const getRequiredStyles = (): React.CSSProperties => ({ diff --git a/apps/widget/src/util/helpers/color.helpers.ts b/apps/widget/src/util/helpers/color.helpers.ts index 252045c27..fa02e7881 100644 --- a/apps/widget/src/util/helpers/color.helpers.ts +++ b/apps/widget/src/util/helpers/color.helpers.ts @@ -56,3 +56,29 @@ export function generateShades(color: string, shadesCount = variables.defaultSha return shades.reverse(); } } + +// Helper function to determine if a color is dark +export function isColorDark(color: string): boolean { + // Remove # if present + const hex = color.replace('#', ''); + + // Convert to RGB + const red = parseInt(hex.substr(0, 2), 16); + const green = parseInt(hex.substr(2, 2), 16); + const blue = parseInt(hex.substr(4, 2), 16); + + // Calculate luminance using the relative luminance formula + const luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255; + + return luminance < 0.5; +} + +// Helper function to get contrasting text color +export function getContrastingTextColor(backgroundColor: string): string { + return isColorDark(backgroundColor) ? '#ffffff' : '#000000'; +} + +// Helper function to get a lighter version of the text color for secondary text +export function getSecondaryTextColor(backgroundColor: string): string { + return isColorDark(backgroundColor) ? '#e0e0e0' : '#666666'; +}