647c32ff3e
## Summary
- **Eliminate `ICON_SIZES` / `ICON_STROKES` constants**: all icon
dimensions are now resolved at runtime via
`resolveThemeVariableAsNumber(themeCssVariables.icon.size.X)`, ensuring
values always come from computed CSS variables
- **No more consumer imports from `twenty-ui/theme`**: moved
`ColorSchemeContext`, `ColorSchemeProvider`, `ThemeColor`,
`MAIN_COLOR_NAMES`, `getNextThemeColor`, `AnimationDuration` to
`twenty-ui/theme-constants`
- **Remove `ThemeContext` / `ThemeContextProvider` / `ThemeProvider` /
`ThemeType`**: replaced across ~300 files with `themeCssVariables` (for
CSS contexts) or `resolveThemeVariable` / `resolveThemeVariableAsNumber`
(for JS runtime values)
- **Simplify provider chain**: only `ColorSchemeProvider` remains — it
toggles `light`/`dark` class on `document.documentElement` and provides
`colorScheme` via React context
- **Fix pre-existing test failures**: `useIcons.test.ts`
(non-configurable ES module spy) and
`turnRecordFilterGroupIntoGqlOperationFilter.test.ts`
(`Omit<RecordFilter, 'id'>` type mismatch)
### Theme access pattern (before → after)
| Context | Before | After |
|---------|--------|-------|
| CSS (Linaria) | `${({ theme }) => theme.font.color.primary}` |
`${themeCssVariables.font.color.primary}` |
| JS runtime (icon size, animation) | `theme.icon.size.md` /
`ICON_SIZES.md` |
`resolveThemeVariableAsNumber(themeCssVariables.icon.size.md)` |
| Color scheme check | `theme.name === 'dark'` |
`useContext(ColorSchemeContext).colorScheme === 'dark'` |
200 lines
5.5 KiB
TypeScript
200 lines
5.5 KiB
TypeScript
import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation';
|
|
import { getCurrentGraphTypeFromConfig } from '@/command-menu/pages/page-layout/utils/getCurrentGraphTypeFromConfig';
|
|
import { isWidgetConfigurationOfTypeGraph } from '@/command-menu/pages/page-layout/utils/isWidgetConfigurationOfTypeGraph';
|
|
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
|
|
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
|
import { t } from '@lingui/core/macro';
|
|
import { CommandMenuPages } from 'twenty-shared/types';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import {
|
|
IconAppWindow,
|
|
IconFrame,
|
|
IconList,
|
|
IconPlus,
|
|
type IconComponent,
|
|
} from 'twenty-ui/display';
|
|
import { ThemeContext } from 'twenty-ui/theme-constants';
|
|
import { useContext } from 'react';
|
|
|
|
type PageLayoutHeaderInfo = {
|
|
headerIcon: IconComponent | undefined;
|
|
headerIconColor: string;
|
|
headerType: string;
|
|
title: string;
|
|
isReadonly: boolean;
|
|
tab: PageLayoutTab | undefined;
|
|
widgetInEditMode: PageLayoutWidget | undefined;
|
|
};
|
|
|
|
type UsePageLayoutHeaderInfoParams = {
|
|
commandMenuPage: CommandMenuPages;
|
|
draftPageLayout: {
|
|
tabs: PageLayoutTab[];
|
|
};
|
|
pageLayoutEditingWidgetId: string | null | undefined;
|
|
openTabId: string | null | undefined;
|
|
editedTitle: string | null | undefined;
|
|
};
|
|
|
|
export const usePageLayoutHeaderInfo = ({
|
|
commandMenuPage,
|
|
draftPageLayout,
|
|
pageLayoutEditingWidgetId,
|
|
openTabId,
|
|
editedTitle,
|
|
}: UsePageLayoutHeaderInfoParams): PageLayoutHeaderInfo | null => {
|
|
const { theme } = useContext(ThemeContext);
|
|
const iconColor = theme.font.color.tertiary;
|
|
|
|
switch (commandMenuPage) {
|
|
case CommandMenuPages.PageLayoutTabSettings: {
|
|
if (!isDefined(openTabId)) {
|
|
return null;
|
|
}
|
|
|
|
const tab = draftPageLayout.tabs.find((t) => t.id === openTabId);
|
|
|
|
if (!isDefined(tab)) {
|
|
return null;
|
|
}
|
|
|
|
const title = isDefined(editedTitle)
|
|
? editedTitle
|
|
: isDefined(tab.title) && tab.title !== ''
|
|
? tab.title
|
|
: '';
|
|
|
|
return {
|
|
headerIcon: IconAppWindow,
|
|
headerIconColor: iconColor,
|
|
headerType: t`Tab`,
|
|
title,
|
|
isReadonly: false,
|
|
tab,
|
|
widgetInEditMode: undefined,
|
|
};
|
|
}
|
|
|
|
case CommandMenuPages.PageLayoutIframeSettings: {
|
|
if (!isDefined(pageLayoutEditingWidgetId)) {
|
|
return null;
|
|
}
|
|
|
|
const widgetInEditMode = draftPageLayout.tabs
|
|
.flatMap((tab) => tab.widgets)
|
|
.find((widget) => widget.id === pageLayoutEditingWidgetId);
|
|
|
|
if (!isDefined(widgetInEditMode)) {
|
|
return null;
|
|
}
|
|
|
|
const title = isDefined(editedTitle)
|
|
? editedTitle
|
|
: isDefined(widgetInEditMode.title) && widgetInEditMode.title !== ''
|
|
? widgetInEditMode.title
|
|
: '';
|
|
|
|
return {
|
|
headerIcon: IconFrame,
|
|
headerIconColor: iconColor,
|
|
headerType: t`iFrame Widget`,
|
|
title,
|
|
isReadonly: false,
|
|
tab: undefined,
|
|
widgetInEditMode,
|
|
};
|
|
}
|
|
|
|
case CommandMenuPages.PageLayoutGraphTypeSelect:
|
|
case CommandMenuPages.PageLayoutGraphFilter: {
|
|
if (!isDefined(pageLayoutEditingWidgetId)) {
|
|
return null;
|
|
}
|
|
|
|
const widgetInEditMode = draftPageLayout.tabs
|
|
.flatMap((tab) => tab.widgets)
|
|
.find((widget) => widget.id === pageLayoutEditingWidgetId);
|
|
|
|
if (!isDefined(widgetInEditMode)) {
|
|
return null;
|
|
}
|
|
|
|
if (!isWidgetConfigurationOfTypeGraph(widgetInEditMode.configuration)) {
|
|
return null;
|
|
}
|
|
|
|
const currentGraphType = getCurrentGraphTypeFromConfig(
|
|
widgetInEditMode.configuration,
|
|
);
|
|
const graphTypeInfo = GRAPH_TYPE_INFORMATION[currentGraphType];
|
|
const graphTypeLabel = t(graphTypeInfo.label);
|
|
|
|
const headerType =
|
|
commandMenuPage === CommandMenuPages.PageLayoutGraphFilter
|
|
? graphTypeLabel
|
|
: t`Chart`;
|
|
|
|
const title = isDefined(editedTitle)
|
|
? editedTitle
|
|
: isDefined(widgetInEditMode.title) && widgetInEditMode.title !== ''
|
|
? widgetInEditMode.title
|
|
: '';
|
|
|
|
return {
|
|
headerIcon: graphTypeInfo.icon,
|
|
headerIconColor: iconColor,
|
|
headerType,
|
|
title,
|
|
isReadonly: commandMenuPage === CommandMenuPages.PageLayoutGraphFilter,
|
|
tab: undefined,
|
|
widgetInEditMode,
|
|
};
|
|
}
|
|
|
|
case CommandMenuPages.PageLayoutFieldsSettings:
|
|
case CommandMenuPages.PageLayoutFieldsLayout: {
|
|
if (!isDefined(pageLayoutEditingWidgetId)) {
|
|
return null;
|
|
}
|
|
|
|
const widgetInEditMode = draftPageLayout.tabs
|
|
.flatMap((tab) => tab.widgets)
|
|
.find((widget) => widget.id === pageLayoutEditingWidgetId);
|
|
|
|
if (!isDefined(widgetInEditMode)) {
|
|
return null;
|
|
}
|
|
|
|
const title = isDefined(editedTitle)
|
|
? editedTitle
|
|
: isDefined(widgetInEditMode.title) && widgetInEditMode.title !== ''
|
|
? widgetInEditMode.title
|
|
: '';
|
|
|
|
return {
|
|
headerIcon: IconList,
|
|
headerIconColor: iconColor,
|
|
headerType: t`Fields Widget`,
|
|
title,
|
|
isReadonly: false,
|
|
tab: undefined,
|
|
widgetInEditMode,
|
|
};
|
|
}
|
|
|
|
case CommandMenuPages.PageLayoutWidgetTypeSelect: {
|
|
return {
|
|
headerIcon: IconPlus,
|
|
headerIconColor: iconColor,
|
|
headerType: '',
|
|
title: t`New widget`,
|
|
isReadonly: true,
|
|
tab: undefined,
|
|
widgetInEditMode: undefined,
|
|
};
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
};
|