From 3bfdc2c83f0ab79dc6c7e5edd4389fa0d74bc3c9 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Tue, 3 Mar 2026 16:42:03 +0100 Subject: [PATCH] chore(twenty-front): migrate command-menu, workflow, page-layout and UI modules from Emotion to Linaria (PR 4-6/10) (#18342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Continues the Emotion → Linaria migration (PR 4-6 from the [migration plan](docs/emotion-to-linaria-migration-plan.md)). Migrates **311 files** across four module groups: | Module | Files | |---|---| | command-menu | 53 | | workflow | 84 | | page-layout | 84 | | UI (partial - first ~80 files) | ~80 | | twenty-ui (TEXT_INPUT_STYLE) | 1 | | misc (hooks, keyboard-shortcut-menu, file-upload) | ~9 | ### Migration patterns applied - `import styled from '@emotion/styled'` → `import { styled } from '@linaria/react'` - `import { useTheme } from '@emotion/react'` → `import { useContext } from 'react'` + `import { ThemeContext } from 'twenty-ui/theme'` - `${({ theme }) => theme.X.Y.Z}` → `${themeCssVariables.X.Y.Z}` (static CSS variables) - `theme.spacing(N)` → `themeCssVariables.spacing[N]` - `styled(motion.div)` → `motion.create(StyledBase)` (11 components) - `styled(Component)` → wrapper div approach for non-HTML elements - Multi-declaration interpolations split into one CSS property per interpolation - Interpolation return types fixed (`&&` → ternary `? : ''`) - `TEXT_INPUT_STYLE` converted from function to static string constant (backward compatible) - Emotion `` replaced with `useEffect` style injection - Complex runtime-dependent styles use CSS custom properties via `style={}` prop ### After this PR - **Remaining files**: ~400 (object-record: ~160, settings: ~200, UI: ~44) - **No breaking changes**: CSS variables resolve identically to the previous Emotion theme values --- ...in-js-transform-npm-0.7.0-ba641dc99f.patch | 58 ++++ docs/emotion-to-linaria-migration-plan.md | 42 +++ package.json | 4 +- packages/twenty-front/.storybook/main.ts | 5 + .../src/hooks/useCopyToClipboard.tsx | 5 +- packages/twenty-front/src/index.css | 1 + .../components/CalendarDayCardContent.tsx | 10 +- .../components/CalendarEventDetails.tsx | 39 +-- .../CalendarEventNotSharedContent.tsx | 16 +- ...arEventParticipantsResponseStatusField.tsx | 7 +- .../calendar/components/CalendarEventRow.tsx | 19 +- .../activities/components/ActivityRow.tsx | 5 +- .../emails/components/EmailThreadPreview.tsx | 40 +-- .../resizable-image/ResizableImageView.tsx | 24 +- .../src/modules/auth/components/Logo.tsx | 11 +- .../components/internal/LastUsedPill.tsx | 31 +- .../command-menu/components/CommandGroup.tsx | 13 +- .../components/CommandMenuAskAIInfo.tsx | 9 +- .../components/CommandMenuBackButton.tsx | 5 +- .../components/CommandMenuContainer.tsx | 7 +- .../components/CommandMenuContextChip.tsx | 34 +-- .../CommandMenuContextRecordChipAvatars.tsx | 22 +- .../components/CommandMenuFolderInfo.tsx | 2 +- .../components/CommandMenuForMobile.tsx | 2 +- .../components/CommandMenuItemNumberInput.tsx | 2 +- .../components/CommandMenuItemTextInput.tsx | 2 +- ...CommandMenuItemWithAddToNavigationDrag.tsx | 2 +- .../components/CommandMenuList.tsx | 15 +- .../CommandMenuMultipleRecordsInfo.tsx | 5 +- .../components/CommandMenuOpenContainer.tsx | 20 +- .../components/CommandMenuPageInfo.tsx | 14 +- .../components/CommandMenuPageInfoLayout.tsx | 25 +- .../CommandMenuPageLayoutInfoContent.tsx | 6 +- .../components/CommandMenuRouter.tsx | 7 +- .../CommandMenuSidePanelForDesktop.tsx | 15 +- .../CommandMenuSubViewWithSearch.tsx | 13 +- .../components/CommandMenuTopBar.tsx | 30 +- .../CommandMenuTopBarRightCornerIcon.tsx | 5 +- .../CommandMenuWorkflowStepInfo.tsx | 6 +- .../hooks/usePageLayoutHeaderInfo.ts | 5 +- .../hooks/useCommandMenuContextChips.tsx | 13 +- .../hooks/useOpenRecordInCommandMenu.ts | 6 +- .../CommandMenuAIChatThreadsPage.tsx | 2 +- .../components/CommandMenuAskAIPage.tsx | 2 +- .../SidePanelSubPageNavigationHeader.tsx | 15 +- ...dMenuMessageThreadIntermediaryMessages.tsx | 5 +- .../CommandMenuMessageThreadPage.tsx | 9 +- .../components/CommandMenuEditColorOption.tsx | 5 +- .../CommandMenuNavigationMenuItemEditPage.tsx | 9 +- .../CommandMenuNewSidebarItemMainMenu.tsx | 5 +- .../components/ChartFiltersSettings.tsx | 7 +- .../page-layout/components/ChartSettings.tsx | 2 +- .../components/ChartTypeSelectionSection.tsx | 5 +- .../CommandMenuPageLayoutChartSettings.tsx | 2 +- .../CommandMenuPageLayoutFieldsLayout.tsx | 7 +- .../CommandMenuPageLayoutFieldsSettings.tsx | 2 +- .../CommandMenuPageLayoutIframeSettings.tsx | 7 +- .../ChartColorGradientOption.tsx | 11 +- .../ChartColorPaletteOption.tsx | 11 +- .../components/CommandMenuMergeRecordPage.tsx | 2 +- .../components/CommandMenuRecordPage.tsx | 2 +- .../CommandMenuUpdateMultipleRecords.tsx | 2 +- .../CommandMenuEditRichTextPage.tsx | 11 +- .../CommandMenuWorkflowSelectAction.tsx | 5 +- .../components/WorkflowActionMenuItems.tsx | 5 +- .../CommandMenuWorkflowEditStepContent.tsx | 2 +- .../CommandMenuWorkflowRunViewStepContent.tsx | 7 +- .../CommandMenuWorkflowViewStepContent.tsx | 2 +- ...ndMenuWorkflowSelectTriggerTypeContent.tsx | 5 +- .../components/FileUploadProvider.tsx | 2 +- .../components/KeyboardShortcutMenuDialog.tsx | 5 +- .../components/KeyboardShortcutMenuStyles.tsx | 74 ++--- .../components/AddToNavigationDragHandle.tsx | 12 +- .../NavigationMenuItemIconContainer.tsx | 8 +- .../components/ObjectIconWithViewOverlay.tsx | 4 +- .../components/FormNumberFieldInput.tsx | 36 ++- .../components/FormRawJsonFieldInput.tsx | 4 +- .../components/FormUuidFieldInput.tsx | 27 +- .../components/PageLayoutCanvasViewer.tsx | 2 +- .../components/PageLayoutGridLayout.tsx | 47 ++-- .../components/PageLayoutGridOverlay.tsx | 29 +- .../components/PageLayoutGridResizeHandle.tsx | 153 +++++----- .../components/PageLayoutLeftPanel.tsx | 7 +- .../components/PageLayoutRendererContent.tsx | 5 +- .../components/PageLayoutTabList.tsx | 9 +- .../PageLayoutTabListDroppableMoreButton.tsx | 27 +- ...youtTabListReorderableOverflowDropdown.tsx | 6 +- .../PageLayoutTabListReorderableTab.tsx | 30 +- .../PageLayoutTabListVisibleTabs.tsx | 2 +- .../PageLayoutTabMenuItemSelectAvatar.tsx | 13 +- .../components/PageLayoutTabRenderClone.tsx | 7 +- .../PageLayoutVerticalListEditor.tsx | 25 +- .../PageLayoutVerticalListViewer.tsx | 17 +- .../__stories__/PageLayoutTabList.stories.tsx | 7 +- .../calendar/components/CalendarWidget.tsx | 2 +- .../PageLayoutWidgetInvalidConfigDisplay.tsx | 2 +- .../PageLayoutWidgetNoDataDisplay.tsx | 2 +- .../components/WidgetActionFieldSeeAll.tsx | 22 +- .../widgets/components/WidgetRenderer.tsx | 8 +- .../components/WidgetSkeletonLoader.tsx | 7 +- .../widgets/emails/components/EmailWidget.tsx | 2 +- .../components/FieldRichTextWidget.tsx | 2 +- .../widgets/field/components/FieldWidget.tsx | 2 +- .../field/components/FieldWidgetDisplay.tsx | 2 +- .../components/FieldWidgetEditAction.tsx | 27 +- .../FieldWidgetInlineCellContainer.tsx | 5 +- .../FieldWidgetMorphRelationCard.tsx | 5 +- .../FieldWidgetMorphRelationField.tsx | 7 +- .../components/FieldWidgetRelationCard.tsx | 5 +- .../FieldWidgetRelationEditAction.tsx | 28 +- .../components/FieldWidgetRelationField.tsx | 7 +- .../components/FieldWidgetShowMoreButton.tsx | 15 +- .../components/FieldsConfigurationEditor.tsx | 2 +- .../FieldsConfigurationGroupEditor.tsx | 15 +- .../FieldsConfigurationGroupRenameInput.tsx | 7 +- .../fields/components/FieldsWidget.tsx | 11 +- .../components/FieldsWidgetGroupContainer.tsx | 36 +-- .../widgets/files/components/FileWidget.tsx | 2 +- .../FrontComponentWidgetRenderer.tsx | 2 +- .../graph/chart-core/layers/AxisLabel.tsx | 5 +- .../graph/chart-core/layers/AxisLayer.tsx | 7 +- .../chart-core/layers/BottomAxisTicks.tsx | 5 +- .../graph/chart-core/layers/LeftAxisTicks.tsx | 5 +- .../graph/chart-core/layers/ZeroLine.tsx | 5 +- .../graph/components/GraphDataLabel.tsx | 5 +- .../components/GraphWidgetChartContainer.tsx | 10 +- .../components/GraphWidgetFloatingTooltip.tsx | 5 +- .../graph/components/GraphWidgetLegend.tsx | 48 ++-- .../graph/components/GraphWidgetLegendDot.tsx | 2 +- .../graph/components/GraphWidgetTooltip.tsx | 84 +++--- .../widgets/graph/components/NoDataLayer.tsx | 5 +- .../components/GraphWidgetAggregateChart.tsx | 18 +- .../components/BarChart.tsx | 8 +- .../components/BarChartBaseLayer.tsx | 2 +- .../components/BarChartBaseLayerEffect.tsx | 12 +- .../components/BarChartHoverLayer.tsx | 2 +- .../components/BarChartHoverLayerEffect.tsx | 6 +- .../components/BarChartLayers.tsx | 2 +- .../components/BarChartTotalsLayer.tsx | 2 +- .../components/GraphWidgetBarChart.tsx | 8 +- .../hooks/useBarChartTheme.ts | 5 +- .../components/GraphWidgetGaugeChart.tsx | 14 +- .../components/CustomCrosshairLayer.tsx | 6 +- .../components/GraphWidgetLineChart.tsx | 8 +- .../hooks/useLineChartTheme.ts | 5 +- .../components/GraphWidgetPieChart.tsx | 9 +- .../components/PieChartCenterMetricLayer.tsx | 23 +- .../iframe/components/IframeWidget.tsx | 15 +- .../widgets/notes/components/NoteWidget.tsx | 2 +- .../components/DashboardColorIcon.tsx | 12 +- .../DashboardColorSelectionMenu.tsx | 28 +- .../components/DashboardEditorSideMenu.tsx | 5 +- .../components/DashboardFormattingToolbar.tsx | 2 +- .../DashboardFormattingToolbarColorButton.tsx | 9 +- .../components/DashboardsBlockEditor.tsx | 43 +-- .../components/StandaloneRichTextWidget.tsx | 7 +- .../widgets/tasks/components/TaskWidget.tsx | 2 +- .../timeline/components/TimelineWidget.tsx | 2 +- .../widget-card/components/WidgetCard.tsx | 264 ++++++++++-------- .../components/WidgetCardContent.tsx | 93 +++--- .../components/WidgetCardHeader.tsx | 36 +-- .../widget-card/components/WidgetGrip.tsx | 17 +- .../SignInAppNavigationDrawerMock.tsx | 32 ++- .../dialog-manager/components/Dialog.tsx | 31 +- .../snack-bar-manager/components/SnackBar.tsx | 55 ++-- .../components/SnackBarProvider.tsx | 7 +- .../display/components/CurrencyDisplay.tsx | 6 +- .../display/components/DateTimeDisplay.tsx | 5 +- .../ui/field/display/components/FileChip.tsx | 2 +- .../components/GlobalFilePreviewModal.tsx | 24 +- .../display/components/UploadFileChip.tsx | 28 +- .../field/input/components/AddressInput.tsx | 2 +- .../field/input/components/BooleanInput.tsx | 9 +- .../field/input/components/CurrencyInput.tsx | 20 +- .../input/components/DoubleTextInput.tsx | 7 +- .../input/components/FieldInputContainer.tsx | 2 +- .../field/input/components/TextAreaInput.tsx | 5 +- .../ui/field/input/components/TextInput.tsx | 5 +- .../ui/input/components/IconPicker.tsx | 59 +++- .../ui/input/components/ImageInput.tsx | 43 +-- .../ui/input/components/InputErrorHelper.tsx | 7 +- .../modules/ui/input/components/InputHint.tsx | 15 +- .../ui/input/components/InputLabel.tsx | 18 +- .../input/components/MultiSelectControl.tsx | 27 +- .../modules/ui/input/components/Select.tsx | 15 +- .../ui/input/components/SelectControl.tsx | 70 ++--- .../modules/ui/input/components/TextArea.tsx | 37 ++- .../modules/ui/input/components/TextInput.tsx | 172 +++++++----- .../ui/input/components/TitleInput.tsx | 13 +- .../CurrencyPickerDropdownButton.tsx | 22 +- .../internal/date/components/DatePicker.tsx | 113 ++++---- .../date/components/DatePickerHeader.tsx | 11 +- .../date/components/DatePickerInput.tsx | 24 +- .../components/DatePickerWithoutCalendar.tsx | 87 +++--- .../date/components/DateTimePicker.tsx | 113 ++++---- .../date/components/DateTimePickerHeader.tsx | 13 +- .../date/components/DateTimePickerInput.tsx | 15 +- .../components/RelativeDatePickerHeader.tsx | 8 +- .../date/components/TimeZoneAbbreviation.tsx | 7 +- .../PhoneCountryPickerDropdownButton.tsx | 25 +- .../PhoneCountryPickerDropdownSelect.tsx | 9 +- .../components/CreateNewButton.tsx | 68 ++++- .../skeletons/DropdownMenuSkeletonItem.tsx | 18 +- .../components/DraggableItem.tsx | 5 +- .../components/DraggableList.tsx | 2 +- .../layout/dropdown/components/Dropdown.tsx | 2 +- .../dropdown/components/DropdownContent.tsx | 2 +- .../DropdownMenuHeader/DropdownMenuHeader.tsx | 33 +-- .../DropdownMenuHeaderLeftComponent.tsx | 21 +- .../components/DropdownMenuInnerSelect.tsx | 20 +- .../dropdown/components/DropdownMenuInput.tsx | 21 +- .../components/DropdownMenuItemsContainer.tsx | 9 +- .../components/DropdownMenuSearchInput.tsx | 7 +- .../components/DropdownMenuSectionLabel.tsx | 11 +- .../components/DropdownMenuSeparator.tsx | 8 +- .../components/OptionsDropdownMenu.tsx | 4 +- .../StyledDropdownButtonContainer.tsx | 29 +- .../StyledDropdownMenuSubheader.tsx | 7 +- .../components/StyledHeaderDropdownButton.tsx | 29 +- .../__stories__/Dropdown.stories.tsx | 2 +- .../internal/DropdownInternalContainer.tsx | 2 +- .../components/ExpandableList.tsx | 9 +- .../components/ExpandedFieldDisplay.tsx | 7 +- .../components/ExpandedListDropdown.tsx | 7 +- .../__stories__/ExpandableList.stories.tsx | 5 +- .../components/FullScreenContainer.tsx | 13 +- .../FullScreenContainer.stories.tsx | 2 +- .../fullscreen/hooks/useFullScreenModal.tsx | 15 +- .../modal/components/ConfirmationModal.tsx | 21 +- .../ui/layout/modal/components/Modal.tsx | 93 +++--- .../overlay/components/OverlayContainer.tsx | 17 +- .../PageHeaderToggleCommandMenuButton.tsx | 38 ++- .../ui/layout/page/components/BlankLayout.tsx | 22 +- .../layout/page/components/DefaultLayout.tsx | 39 ++- .../ui/layout/page/components/PageBody.tsx | 11 +- .../layout/page/components/PageContainer.tsx | 2 +- .../ui/layout/page/components/PageHeader.tsx | 41 +-- .../ui/layout/page/components/PagePanel.tsx | 9 +- .../page/components/ShowPageContainer.tsx | 27 +- .../components/SubMenuTopBarContainer.tsx | 16 +- .../components/ResizablePanelEdge.tsx | 37 +-- .../components/ResizablePanelGap.tsx | 2 +- .../components/RightDrawerFooter.tsx | 11 +- .../WorkflowStepExecutionResult.tsx | 26 +- .../components/WorkflowDiagramCanvasBase.tsx | 9 +- .../components/WorkflowDiagramConnector.tsx | 5 +- .../WorkflowDiagramCreateStepElement.tsx | 2 +- .../WorkflowDiagramRightClickCommandMenu.tsx | 13 +- .../components/WorkflowRunCard.tsx | 13 +- .../components/WorkflowVersionCard.tsx | 13 +- .../utils/getWorkflowDiagramColors.ts | 4 +- .../components/WorkflowDiagramBaseEdge.tsx | 5 +- .../components/WorkflowDiagramBlankEdge.tsx | 5 +- .../components/WorkflowDiagramConnection.tsx | 5 +- .../WorkflowDiagramCustomMarkers.tsx | 5 +- .../WorkflowDiagramDefaultEdgeReadonly.tsx | 5 +- .../WorkflowDiagramEdgeButtonGroup.tsx | 46 +-- .../components/WorkflowDiagramEdgeLabel.tsx | 19 +- .../WorkflowDiagramEdgeLabelContainer.tsx | 30 +- .../WorkflowDiagramEdgeV2Container.tsx | 11 +- ...rkflowDiagramEdgeV2VisibilityContainer.tsx | 2 +- .../WorkflowDiagramEmptyTriggerEditable.tsx | 5 +- .../WorkflowDiagramEmptyTriggerReadonly.tsx | 5 +- .../WorkflowDiagramHandleSource.tsx | 167 +++++------ .../WorkflowDiagramHandleTarget.tsx | 5 +- ...WorkflowDiagramStepNodeEditableContent.tsx | 8 +- .../WorkflowDiagramStepNodeIcon.tsx | 5 +- .../WorkflowDiagramStepNodeReadonly.tsx | 4 + .../components/WorkflowNodeContainer.tsx | 61 ++-- .../components/WorkflowNodeIconContainer.tsx | 5 +- .../components/WorkflowNodeLabel.tsx | 41 ++- .../WorkflowNodeLabelWithCounterPart.tsx | 2 +- .../components/WorkflowNodeRightPart.tsx | 2 +- .../components/WorkflowNodeTitle.tsx | 37 +-- .../components/WorkflowRunDiagramStepNode.tsx | 41 +-- ...RightDrawerWorkflowSelectStepContainer.tsx | 7 +- .../RightDrawerWorkflowSelectStepTitle.tsx | 17 +- .../WorkflowRunStepJsonContainer.tsx | 2 +- .../components/WorkflowStepBody.tsx | 11 +- ...kflowStepFilterAddRootStepFilterButton.tsx | 5 +- .../components/WorkflowStepFilterColumn.tsx | 5 +- .../WorkflowStepFilterFieldSelect.tsx | 6 +- .../WorkflowStepFilterGroupChildren.tsx | 17 +- .../WorkflowStepFilterGroupColumn.tsx | 5 +- .../WorkflowStepFilterLogicalOperatorCell.tsx | 15 +- .../WorkflowAiAgentPermissionsFlagRow.tsx | 5 +- .../WorkflowAiAgentPermissionsObjectRow.tsx | 5 +- .../WorkflowAiAgentPermissionsStyles.ts | 34 +-- .../WorkflowAiAgentPermissionsTab.tsx | 15 +- .../components/WorkflowEditActionAiAgent.tsx | 7 +- .../WorkflowOutputSchemaBuilder.tsx | 68 ++--- .../components/WorkflowCodeEditor.tsx | 7 +- .../components/WorkflowEditActionCode.tsx | 7 +- .../WorkflowEditActionCodeFields.tsx | 5 +- .../components/WorkflowReadonlyActionCode.tsx | 2 +- .../WorkflowEditActionCreateRecord.tsx | 5 +- .../WorkflowEditActionDeleteRecord.tsx | 5 +- .../WorkflowEditActionEmailBase.tsx | 4 +- .../WorkflowEditActionUpdateRecord.tsx | 5 +- .../WorkflowEditActionUpsertRecord.tsx | 5 +- .../WorkflowEditActionFilterBody.tsx | 9 +- .../WorkflowEditActionFindRecords.tsx | 15 +- .../components/WorkflowFindRecordsSorts.tsx | 9 +- .../WorkflowEditActionFormBuilder.tsx | 68 ++--- .../WorkflowEditActionFormFieldSettings.tsx | 40 +-- .../WorkflowFormFieldSettingsNumber.tsx | 5 +- .../WorkflowFormFieldSettingsRecordPicker.tsx | 10 +- .../WorkflowFormFieldSettingsSelect.tsx | 7 +- .../WorkflowFormFieldSettingsText.tsx | 5 +- .../hooks/useActionIconColorOrThrow.ts | 5 +- .../components/BodyInput.tsx | 13 +- .../HttpRequestTestVariableInput.tsx | 5 +- .../components/KeyValuePairInput.tsx | 18 +- .../WorkflowEditActionHttpRequest.tsx | 17 +- .../WorkflowEditActionHttpRequest.stories.tsx | 6 +- .../WorkflowEditActionIfElseBody.tsx | 7 +- .../components/WorkflowIfElseBranchEditor.tsx | 7 +- .../WorkflowIteratorSubStepSwitcher.tsx | 11 +- .../WorkflowEditActionLogicFunction.tsx | 5 +- .../getActionIconColorOrThrow.test.ts | 21 +- .../utils/getActionIconColorOrThrow.ts | 4 +- .../components/CronExpressionHelper.tsx | 39 +-- .../WorkflowEditTriggerDatabaseEventForm.tsx | 15 +- .../components/WorkflowEditTriggerManual.tsx | 26 +- .../WorkflowEditTriggerWebhookForm.tsx | 8 +- .../__tests__/getTriggerIconColor.test.ts | 15 +- .../utils/getTriggerIconColor.ts | 4 +- .../components/WorkflowTextEditorTextChip.tsx | 5 +- .../WorkflowTextEditorVariableChip.tsx | 5 +- .../components/WorkflowVariablePicker.tsx | 65 +++-- .../components/WorkflowVariablesDropdown.tsx | 19 +- packages/twenty-front/vite.config.ts | 261 ++++++++++++++++- packages/twenty-ui/.storybook/main.ts | 8 + .../button/components/ColorPickerButton.tsx | 12 +- .../components/JsonNestedNode.tsx | 12 +- .../testing/decorators/CatalogDecorator.tsx | 18 +- .../src/theme/constants/TextInputStyle.ts | 16 +- packages/twenty-ui/vite.config.ts | 1 + yarn.lock | 67 ++--- 339 files changed, 3439 insertions(+), 2613 deletions(-) create mode 100644 .yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch diff --git a/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch b/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch new file mode 100644 index 00000000000..b7433aad3ea --- /dev/null +++ b/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch @@ -0,0 +1,58 @@ +diff --git a/esm/cache.js b/esm/cache.js +index 07cf6d7dd99effb9c3464b620ba67a7f445224f5..248bb527923499a6be8065ee7a3613b55819c58c 100644 +--- a/esm/cache.js ++++ b/esm/cache.js +@@ -69,17 +69,20 @@ export class TransformCacheCollection { + this.invalidate(cacheName, filename); + }); + } +- invalidateIfChanged(filename, content) { ++ invalidateIfChanged(filename, content, _visited) { ++ const visited = _visited || new Set(); ++ if (visited.has(filename)) { ++ return false; ++ } ++ visited.add(filename); + const fileEntrypoint = this.get('entrypoints', filename); + +- // We need to check all dependencies of the file +- // because they might have changed as well. + if (fileEntrypoint) { + for (const [, dependency] of fileEntrypoint.dependencies) { + const dependencyFilename = dependency.resolved; + if (dependencyFilename) { + const dependencyContent = fs.readFileSync(dependencyFilename, 'utf8'); +- this.invalidateIfChanged(dependencyFilename, dependencyContent); ++ this.invalidateIfChanged(dependencyFilename, dependencyContent, visited); + } + } + } +diff --git a/lib/cache.js b/lib/cache.js +index 0762ed7d3c39b31000f7aa7d8156da15403c8e64..6955410cd3c9ec53cf7a01c8346abc4c47fff791 100644 +--- a/lib/cache.js ++++ b/lib/cache.js +@@ -77,17 +77,20 @@ class TransformCacheCollection { + this.invalidate(cacheName, filename); + }); + } +- invalidateIfChanged(filename, content) { ++ invalidateIfChanged(filename, content, _visited) { ++ const visited = _visited || new Set(); ++ if (visited.has(filename)) { ++ return false; ++ } ++ visited.add(filename); + const fileEntrypoint = this.get('entrypoints', filename); + +- // We need to check all dependencies of the file +- // because they might have changed as well. + if (fileEntrypoint) { + for (const [, dependency] of fileEntrypoint.dependencies) { + const dependencyFilename = dependency.resolved; + if (dependencyFilename) { + const dependencyContent = _nodeFs.default.readFileSync(dependencyFilename, 'utf8'); +- this.invalidateIfChanged(dependencyFilename, dependencyContent); ++ this.invalidateIfChanged(dependencyFilename, dependencyContent, visited); + } + } + } diff --git a/docs/emotion-to-linaria-migration-plan.md b/docs/emotion-to-linaria-migration-plan.md index d00a1844faa..fa210863a83 100644 --- a/docs/emotion-to-linaria-migration-plan.md +++ b/docs/emotion-to-linaria-migration-plan.md @@ -372,6 +372,48 @@ Once all PRs are merged: --- +## Known Issues & TODOs + +### `styled(Component)` from `twenty-ui` — style overrides silently dropped + +When `twenty-front` uses `styled(SomeComponent)` to extend a pre-built +component from `twenty-ui` (e.g. `Card`, `CardContent`, `PropertyBox`, +`Chip`, `Pill`, `Avatar`, `StyledHoverableMenuItemBase`, `MenuItemLeftContent`, +`TabList`, `NavigationDrawerSection`), the style overrides are silently +ignored at runtime. This happens because `wyw-in-js` in `twenty-front` +cannot resolve the base class name of a component that was already compiled +in another package. + +**Current workaround:** Replace `styled(Component)` with a plain +`styled.div` (or wrapper div) that duplicates the needed base styles. +This fixes the visual regression but loses the component's built-in +behavior (e.g. `CardContent`'s framer-motion animation, `PropertyBox`'s +layout-context padding logic, `Card`'s border/overflow). + +**Proper fix (TODO):** Add customization props directly to the base +components so consumers can override styles without wrapping: + +- `Card` / `CardContent` — add `padding`, `backgroundColor`, `borderColor` props +- `PropertyBox` — add `padding`, `height`, `noPadding` props +- Other frequently extended components — audit and add props as needed + +**Affected files (using workaround today):** + +- `CalendarEventDetails.tsx` — `styled(PropertyBox)` → `styled.div`, `styled(Chip)` → wrapper +- `CalendarEventParticipantsResponseStatusField.tsx` — `styled(PropertyBox)` → `styled.div` +- `CalendarEventNotSharedContent.tsx` — `styled(Card)` / `styled(CardContent)` → `styled.div` +- `CalendarDayCardContent.tsx` — `styled(CardContent)` → `styled(motion.div)` +- `ActivityRow.tsx` — `styled(CardContent)` → `styled.div` +- `EmailThreadPreview.tsx` — `styled(Avatar)` → wrapper div +- `SignInAppNavigationDrawerMock.tsx` — `styled(NavigationDrawerSection)` → wrapper div +- `DefaultLayout.tsx` — `styled(SignInAppNavigationDrawerMock)` → wrapper div +- `LastUsedPill.tsx` — `styled(Pill)` → wrapper span +- `Logo.tsx` — dynamic `background-image` via inline `style` instead of prop +- `DatePicker.tsx` / `DateTimePicker.tsx` — `styled(StyledHoverableMenuItemBase)` / `styled(MenuItemLeftContent)` → `styled.div` +- `SelectControl.tsx` / `MultiSelectControl.tsx` — `styled(IconChevronDown)` → wrapper div + +--- + ## Validation Checklist (per PR) - [ ] `npx nx lint:diff-with-main twenty-front` passes diff --git a/package.json b/package.json index 405b69a711a..d241873387c 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,9 @@ "typescript": "5.9.2", "graphql-redis-subscriptions/ioredis": "^5.6.0", "@lingui/core": "5.1.2", - "@types/qs": "6.9.16" + "@types/qs": "6.9.16", + "@wyw-in-js/transform@npm:0.6.0": "patch:@wyw-in-js/transform@npm%3A0.7.0#~/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch", + "@wyw-in-js/transform@npm:0.7.0": "patch:@wyw-in-js/transform@npm%3A0.7.0#~/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch" }, "version": "0.2.1", "nx": {}, diff --git a/packages/twenty-front/.storybook/main.ts b/packages/twenty-front/.storybook/main.ts index 797f5ef84f6..1dbac287368 100644 --- a/packages/twenty-front/.storybook/main.ts +++ b/packages/twenty-front/.storybook/main.ts @@ -58,6 +58,11 @@ const config: StorybookConfig = { return mergeConfig(viteConfig, { logLevel: 'warn', + resolve: { + alias: { + '@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs', + }, + }, }); }, diff --git a/packages/twenty-front/src/hooks/useCopyToClipboard.tsx b/packages/twenty-front/src/hooks/useCopyToClipboard.tsx index 22ee1cbec93..ffb4754604b 100644 --- a/packages/twenty-front/src/hooks/useCopyToClipboard.tsx +++ b/packages/twenty-front/src/hooks/useCopyToClipboard.tsx @@ -1,10 +1,11 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { IconCopy, IconExclamationCircle } from 'twenty-ui/display'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const useCopyToClipboard = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); const { t } = useLingui(); diff --git a/packages/twenty-front/src/index.css b/packages/twenty-front/src/index.css index e7b2dce9b72..57dfbf28202 100644 --- a/packages/twenty-front/src/index.css +++ b/packages/twenty-front/src/index.css @@ -3,6 +3,7 @@ body { font-family: 'Inter', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background: var(--t-background-tertiary); } html { diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx index 9ec4d36ca00..32e0571e12f 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx @@ -4,7 +4,7 @@ import { differenceInSeconds, endOfDay, format } from 'date-fns'; import { CalendarEventRow } from '@/activities/calendar/components/CalendarEventRow'; import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; -import { CardContent } from 'twenty-ui/layout'; +import { motion } from 'framer-motion'; import { ThemeContext } from 'twenty-ui/theme'; import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type TimelineCalendarEvent } from '~/generated/graphql'; @@ -14,15 +14,19 @@ type CalendarDayCardContentProps = { divider?: boolean; }; -const StyledCardContent = styled(CardContent)` +const StyledCardContentBase = styled.div<{ divider?: boolean }>` align-items: flex-start; - border-color: ${themeCssVariables.border.color.light}; + background-color: ${themeCssVariables.background.secondary}; + border-bottom: ${({ divider }) => + divider ? `1px solid ${themeCssVariables.border.color.light}` : 'none'}; display: flex; flex-direction: row; gap: ${themeCssVariables.spacing[3]}; padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; `; +const StyledCardContent = motion.create(StyledCardContentBase); + const StyledDayContainer = styled.div` text-align: center; width: ${themeCssVariables.spacing[6]}; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx index 4725892f94e..6f3a14ef446 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx @@ -19,7 +19,6 @@ import { } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; -import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; import { useIsRecordReadOnly } from '@/object-record/read-only/hooks/useIsRecordReadOnly'; import { isRecordFieldReadOnly } from '@/object-record/read-only/utils/isRecordFieldReadOnly'; import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId'; @@ -53,10 +52,14 @@ const StyledContainer = styled.div` box-sizing: border-box; `; -const StyledEventChip = styled(Chip)` - gap: ${themeCssVariables.spacing[2]}; - padding-left: ${themeCssVariables.spacing[2]}; - padding-right: ${themeCssVariables.spacing[2]}; +const StyledEventChipWrapper = styled.span` + display: inline-flex; + + & > [data-testid='chip'] { + gap: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; + } `; const StyledHeader = styled.header``; @@ -67,7 +70,7 @@ const StyledTitle = styled.h2<{ canceled?: boolean }>` margin: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[2]}; - ${({ canceled }) => (canceled ? 'text-decoration: line-through' : '')} + text-decoration: ${({ canceled }) => (canceled ? 'line-through' : 'none')}; `; const StyledCreatedAt = styled.div` @@ -81,9 +84,11 @@ const StyledFields = styled.div` width: 100%; `; -const StyledPropertyBox = styled(PropertyBox)` +const StyledPropertyBox = styled.div` + align-self: stretch; + display: flex; + flex-direction: column; height: ${themeCssVariables.spacing[6]}; - padding: 0; width: 100%; `; @@ -199,14 +204,16 @@ export const CalendarEventDetails = ({ value={{ scopeInstanceId: INPUT_ID_PREFIX }} > - } - label={t`Event`} - /> + + } + label={t`Event`} + /> + {calendarEvent.title} diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx index 1d8b2c7e68d..30aa259e52b 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx @@ -2,27 +2,29 @@ import { useContext } from 'react'; import { styled } from '@linaria/react'; import { Trans } from '@lingui/react/macro'; import { IconLock } from 'twenty-ui/display'; -import { Card, CardContent } from 'twenty-ui/layout'; import { ThemeContext } from 'twenty-ui/theme'; import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledVisibilityCard = styled(Card)` - border-color: ${themeCssVariables.border.color.light}; +const StyledVisibilityCard = styled.div` + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; color: ${themeCssVariables.font.color.light}; flex: 1; + overflow: hidden; transition: color ${themeCssVariables.animation.duration.normal} ease; width: 100%; `; -const StyledVisibilityCardContent = styled(CardContent)` +const StyledVisibilityCardContent = styled.div` align-items: center; + background-color: ${themeCssVariables.background.transparent.lighter}; + box-sizing: border-box; + display: flex; font-size: ${themeCssVariables.font.size.sm}; font-weight: ${themeCssVariables.font.weight.medium}; - display: flex; gap: ${themeCssVariables.spacing[1]}; - padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; height: ${themeCssVariables.spacing[6]}; - background-color: ${themeCssVariables.background.transparent.lighter}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; `; export const CalendarEventNotSharedContent = () => { diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx index 70f81a2ac45..ace4aaa0d45 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx @@ -3,7 +3,6 @@ import { styled } from '@linaria/react'; import { type CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant'; import { ParticipantChip } from '@/activities/components/ParticipantChip'; -import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; import { IconCheck, IconQuestionMark, IconX } from 'twenty-ui/display'; @@ -22,9 +21,11 @@ const StyledInlineCellBaseContainer = styled.div` user-select: none; `; -const StyledPropertyBox = styled(PropertyBox)` +const StyledPropertyBox = styled.div` + align-self: stretch; + display: flex; + flex-direction: column; height: ${themeCssVariables.spacing[6]}; - padding: 0; width: 100%; `; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx index 423e7eee576..5240a159adc 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -34,13 +34,13 @@ const StyledContainer = styled.div<{ showTitle?: boolean }>` `; const StyledAttendanceIndicator = styled.div<{ active?: boolean }>` - background-color: ${themeCssVariables.tag.background.gray}; + background-color: ${({ active }) => + active + ? themeCssVariables.tag.background.red + : themeCssVariables.tag.background.gray}; height: 100%; width: ${themeCssVariables.spacing[1]}; border-radius: ${themeCssVariables.border.radius.xs}; - - ${({ active }) => - active ? `background-color: ${themeCssVariables.tag.background.red}` : ''} `; const StyledLabels = styled.div` @@ -60,17 +60,16 @@ const StyledTime = styled.div` `; const StyledTitle = styled.div<{ active: boolean; canceled: boolean }>` + color: ${({ active }) => + active ? themeCssVariables.font.color.primary : 'inherit'}; flex: 1 0 auto; + font-weight: ${({ active }) => + active ? themeCssVariables.font.weight.medium : 'inherit'}; overflow: hidden; + text-decoration: ${({ canceled }) => (canceled ? 'line-through' : 'none')}; text-overflow: ellipsis; white-space: nowrap; width: ${themeCssVariables.spacing[10]}; - ${({ active }) => - active - ? `color: ${themeCssVariables.font.color.primary}; font-weight: ${themeCssVariables.font.weight.medium}` - : ''} - - ${({ canceled }) => (canceled ? 'text-decoration: line-through' : '')} `; export const CalendarEventRow = ({ diff --git a/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx b/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx index 7974043bed2..d696ad33c57 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx @@ -1,10 +1,11 @@ import { styled } from '@linaria/react'; import React from 'react'; -import { CardContent } from 'twenty-ui/layout'; import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledRowContent = styled(CardContent)` +const StyledRowContent = styled.div<{ isClickable: boolean }>` align-items: center; + background-color: ${themeCssVariables.background.secondary}; + cursor: ${({ isClickable }) => (isClickable ? 'pointer' : 'default')}; display: flex; gap: ${themeCssVariables.spacing[2]}; height: ${themeCssVariables.spacing[12]}; diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx index 895073a0c3f..0d618f892ab 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx @@ -25,7 +25,7 @@ const StyledParticipantsContainer = styled.div` display: flex; `; -const StyledAvatar = styled(Avatar)` +const StyledAvatarWrapper = styled.div` margin-left: calc(-1 * ${themeCssVariables.spacing[1]}); `; @@ -123,24 +123,30 @@ export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => { type="rounded" /> {thread?.lastTwoParticipants?.[0] && ( - + + + )} {finalDisplayedName && ( - + + + )} diff --git a/packages/twenty-front/src/modules/advanced-text-editor/extensions/resizable-image/ResizableImageView.tsx b/packages/twenty-front/src/modules/advanced-text-editor/extensions/resizable-image/ResizableImageView.tsx index 12cec7ff09c..067ac29b229 100644 --- a/packages/twenty-front/src/modules/advanced-text-editor/extensions/resizable-image/ResizableImageView.tsx +++ b/packages/twenty-front/src/modules/advanced-text-editor/extensions/resizable-image/ResizableImageView.tsx @@ -11,18 +11,10 @@ const StyledNodeViewWrapperContainer = styled.div<{ align?: string; }>` height: 100%; - ${({ align }) => { - switch (align) { - case 'left': - return 'margin-left: 0;'; - case 'right': - return 'margin-right: 0;'; - case 'center': - return 'margin-left: auto; margin-right: auto;'; - default: - return ''; - } - }} + margin-left: ${({ align }) => + align === 'left' ? '0' : align === 'center' ? 'auto' : 'unset'}; + margin-right: ${({ align }) => + align === 'right' ? '0' : align === 'center' ? 'auto' : 'unset'}; `; const StyledImageWrapper = styled.div<{ width?: number }>` @@ -51,10 +43,10 @@ const StyledImageHandle = styled.div<{ handle: 'left' | 'right' }>` width: ${themeCssVariables.spacing[2]}; z-index: 1; - ${({ handle }) => - handle === 'left' - ? `left: ${themeCssVariables.spacing[1]};` - : `right: ${themeCssVariables.spacing[1]};`} + left: ${({ handle }) => + handle === 'left' ? themeCssVariables.spacing[1] : 'auto'}; + right: ${({ handle }) => + handle === 'right' ? themeCssVariables.spacing[1] : 'auto'}; `; type ResizeParams = { diff --git a/packages/twenty-front/src/modules/auth/components/Logo.tsx b/packages/twenty-front/src/modules/auth/components/Logo.tsx index 0135ed0c3bc..0a4dc0990c4 100644 --- a/packages/twenty-front/src/modules/auth/components/Logo.tsx +++ b/packages/twenty-front/src/modules/auth/components/Logo.tsx @@ -44,8 +44,7 @@ const StyledSecondaryLogoContainer = styled.div` width: ${themeCssVariables.spacing[7]}; `; -const StyledPrimaryLogo = styled.div<{ src: string }>` - background: url(${(props) => props.src}); +const StyledPrimaryLogo = styled.div` background-size: cover; height: 100%; width: 100%; @@ -81,10 +80,14 @@ export const Logo = ({ to={AppPath.SignInUp} onClick={redirectToDefaultDomain} > - + ) : ( - + )} {isDefined(secondaryLogoUrl) ? ( diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/LastUsedPill.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/LastUsedPill.tsx index 6287f3c4d22..c5b8de888db 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/LastUsedPill.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/LastUsedPill.tsx @@ -3,27 +3,32 @@ import { useLingui } from '@lingui/react/macro'; import { Pill } from 'twenty-ui/components'; import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledPill = styled(Pill)` - background: ${themeCssVariables.color.blue3}; - border: 1px solid ${themeCssVariables.color.blue5}; - border-radius: ${themeCssVariables.border.radius.pill}; - color: ${themeCssVariables.color.blue}; - font-weight: ${themeCssVariables.font.weight.semiBold}; +const StyledPillContainer = styled.span` position: absolute; right: calc(-1 * ${themeCssVariables.spacing[5]}); top: calc(-1 * ${themeCssVariables.spacing[2]}); + + > span { + background: ${themeCssVariables.color.blue3}; + border: 1px solid ${themeCssVariables.color.blue5}; + border-radius: ${themeCssVariables.border.radius.pill}; + color: ${themeCssVariables.color.blue}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + } `; export const LastUsedPill = () => { const { t } = useLingui(); return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandGroup.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandGroup.tsx index ad05dc98593..f104a9b8eb9 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandGroup.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandGroup.tsx @@ -1,20 +1,21 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import React from 'react'; import { Label } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledGroupHeading = styled(Label)` align-items: center; - padding-bottom: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(1)}; - padding-right: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[1]}; + padding-right: ${themeCssVariables.spacing[1]}; + padding-top: ${themeCssVariables.spacing[2]}; user-select: none; `; const StyledGroup = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; type CommandGroupProps = { diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx index ffe86edaf44..77d5e8b5731 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuAskAIInfo.tsx @@ -1,13 +1,14 @@ import { currentAIChatThreadTitleState } from '@/ai/states/currentAIChatThreadTitleState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledPageTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; export const CommandMenuAskAIInfo = () => { diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuBackButton.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuBackButton.tsx index c5cc3265030..167574498ea 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuBackButton.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuBackButton.tsx @@ -6,10 +6,11 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconChevronLeft } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; import { MenuItem } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledNavigationIcon = styled.div` align-items: center; @@ -19,7 +20,7 @@ const StyledNavigationIcon = styled.div` `; const StyledIconChevronLeft = styled(IconChevronLeft)` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; export const CommandMenuBackButton = () => { diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx index c4d7f5333fa..6e54677cdcb 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; @@ -10,10 +10,11 @@ import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/u import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCommandMenuContainer = styled.div<{ isMobile: boolean }>` - max-height: ${({ theme, isMobile }) => { - const mobileOffset = isMobile ? theme.spacing(16) : '0px'; + max-height: ${({ isMobile }) => { + const mobileOffset = isMobile ? themeCssVariables.spacing[16] : '0px'; return `calc(100% - ${mobileOffset})`; }}; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx index bd101ddbaeb..e5aa80897bb 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { Fragment } from 'react/jsx-runtime'; import { type CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledChip = styled.button<{ withText: boolean; @@ -14,30 +15,31 @@ const StyledChip = styled.button<{ all: unset; align-items: center; justify-content: center; - background: ${({ theme }) => theme.background.transparent.light}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.transparent.light}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; box-sizing: border-box; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - height: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[1]}; + height: ${themeCssVariables.spacing[6]}; /* If the chip has text, we add extra padding to have a more balanced design */ padding: 0 - ${({ theme, withText }) => (withText ? theme.spacing(2) : theme.spacing(1))}; + ${({ withText }) => + withText ? themeCssVariables.spacing[2] : themeCssVariables.spacing[1]}; font-family: inherit; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - line-height: ${({ theme }) => theme.text.lineHeight.lg}; - color: ${({ theme }) => theme.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + line-height: ${themeCssVariables.text.lineHeight.lg}; + color: ${themeCssVariables.font.color.primary}; cursor: ${({ onClick }) => (isDefined(onClick) ? 'pointer' : 'default')}; &:hover { - background: ${({ onClick, theme }) => + background: ${({ onClick }) => isDefined(onClick) - ? theme.background.transparent.medium - : theme.background.transparent.light}; + ? themeCssVariables.background.transparent.medium + : themeCssVariables.background.transparent.light}; } - max-width: ${({ maxWidth }) => maxWidth}; + max-width: ${({ maxWidth }) => maxWidth ?? ''}; `; const StyledIconsContainer = styled.div` @@ -46,7 +48,7 @@ const StyledIconsContainer = styled.div` `; const StyledEmptyText = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export type CommandMenuContextChipProps = { diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextRecordChipAvatars.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextRecordChipAvatars.tsx index 66f25716415..f3c0fb2a309 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextRecordChipAvatars.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextRecordChipAvatars.tsx @@ -2,19 +2,23 @@ import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandard import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useRecordChipData } from '@/object-record/hooks/useRecordChipData'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Avatar } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledIconWrapper = styled.div<{ withIconBackground?: boolean }>` - background: ${({ theme, withIconBackground }) => - withIconBackground ? theme.background.primary : 'unset'}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${({ withIconBackground }) => + withIconBackground ? themeCssVariables.background.primary : 'unset'}; + border-radius: ${themeCssVariables.border.radius.sm}; border: 1px solid - ${({ theme, withIconBackground }) => - withIconBackground ? theme.border.color.medium : 'transparent'}; + ${({ withIconBackground }) => + withIconBackground + ? themeCssVariables.border.color.medium + : 'transparent'}; &:not(:first-of-type) { - margin-left: -${({ theme }) => theme.spacing(1)}; + margin-left: -${themeCssVariables.spacing[1]}; } display: flex; align-items: center; @@ -36,7 +40,7 @@ export const CommandMenuContextRecordChipAvatars = ({ objectMetadataItem.nameSingular, ); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(2)}; - width: calc(100% - ${({ theme }) => theme.spacing(4)}); + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[2]}; + width: calc(100% - ${themeCssVariables.spacing[4]}); @media (min-width: ${MOBILE_VIEWPORT}px) { max-height: calc( @@ -47,9 +48,9 @@ const StyledCommandMenuList = styled.div` const StyledEmpty = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; height: 64px; justify-content: center; white-space: pre-wrap; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuMultipleRecordsInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuMultipleRecordsInfo.tsx index 7cebd674391..fb2f2a2623a 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuMultipleRecordsInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuMultipleRecordsInfo.tsx @@ -3,8 +3,9 @@ import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/ import { getActionLabel } from '@/action-menu/utils/getActionLabel'; import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout'; import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type CommandMenuMultipleRecordsInfoProps = { commandMenuPageInstanceId: string; @@ -13,7 +14,7 @@ type CommandMenuMultipleRecordsInfoProps = { export const CommandMenuMultipleRecordsInfo = ({ commandMenuPageInstanceId, }: CommandMenuMultipleRecordsInfoProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { totalCount } = useFindManyRecordsSelectedInContextStore({ instanceId: commandMenuPageInstanceId, diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx index 50421f05c46..3d86aba025e 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx @@ -17,19 +17,20 @@ import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomStat import { WORKFLOW_DIAGRAM_CREATE_STEP_NODE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramCreateStepNodeClickOutsideId'; import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId'; import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowDiagramEdgeOptionsClickOutsideId'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; -import { useCallback, useRef } from 'react'; +import { useCallback, useContext, useRef } from 'react'; import { LINK_CHIP_CLICK_OUTSIDE_ID } from 'twenty-ui/components'; import { useIsMobile } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; -const StyledCommandMenu = styled(motion.div)` - background: ${({ theme }) => theme.background.primary}; - border-left: 1px solid ${({ theme }) => theme.border.color.medium}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; - font-family: ${({ theme }) => theme.font.family}; +const StyledCommandMenuBase = styled.div` + background: ${themeCssVariables.background.primary}; + border-left: 1px solid ${themeCssVariables.border.color.medium}; + box-shadow: ${themeCssVariables.boxShadow.strong}; + font-family: ${themeCssVariables.font.family}; height: 100%; overflow: hidden; padding: 0; @@ -40,6 +41,7 @@ const StyledCommandMenu = styled(motion.div)` display: flex; flex-direction: column; `; +const StyledCommandMenu = motion.create(StyledCommandMenuBase); export const CommandMenuOpenContainer = ({ children, @@ -50,7 +52,7 @@ export const CommandMenuOpenContainer = ({ ? 'fullScreen' : 'normal'; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { closeCommandMenu } = useCommandMenu(); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfo.tsx index af7dd95864e..abb7ec3e297 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfo.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { IconColumnInsertRight, @@ -20,13 +20,15 @@ import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-ite import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { CommandMenuPages } from 'twenty-shared/types'; -import { useTheme } from '@emotion/react'; import { type CommandMenuContextChipProps } from './CommandMenuContextChip'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledPageTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; type CommandMenuPageInfoProps = { @@ -34,7 +36,7 @@ type CommandMenuPageInfoProps = { }; export const CommandMenuPageInfo = ({ pageChip }: CommandMenuPageInfoProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const selectedNavigationMenuItemInEditMode = useAtomStateValue( selectedNavigationMenuItemInEditModeState, ); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfoLayout.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfoLayout.tsx index 749cb9a2d2a..436ec2517a9 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfoLayout.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageInfoLayout.tsx @@ -1,42 +1,43 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export const StyledPageInfoContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; export const StyledPageInfoIcon = styled.div<{ iconColor?: string }>` align-items: center; - background: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ iconColor }) => iconColor}; + background: ${themeCssVariables.background.transparent.light}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${({ iconColor }) => iconColor ?? ''}; display: flex; flex-shrink: 0; justify-content: center; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; `; export const StyledPageInfoTextContainer = styled.div` align-items: center; display: flex; flex: 1; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; min-width: 0; `; export const StyledPageInfoTitleContainer = styled.div` - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - padding-inline: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + padding-inline: ${themeCssVariables.spacing[1]}; min-width: 0; max-width: 150px; `; export const StyledPageInfoLabel = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; white-space: nowrap; flex-shrink: 0; `; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx index 15c2a07d4ba..b448de7e1c0 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuPageLayoutInfoContent.tsx @@ -11,21 +11,21 @@ import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/stat import { TitleInput } from '@/ui/input/components/TitleInput'; import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useTheme } from '@emotion/react'; import { isNonEmptyString } from '@sniptt/guards'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; import { CommandMenuPageInfoLayout } from './CommandMenuPageInfoLayout'; +import { ThemeContext } from 'twenty-ui/theme'; export const CommandMenuPageLayoutInfoContent = ({ pageLayoutId, }: { pageLayoutId: string; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const commandMenuPage = useAtomStateValue(commandMenuPageState); const commandMenuPageInfo = useAtomStateValue(commandMenuPageInfoState); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx index 855cb0c00af..0faf55086ca 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuRouter.tsx @@ -6,10 +6,11 @@ import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageI import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; import { isDefined } from 'twenty-shared/utils'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledCommandMenuContent = styled.div` flex: 1; @@ -26,7 +27,7 @@ export const CommandMenuRouter = () => { <> ); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx index 405f93a59b2..3116a2e63a0 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSidePanelForDesktop.tsx @@ -15,8 +15,9 @@ import { COMMAND_MENU_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/ import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useCallback, useState } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSidePanelWrapper = styled.div<{ isOpen: boolean; @@ -26,14 +27,16 @@ const StyledSidePanelWrapper = styled.div<{ min-width: 0; overflow: hidden; width: ${({ isOpen }) => (isOpen ? `var(${COMMAND_MENU_WIDTH_VAR})` : '0px')}; - transition: ${({ isResizing, theme }) => - isResizing ? 'none' : `width ${theme.animation.duration.normal}s`}; + transition: ${({ isResizing }) => + isResizing + ? 'none' + : `width ${themeCssVariables.animation.duration.normal}s`}; `; const StyledSidePanel = styled.aside` - background: ${({ theme }) => theme.background.primary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.primary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; height: 100%; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSubViewWithSearch.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSubViewWithSearch.tsx index da0266409a4..6b1a65c1232 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuSubViewWithSearch.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuSubViewWithSearch.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; import { SidePanelSubPageNavigationHeader } from '@/command-menu/pages/common/components/SidePanelSubPageNavigationHeader'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSubViewContainer = styled.div` display: flex; @@ -13,17 +14,17 @@ const StyledSubViewContainer = styled.div` const StyledSearchContainer = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; - height: ${({ theme }) => theme.spacing(10)}; + height: ${themeCssVariables.spacing[10]}; min-width: 0; - padding-inline: ${({ theme }) => theme.spacing(3)}; + padding-inline: ${themeCssVariables.spacing[3]}; `; const StyledSearchInput = styled.input` background: transparent; border: none; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; padding: 0; @@ -31,7 +32,7 @@ const StyledSearchInput = styled.input` outline: none; &::placeholder { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } `; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx index 7320c2cfddc..48c181f0c42 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx @@ -4,7 +4,6 @@ import { CommandMenuTopBarInputFocusEffect } from '@/command-menu/components/Com import { CommandMenuTopBarRightCornerIcon } from '@/command-menu/components/CommandMenuTopBarRightCornerIcon'; import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight'; import { COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE } from '@/command-menu/constants/CommandMenuSearchBarHeightMobile'; -import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding'; import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useCommandMenuContextChips } from '@/command-menu/hooks/useCommandMenuContextChips'; @@ -14,29 +13,30 @@ import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchS import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { AnimatePresence, motion } from 'framer-motion'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useRef } from 'react'; +import { useContext, useRef } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconX } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; import { useIsMobile } from 'twenty-ui/utilities'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInputContainer = styled.div<{ isMobile: boolean }>` align-items: center; - background-color: ${({ theme }) => theme.background.secondary}; + background-color: ${themeCssVariables.background.secondary}; border: none; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; border-radius: 0; box-sizing: border-box; display: flex; justify-content: space-between; - font-size: ${({ theme }) => theme.font.size.lg}; + font-size: ${themeCssVariables.font.size.lg}; height: ${({ isMobile }) => isMobile ? COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE @@ -46,8 +46,8 @@ const StyledInputContainer = styled.div<{ isMobile: boolean }>` position: relative; overflow: hidden; - padding: 0 ${({ theme }) => theme.spacing(COMMAND_MENU_SEARCH_BAR_PADDING)}; - gap: ${({ theme }) => theme.spacing(4)}; + padding: 0 ${themeCssVariables.spacing[2]}; + gap: ${themeCssVariables.spacing[4]}; flex-shrink: 0; justify-content: space-between; `; @@ -56,8 +56,8 @@ const StyledInput = styled.input` border: none; border-radius: 0; background-color: transparent; - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; margin: 0; outline: none; height: 24px; @@ -65,8 +65,8 @@ const StyledInput = styled.input` flex: 1; &::placeholder { - color: ${({ theme }) => theme.font.color.light}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.light}; + font-weight: ${themeCssVariables.font.weight.medium}; } `; @@ -74,7 +74,7 @@ const StyledContentContainer = styled.div` align-items: center; display: flex; flex: 1; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; min-width: 0; overflow: hidden; `; @@ -101,7 +101,7 @@ export const CommandMenuTopBar = () => { commandMenuNavigationStackState, ); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { contextChips } = useCommandMenuContextChips(); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx index 9a2efda394f..50b7cc95a40 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBarRightCornerIcon.tsx @@ -2,7 +2,7 @@ import { useOpenAskAIPageInCommandMenu } from '@/command-menu/hooks/useOpenAskAI import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { CommandMenuPages } from 'twenty-shared/types'; import { IconEdit, IconSparkles } from 'twenty-ui/display'; @@ -11,9 +11,10 @@ import { useIsMobile } from 'twenty-ui/utilities'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { useCreateNewAIChatThread } from '@/ai/hooks/useCreateNewAIChatThread'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledIconButton = styled(IconButton)` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; export const CommandMenuTopBarRightCornerIcon = () => { diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx index 580c9e3e88d..3e5fe1b4653 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuWorkflowStepInfo.tsx @@ -17,22 +17,22 @@ import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/ import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow'; import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon'; import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; import { CommandMenuPageInfoLayout } from './CommandMenuPageInfoLayout'; +import { ThemeContext } from 'twenty-ui/theme'; export const CommandMenuWorkflowStepInfo = ({ commandMenuPageInstanceId, }: { commandMenuPageInstanceId: string; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const commandMenuPage = useAtomStateValue(commandMenuPageState); diff --git a/packages/twenty-front/src/modules/command-menu/components/hooks/usePageLayoutHeaderInfo.ts b/packages/twenty-front/src/modules/command-menu/components/hooks/usePageLayoutHeaderInfo.ts index 1a5c44269cc..f660af8d7ea 100644 --- a/packages/twenty-front/src/modules/command-menu/components/hooks/usePageLayoutHeaderInfo.ts +++ b/packages/twenty-front/src/modules/command-menu/components/hooks/usePageLayoutHeaderInfo.ts @@ -3,7 +3,6 @@ import { getCurrentGraphTypeFromConfig } from '@/command-menu/pages/page-layout/ 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 { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -14,6 +13,8 @@ import { IconPlus, type IconComponent, } from 'twenty-ui/display'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type PageLayoutHeaderInfo = { headerIcon: IconComponent | undefined; @@ -42,7 +43,7 @@ export const usePageLayoutHeaderInfo = ({ openTabId, editedTitle, }: UsePageLayoutHeaderInfoParams): PageLayoutHeaderInfo | null => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const iconColor = theme.font.color.tertiary; switch (commandMenuPage) { diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx index e3efb396d96..ff13ddbc7c8 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuContextChips.tsx @@ -6,17 +6,18 @@ import { CommandMenuPages } from 'twenty-shared/types'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { recordStoreIdentifiersFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifiersSelector'; import { recordStoreRecordsSelector } from '@/object-record/record-store/states/selectors/recordStoreRecordsSelector'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useMemo } from 'react'; +import { styled } from '@linaria/react'; +import { useContext, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons'; import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledIconWrapper = styled.div` - background: ${({ theme }) => theme.background.primary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.primary}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; align-items: center; justify-content: center; @@ -35,7 +36,7 @@ export const useCommandMenuContextChips = () => { const { navigateCommandMenuHistory } = useCommandMenuHistory(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const commandMenuNavigationMorphItemsByPage = useAtomStateValue( commandMenuNavigationMorphItemsByPageState, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts index 0975823594b..4eb01346d69 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts @@ -20,17 +20,17 @@ import { useOpenNewRecordTitleCell } from '@/object-record/record-title-cell/hoo import { CommandMenuPages } from 'twenty-shared/types'; import { useRunWorkflowRunOpeningInCommandMenuSideEffects } from '@/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useStore } from 'jotai'; -import { useCallback } from 'react'; +import { useCallback, useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; import { v4 } from 'uuid'; +import { ThemeContext } from 'twenty-ui/theme'; export const useOpenRecordInCommandMenu = () => { const store = useStore(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const { navigateCommandMenu } = useCommandMenu(); diff --git a/packages/twenty-front/src/modules/command-menu/pages/AIChatThreads/components/CommandMenuAIChatThreadsPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/AIChatThreads/components/CommandMenuAIChatThreadsPage.tsx index 7ebdcefa003..cee799f3ae4 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/AIChatThreads/components/CommandMenuAIChatThreadsPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/AIChatThreads/components/CommandMenuAIChatThreadsPage.tsx @@ -1,5 +1,5 @@ import { AIChatThreadsList } from '@/ai/components/AIChatThreadsList'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` height: 100%; diff --git a/packages/twenty-front/src/modules/command-menu/pages/ask-ai/components/CommandMenuAskAIPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/ask-ai/components/CommandMenuAskAIPage.tsx index 4d8e93f2925..e5cd9b68caf 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/ask-ai/components/CommandMenuAskAIPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/ask-ai/components/CommandMenuAskAIPage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AIChatTab } from '@/ai/components/AIChatTab'; const StyledContainer = styled.div` diff --git a/packages/twenty-front/src/modules/command-menu/pages/common/components/SidePanelSubPageNavigationHeader.tsx b/packages/twenty-front/src/modules/command-menu/pages/common/components/SidePanelSubPageNavigationHeader.tsx index 181f59fb6b2..fbefae75f5f 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/common/components/SidePanelSubPageNavigationHeader.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/common/components/SidePanelSubPageNavigationHeader.tsx @@ -1,20 +1,21 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconChevronLeft } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - padding: 0 ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + padding: 0 ${themeCssVariables.spacing[2]}; height: 40px; `; const StyledText = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; `; type SidePanelSubPageNavigationHeaderProps = { diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages.tsx b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages.tsx index ab5e338fc25..e22a1ba0d29 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages.tsx @@ -1,13 +1,14 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useState } from 'react'; import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMessage'; import { type EmailThreadMessageWithSender } from '@/activities/emails/types/EmailThreadMessageWithSender'; import { Button } from 'twenty-ui/input'; import { IconArrowsVertical } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledButtonContainer = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; padding: 16px 24px; `; diff --git a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx index 949adad8f13..df2784749bc 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useMemo } from 'react'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; @@ -14,6 +14,7 @@ import { ConnectedAccountProvider } from 'twenty-shared/types'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; import { IconArrowBackUp } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledWrapper = styled.div` display: flex; @@ -31,11 +32,11 @@ const StyledContainer = styled.div` `; const StyledButtonContainer = styled.div` - background: ${({ theme }) => theme.background.secondary}; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.background.secondary}; + border-top: 1px solid ${themeCssVariables.border.color.light}; display: flex; justify-content: flex-end; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; width: 100%; box-sizing: border-box; `; diff --git a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuEditColorOption.tsx b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuEditColorOption.tsx index 4ee7ae8ef37..17752bcdfa3 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuEditColorOption.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuEditColorOption.tsx @@ -5,7 +5,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { useState } from 'react'; @@ -16,11 +16,12 @@ import { MenuItemSelectColor, } from 'twenty-ui/navigation'; import { MAIN_COLOR_NAMES, type ThemeColor } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const NAVIGATION_MENU_ITEM_COLOR_DROPDOWN_ID = 'navigation-menu-item-color'; const StyledMenuStyleText = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; font-size: 13px; `; diff --git a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNavigationMenuItemEditPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNavigationMenuItemEditPage.tsx index 05f6ff3aa83..c3688912719 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNavigationMenuItemEditPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNavigationMenuItemEditPage.tsx @@ -21,21 +21,22 @@ import { parseThemeColor } from '@/navigation-menu-item/utils/parseThemeColor'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { ViewKey } from '@/views/types/ViewKey'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const ADD_ITEM_TO_FOLDER_ACTION_ID = 'add-item-to-folder'; const StyledCommandMenuPlaceholder = styled.p` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; `; const StyledCommandMenuPageContainer = styled.div` - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; export const CommandMenuNavigationMenuItemEditPage = () => { diff --git a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNewSidebarItemMainMenu.tsx b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNewSidebarItemMainMenu.tsx index c95d9b2106e..b1bc13ccde8 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNewSidebarItemMainMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/navigation-menu-item/components/CommandMenuNewSidebarItemMainMenu.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { Avatar, @@ -19,6 +18,8 @@ import { useAddLinkToNavigationMenu } from '@/command-menu/pages/navigation-menu import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon'; import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type CommandMenuNewSidebarItemMainMenuProps = { onSelectObject: () => void; @@ -32,7 +33,7 @@ export const CommandMenuNewSidebarItemMainMenu = ({ onSelectRecord, }: CommandMenuNewSidebarItemMainMenuProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { handleAddFolder } = useAddFolderToNavigationMenu(); const { handleAddLink } = useAddLinkToNavigationMenu(); diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx index 8bb670ba1d8..d7bf8814b48 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartFiltersSettings.tsx @@ -16,16 +16,17 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { InputLabel } from '@/ui/input/components/InputLabel'; import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState'; import { useStore } from 'jotai'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledChartFiltersPageContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; export type ChartFiltersSettingsProps = { diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx index c6f9586a0de..4139bc8bbe1 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartSettings.tsx @@ -15,7 +15,7 @@ import { shouldHideChartSetting } from '@/command-menu/pages/page-layout/utils/s import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { hasWidgetTooManyGroupsComponentState } from '@/page-layout/widgets/graph/states/hasWidgetTooManyGroupsComponentState'; import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isFieldMetadataDateKind } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx index 7a0cef8dfe9..72f129bb0ac 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/ChartTypeSelectionSection.tsx @@ -1,11 +1,12 @@ import { GRAPH_TYPE_INFORMATION } from '@/command-menu/pages/page-layout/constants/GraphTypeInformation'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { GraphType } from '@/command-menu/pages/page-layout/types/GraphType'; import { t } from '@lingui/core/macro'; import { MenuPicker } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const graphTypeOptions = [ GraphType.VERTICAL_BAR, @@ -19,7 +20,7 @@ const graphTypeOptions = [ const StyledChartTypeSelectionContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; type ChartTypeSelectionSectionProps = { diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx index f839f41d2cc..3e9632f2a77 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx @@ -6,7 +6,7 @@ import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDr import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; const StyledContainer = styled.div` diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsLayout.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsLayout.tsx index 6c024cc551d..03690c9f0d0 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsLayout.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsLayout.tsx @@ -5,13 +5,14 @@ import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useW import { useTemporaryFieldsConfiguration } from '@/page-layout/hooks/useTemporaryFieldsConfiguration'; import { FieldsConfigurationEditor } from '@/page-layout/widgets/fields/components/FieldsConfigurationEditor'; import { FieldsWidgetGroupsDraftInitializationEffect } from '@/page-layout/widgets/fields/components/FieldsWidgetGroupsDraftInitializationEffect'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { type FieldsConfiguration, WidgetConfigurationType, } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledOuterContainer = styled.div` display: flex; @@ -23,8 +24,8 @@ const StyledContainer = styled.div` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[3]}; + padding: ${themeCssVariables.spacing[2]}; overflow-y: auto; `; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsSettings.tsx index 5cde68619a3..8a186e3c853 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutFieldsSettings.tsx @@ -7,7 +7,7 @@ import { usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord } from import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { useFieldsWidgetGroups } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetGroups'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeSettings.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeSettings.tsx index 804b96f7dbb..84391efca72 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeSettings.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeSettings.tsx @@ -3,12 +3,13 @@ import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pa import { useWidgetInEditMode } from '@/command-menu/pages/page-layout/hooks/useWidgetInEditMode'; import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput'; import { useUpdatePageLayoutWidget } from '@/page-layout/hooks/useUpdatePageLayoutWidget'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isNonEmptyString, isString } from '@sniptt/guards'; import { useState } from 'react'; import { isDefined, isValidUrl } from 'twenty-shared/utils'; import { WidgetConfigurationType } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledOuterContainer = styled.div` display: flex; @@ -20,8 +21,8 @@ const StyledContainer = styled.div` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[3]}; + padding: ${themeCssVariables.spacing[2]}; `; export const CommandMenuPageLayoutIframeSettings = () => { diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorGradientOption.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorGradientOption.tsx index d0e38cd4ef1..7598943ab5c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorGradientOption.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorGradientOption.tsx @@ -2,11 +2,12 @@ import { CHART_SETTINGS_PALETTE_COLOR_GROUP_COUNT } from '@/command-menu/pages/p import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/createGraphColorRegistry'; import { generateGroupColor } from '@/page-layout/widgets/graph/utils/generateGroupColor'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ColorSample } from 'twenty-ui/display'; import { MenuItemSelect } from 'twenty-ui/navigation'; -import { type ThemeColor } from 'twenty-ui/theme'; +import { type ThemeColor, ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; type ChartColorGradientOptionProps = { colorOption: { @@ -22,7 +23,7 @@ type ChartColorGradientOptionProps = { const StyledColorSamplesContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; export const ChartColorGradientOption = ({ @@ -32,7 +33,7 @@ export const ChartColorGradientOption = ({ onSelectColor, }: ChartColorGradientOptionProps) => { const colorName = colorOption.colorName as ThemeColor; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); const colorSamples = ( diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorPaletteOption.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorPaletteOption.tsx index e536ae59436..b1558b0d48e 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorPaletteOption.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/dropdown-content/ChartColorPaletteOption.tsx @@ -2,13 +2,14 @@ import { CHART_SETTINGS_PALETTE_COLOR_GROUP_COUNT } from '@/command-menu/pages/p import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/createGraphColorRegistry'; import { getColorSchemeByIndex } from '@/page-layout/widgets/graph/utils/getColorSchemeByIndex'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { ColorSample } from 'twenty-ui/display'; import { MenuItemSelect } from 'twenty-ui/navigation'; -import { type ThemeColor } from 'twenty-ui/theme'; +import { type ThemeColor, ThemeContext } from 'twenty-ui/theme'; import { getMainColorNameFromPaletteColorName } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; type ChartColorPaletteOptionProps = { selectedItemId: string | null; @@ -19,7 +20,7 @@ type ChartColorPaletteOptionProps = { const StyledColorSamplesContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; export const ChartColorPaletteOption = ({ @@ -27,7 +28,7 @@ export const ChartColorPaletteOption = ({ currentColor, onSelectColor, }: ChartColorPaletteOptionProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx index 5749d4fd7ac..ebc7fa4813c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuMergeRecordPage.tsx @@ -5,7 +5,7 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; import { MergeRecordsContainer } from '@/object-record/record-merge/components/MergeRecordsContainer'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledRightDrawerRecord = styled.div` height: 100%; diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx index 8bf907ed581..080a0d88684 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuRecordPage.tsx @@ -11,7 +11,7 @@ import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordSh import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue'; const StyledRightDrawerRecord = styled.div<{ diff --git a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuUpdateMultipleRecords.tsx b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuUpdateMultipleRecords.tsx index 6be2188f3da..ab3d4094c54 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuUpdateMultipleRecords.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/record-page/components/CommandMenuUpdateMultipleRecords.tsx @@ -3,7 +3,7 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/ import { UpdateMultipleRecordsContainer } from '@/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer'; import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledRightDrawerRecord = styled.div` height: 100%; diff --git a/packages/twenty-front/src/modules/command-menu/pages/rich-text-page/components/CommandMenuEditRichTextPage.tsx b/packages/twenty-front/src/modules/command-menu/pages/rich-text-page/components/CommandMenuEditRichTextPage.tsx index 73e58b3232c..0a2fd51409a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/rich-text-page/components/CommandMenuEditRichTextPage.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/rich-text-page/components/CommandMenuEditRichTextPage.tsx @@ -1,11 +1,12 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { lazy, Suspense } from 'react'; +import { styled } from '@linaria/react'; +import { Suspense, lazy, useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { viewableRichTextComponentState } from '@/command-menu/pages/rich-text-page/states/viewableRichTextComponentState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const ActivityRichTextEditor = lazy(() => import('@/activities/components/ActivityRichTextEditor').then((module) => ({ @@ -15,13 +16,13 @@ const ActivityRichTextEditor = lazy(() => const StyledContainer = styled.div` box-sizing: border-box; - margin: ${({ theme }) => theme.spacing(4)} ${({ theme }) => theme.spacing(-2)}; + margin: ${themeCssVariables.spacing[4]} -8px; padding-inline: 44px 0px; width: 100%; `; const LoadingSkeleton = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( void; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); return ( diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx index 6ff3dd13e74..3c2b7354a9f 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent.tsx @@ -4,7 +4,7 @@ import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/ import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep'; import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; const StyledContainer = styled.div` diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx index c43318a5b2a..9ce0ebf4312 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx @@ -22,11 +22,12 @@ import { } from '@/workflow/workflow-steps/types/WorkflowRunTabId'; import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus'; import { WorkflowIteratorSubStepSwitcher } from '@/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isNull } from '@sniptt/guards'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; @@ -35,8 +36,8 @@ const StyledContainer = styled.div` `; const StyledTabList = styled(TabList)` - background-color: ${({ theme }) => theme.background.secondary}; - padding-left: ${({ theme }) => theme.spacing(2)}; + background-color: ${themeCssVariables.background.secondary}; + padding-left: ${themeCssVariables.spacing[2]}; `; type TabId = WorkflowRunTabIdType; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx index 1e19454c82e..5c489ce1116 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx @@ -2,7 +2,7 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; const StyledContainer = styled.div` diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx index e73bf7c43ff..cc8363ed139 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx @@ -14,12 +14,13 @@ import { DATABASE_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/Da import { OTHER_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/OtherTriggerTypes'; import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger'; import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const CommandMenuWorkflowSelectTriggerTypeContent = () => { const { getIcon } = useIcons(); @@ -72,7 +73,7 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = () => { }; }; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/file-upload/components/FileUploadProvider.tsx b/packages/twenty-front/src/modules/file-upload/components/FileUploadProvider.tsx index ccd4a8e9005..fc036748e7a 100644 --- a/packages/twenty-front/src/modules/file-upload/components/FileUploadProvider.tsx +++ b/packages/twenty-front/src/modules/file-upload/components/FileUploadProvider.tsx @@ -2,7 +2,7 @@ import { FileUploadContext, type FileUploadOptions, } from '@/file-upload/contexts/FileUploadContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useCallback, useEffect, useRef, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuDialog.tsx b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuDialog.tsx index a6a719c5ba9..b10753628e5 100644 --- a/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuDialog.tsx +++ b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuDialog.tsx @@ -6,6 +6,7 @@ import { import { t } from '@lingui/core/macro'; import { IconButton } from 'twenty-ui/input'; import { IconX } from 'twenty-ui/display'; +import { useIsMobile } from 'twenty-ui/utilities'; type KeyboardMenuDialogProps = { onClose: () => void; @@ -16,8 +17,10 @@ export const KeyboardMenuDialog = ({ onClose, children, }: KeyboardMenuDialogProps) => { + const isMobile = useIsMobile(); + return ( - + {t`Keyboard shortcuts`} diff --git a/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuStyles.tsx b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuStyles.tsx index 1c5b129430b..91a88f5c11c 100644 --- a/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuStyles.tsx +++ b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/KeyboardShortcutMenuStyles.tsx @@ -1,88 +1,88 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -export const StyledDialog = styled.div` - background: ${({ theme }) => theme.background.primary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; - font-family: ${({ theme }) => theme.font.family}; +export const StyledDialog = styled.div<{ isMobile: boolean }>` + background: ${themeCssVariables.background.primary}; + border-radius: ${themeCssVariables.border.radius.md}; + box-shadow: ${themeCssVariables.boxShadow.strong}; + font-family: ${themeCssVariables.font.family}; left: 50%; max-width: 400px; overflow: hidden; padding: 0; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; position: fixed; top: 30%; - transform: ${() => - useIsMobile() ? 'translateX(-49.5%)' : 'translateX(-50%)'}; - width: ${() => (useIsMobile() ? 'calc(100% - 40px)' : '100%')}; + transform: ${({ isMobile }) => + isMobile ? 'translateX(-49.5%)' : 'translateX(-50%)'}; + width: ${({ isMobile }) => (isMobile ? 'calc(100% - 40px)' : '100%')}; z-index: 1000; `; export const StyledHeading = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; - color: ${({ theme }) => theme.font.color.primary}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + font-weight: ${themeCssVariables.font.weight.semiBold}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; export const StyledContainer = styled.div` - gap: ${({ theme }) => theme.spacing(2)}; - padding-bottom: ${({ theme }) => theme.spacing(4)}; - padding-left: ${({ theme }) => theme.spacing(4)}; - padding-right: ${({ theme }) => theme.spacing(4)}; - padding-top: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[2]}; + padding-bottom: ${themeCssVariables.spacing[4]}; + padding-left: ${themeCssVariables.spacing[4]}; + padding-right: ${themeCssVariables.spacing[4]}; + padding-top: ${themeCssVariables.spacing[1]}; `; export const StyledGroupHeading = styled.label` - color: ${({ theme }) => theme.color.gray10}; - padding-bottom: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(4)}; + color: ${themeCssVariables.color.gray10}; + padding-bottom: ${themeCssVariables.spacing[1]}; + padding-top: ${themeCssVariables.spacing[4]}; `; export const StyledGroup = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const StyledItem = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-weight: ${themeCssVariables.font.weight.regular}; height: 24px; justify-content: space-between; `; export const StyledShortcutKey = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.strong}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - box-shadow: ${({ theme }) => theme.boxShadow.underline}; - color: ${({ theme }) => theme.font.color.tertiary}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.strong}; + border-radius: ${themeCssVariables.border.radius.sm}; + box-shadow: ${themeCssVariables.boxShadow.underline}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-direction: column; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; height: 20px; justify-content: center; - padding-left: ${({ theme }) => theme.spacing(1)}; - padding-right: ${({ theme }) => theme.spacing(1)}; + padding-left: ${themeCssVariables.spacing[1]}; + padding-right: ${themeCssVariables.spacing[1]}; text-align: center; `; export const StyledShortcutKeyContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/AddToNavigationDragHandle.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/AddToNavigationDragHandle.tsx index 1b049d20c97..c0332971d1b 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/AddToNavigationDragHandle.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/AddToNavigationDragHandle.tsx @@ -18,14 +18,10 @@ const StyledIconSlot = styled.div<{ $hasFixedSize: boolean }>` display: flex; flex-shrink: 0; justify-content: center; - - ${({ $hasFixedSize }) => - $hasFixedSize - ? ` - height: ${themeCssVariables.spacing[4]}; - width: ${themeCssVariables.spacing[4]}; - ` - : ''} + height: ${({ $hasFixedSize }) => + $hasFixedSize ? themeCssVariables.spacing[4] : 'auto'}; + width: ${({ $hasFixedSize }) => + $hasFixedSize ? themeCssVariables.spacing[4] : 'auto'}; &:active { cursor: grabbing; diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuItemIconContainer.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuItemIconContainer.tsx index 51df1dfa499..26397cbd1d0 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuItemIconContainer.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/NavigationMenuItemIconContainer.tsx @@ -14,8 +14,8 @@ export const StyledNavigationMenuItemIconContainer = styled.div<{ justify-content: center; width: ${themeCssVariables.spacing[4]}; - ${({ $backgroundColor }) => - $backgroundColor ? `background-color: ${$backgroundColor};` : ''} - ${({ $borderColor }) => - $borderColor ? `border: 1px solid ${$borderColor};` : ''} + background-color: ${({ $backgroundColor }) => + $backgroundColor ?? 'transparent'}; + border: ${({ $borderColor }) => + $borderColor ? `1px solid ${$borderColor}` : 'none'}; `; diff --git a/packages/twenty-front/src/modules/navigation-menu-item/components/ObjectIconWithViewOverlay.tsx b/packages/twenty-front/src/modules/navigation-menu-item/components/ObjectIconWithViewOverlay.tsx index 6988db7ee85..5eebc718142 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/components/ObjectIconWithViewOverlay.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/components/ObjectIconWithViewOverlay.tsx @@ -29,8 +29,8 @@ const StyledObjectIconWrapper = styled.div<{ display: flex; align-items: center; justify-content: center; - ${({ $borderColor }) => - $borderColor ? `border: 1px solid ${$borderColor};` : ''} + border: ${({ $borderColor }) => + $borderColor ? `1px solid ${$borderColor}` : 'none'}; `; const StyledViewOverlay = styled.div<{ $backgroundColor: string }>` diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormNumberFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormNumberFieldInput.tsx index f82a1a86d5f..80732d0baf1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormNumberFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormNumberFieldInput.tsx @@ -8,17 +8,21 @@ import { TextInput } from '@/ui/field/input/components/TextInput'; import { InputHint } from '@/ui/input/components/InputHint'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; -import styled from '@emotion/styled'; import isEmpty from 'lodash.isempty'; import { useId, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { canBeCastAsNumberOrNull, castAsNumberOrNull, } from '~/utils/cast-as-number-or-null'; -const StyledInput = styled(TextInput)` - padding: ${({ theme }) => `${theme.spacing(1)} ${theme.spacing(2)}`}; +import { styled } from '@linaria/react'; + +const StyledInputWrapper = styled.div` + & input { + padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}; + } `; type FormNumberFieldInputProps = { @@ -113,18 +117,20 @@ export const FormNumberFieldInput = ({ onBlur={onBlur} > {draftValue.type === 'static' ? ( - + + + ) : ( { const instanceId = useId(); @@ -67,7 +69,7 @@ export const FormRawJsonFieldInput = ({ } return ( - + {label ? {label} : null} diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormUuidFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormUuidFieldInput.tsx index a5d772e96fc..a4b73e8783a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormUuidFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormUuidFieldInput.tsx @@ -7,12 +7,15 @@ import { type VariablePickerComponent } from '@/object-record/record-field/ui/fo import { TextInput } from '@/ui/field/input/components/TextInput'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useId, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledInput = styled(TextInput)` - padding: ${({ theme }) => `${theme.spacing(1)} ${theme.spacing(2)}`}; +const StyledInputWrapper = styled.div` + & input { + padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}; + } `; type FormUuidFieldInputProps = { @@ -100,14 +103,16 @@ export const FormUuidFieldInput = ({ hasRightElement={isDefined(VariablePicker) && !readonly} > {draftValue.type === 'static' ? ( - + + + ) : ( ` +const disabledTransitionsClass = css` + .react-grid-layout { + transition: none !important; + } + + .react-grid-item { + transition: none !important; + } + + .react-grid-item.cssTransforms { + transition-property: none !important; + } +`; + +const StyledGridContainer = styled.div` box-sizing: border-box; flex: 1; min-height: 100%; position: relative; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; width: 100%; user-select: none; .react-grid-placeholder { - background: ${({ theme }) => theme.color.blue7} !important; + background: ${themeCssVariables.color.blue7} !important; - border-radius: ${({ theme }) => theme.border.radius.md}; + border-radius: ${themeCssVariables.border.radius.md}; } .react-grid-item:not(.react-draggable-dragging) { @@ -68,22 +83,6 @@ const StyledGridContainer = styled.div<{ $disableTransitions: boolean }>` .react-grid-item:hover .widget-card-resize-handle { display: block !important; } - - ${({ $disableTransitions }) => - $disableTransitions && - css` - .react-grid-layout { - transition: none !important; - } - - .react-grid-item { - transition: none !important; - } - - .react-grid-item.cssTransforms { - transition-property: none !important; - } - `} `; type ExtendedResponsiveProps = ResponsiveProps & { @@ -172,7 +171,9 @@ export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => { return ( {isPageLayoutInEditMode && ( <> diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx index 498cd365d35..c893518e228 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridOverlay.tsx @@ -9,41 +9,44 @@ import { calculateTotalGridRows } from '@/page-layout/utils/calculateTotalGridRo import { generateCellId } from '@/page-layout/utils/generateCellId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useMemo } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledGridOverlay = styled.div<{ isDragSelecting?: boolean; breakpoint: PageLayoutBreakpoint; }>` position: absolute; - top: ${({ theme }) => theme.spacing(2)}; - left: ${({ theme }) => theme.spacing(2)}; - right: ${({ theme }) => theme.spacing(2)}; - bottom: ${({ theme }) => theme.spacing(2)}; + top: ${themeCssVariables.spacing[2]}; + left: ${themeCssVariables.spacing[2]}; + right: ${themeCssVariables.spacing[2]}; + bottom: ${themeCssVariables.spacing[2]}; display: grid; grid-template-columns: ${({ breakpoint }) => breakpoint === 'mobile' ? '1fr' : 'repeat(12, 1fr)'}; grid-auto-rows: 55px; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; pointer-events: ${({ isDragSelecting }) => isDragSelecting ? 'auto' : 'none'}; z-index: ${PAGE_LAYOUT_GRID_OVERLAY_Z_INDEX}; `; const StyledGridCell = styled.div<{ isSelected?: boolean }>` - background: ${({ isSelected, theme }) => - isSelected ? theme.color.blue3 : 'transparent'}; + background: ${({ isSelected }) => + isSelected ? themeCssVariables.color.blue3 : 'transparent'}; border: 1px solid - ${({ theme, isSelected }) => - isSelected ? theme.color.blue7 : theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + ${({ isSelected }) => + isSelected + ? themeCssVariables.color.blue7 + : themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; cursor: pointer; transition: background-color 0.3s ease; &:hover { - background: ${({ theme }) => theme.background.transparent.lighter}; - border-color: ${({ theme }) => theme.border.color.medium}; + background: ${themeCssVariables.background.transparent.lighter}; + border-color: ${themeCssVariables.border.color.medium}; } `; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridResizeHandle.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridResizeHandle.tsx index ae3c331e28c..44dc5c28a74 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridResizeHandle.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridResizeHandle.tsx @@ -1,12 +1,13 @@ -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { forwardRef } from 'react'; +import { styled } from '@linaria/react'; +import { forwardRef, useContext } from 'react'; import { IconRadiusBottomLeft, IconRadiusBottomRight, IconRadiusTopLeft, IconRadiusTopRight, } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; type WidgetHandleAxis = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'; type WidgetHorizontalHandleAxis = 'n' | 's'; @@ -29,60 +30,61 @@ const StyledCornerIconWrapper = styled.div<{ justify-content: center; align-items: center; cursor: ${({ cursor }) => cursor}; - width: ${({ theme }) => theme.spacing(4)}; - height: ${({ theme }) => theme.spacing(4)}; + width: ${themeCssVariables.spacing[4]}; + height: ${themeCssVariables.spacing[4]}; & svg { color: transparent; flex-shrink: 0; pointer-events: none; - transform: ${({ position, theme }) => { + transform: ${({ position }) => { if (position === 'se') { - return `translate(-${theme.spacing(2)}, -${theme.spacing(2)})`; + return `translate(-${themeCssVariables.spacing[2]}, -${themeCssVariables.spacing[2]})`; } if (position === 'sw') { - return `translate(${theme.spacing(2)}, -${theme.spacing(2)})`; + return `translate(${themeCssVariables.spacing[2]}, -${themeCssVariables.spacing[2]})`; } if (position === 'ne') { - return `translate(-${theme.spacing(2)}, ${theme.spacing(2)})`; + return `translate(-${themeCssVariables.spacing[2]}, ${themeCssVariables.spacing[2]})`; } if (position === 'nw') { - return `translate(${theme.spacing(2)}, ${theme.spacing(2)})`; + return `translate(${themeCssVariables.spacing[2]}, ${themeCssVariables.spacing[2]})`; } + return ''; }}; } :hover { svg { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } } `; const StyledVerticalHandle = styled.div` - border-radius: ${({ theme }) => theme.border.radius.sm}; - height: ${({ theme }) => theme.spacing(5)}; - width: ${({ theme }) => theme.icon.stroke.lg}px; + border-radius: ${themeCssVariables.border.radius.sm}; + height: ${themeCssVariables.spacing[5]}; + width: ${themeCssVariables.icon.stroke.lg}px; `; const StyledHorizontalHandle = styled.div` - border-radius: ${({ theme }) => theme.border.radius.sm}; - height: ${({ theme }) => theme.icon.stroke.lg}px; - width: ${({ theme }) => theme.spacing(5)}; + border-radius: ${themeCssVariables.border.radius.sm}; + height: ${themeCssVariables.icon.stroke.lg}px; + width: ${themeCssVariables.spacing[5]}; `; const StyledHorizontalHandleWrapper = styled.div<{ widgetHandleAxis: WidgetHorizontalHandleAxis; }>` - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; cursor: row-resize; transform: ${({ widgetHandleAxis }) => widgetHandleAxis === 'n' ? 'translateY(-50%)' : 'translateY(50%)'}; - padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]}; :hover { & > div { - background-color: ${({ theme }) => theme.font.color.tertiary}; + background-color: ${themeCssVariables.font.color.tertiary}; } } `; @@ -91,14 +93,14 @@ const StyledVerticalHandleWrapper = styled.div<{ widgetHandleAxis: WidgetVerticalHandleAxis; }>` cursor: col-resize; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; transform: ${({ widgetHandleAxis }) => widgetHandleAxis === 'w' ? 'translateX(-50%)' : 'translateX(50%)'}; - padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]}; :hover { & > div { - background-color: ${({ theme }) => theme.font.color.tertiary}; + background-color: ${themeCssVariables.font.color.tertiary}; } } `; @@ -107,64 +109,53 @@ const StyledResizeHandleWrapper = styled.div<{ widgetHandleAxis?: WidgetHandleAxis; }>` position: absolute; - ${({ theme, widgetHandleAxis }) => { - if (widgetHandleAxis === 'w') { - return css` - left: ${theme.spacing(1.5)}; - top: 50%; - transform: translateY(-50%); - `; + + top: ${({ widgetHandleAxis }) => { + if (widgetHandleAxis === 'w' || widgetHandleAxis === 'e') return '50%'; + if (widgetHandleAxis === 'n') return themeCssVariables.spacing[1.5]; + if (widgetHandleAxis === 'ne' || widgetHandleAxis === 'nw') return '0'; + return 'auto'; + }}; + + bottom: ${({ widgetHandleAxis }) => { + if (widgetHandleAxis === 's') return themeCssVariables.spacing[1.5]; + if (widgetHandleAxis === 'se' || widgetHandleAxis === 'sw') return '0'; + return 'auto'; + }}; + + left: ${({ widgetHandleAxis }) => { + if (widgetHandleAxis === 'w') return themeCssVariables.spacing[1.5]; + if (widgetHandleAxis === 'n' || widgetHandleAxis === 's') return '50%'; + if (widgetHandleAxis === 'sw' || widgetHandleAxis === 'nw') return '0'; + return 'auto'; + }}; + + right: ${({ widgetHandleAxis }) => { + if (widgetHandleAxis === 'e') return themeCssVariables.spacing[1.5]; + if (widgetHandleAxis === 'se' || widgetHandleAxis === 'ne') return '0'; + return 'auto'; + }}; + + transform: ${({ widgetHandleAxis }) => { + switch (widgetHandleAxis) { + case 'w': + case 'e': + return 'translateY(-50%)'; + case 'n': + case 's': + return 'translateX(-50%)'; + case 'se': + return `translate(${themeCssVariables.spacing[1]}, ${themeCssVariables.spacing[1]})`; + case 'sw': + return `translate(-${themeCssVariables.spacing[1]}, ${themeCssVariables.spacing[1]})`; + case 'ne': + return `translate(${themeCssVariables.spacing[1]}, -${themeCssVariables.spacing[1]})`; + case 'nw': + return `translate(-${themeCssVariables.spacing[1]}, -${themeCssVariables.spacing[1]})`; + default: + return 'none'; } - if (widgetHandleAxis === 'e') { - return css` - right: ${theme.spacing(1.5)}; - top: 50%; - transform: translateY(-50%); - `; - } - if (widgetHandleAxis === 'n') { - return css` - top: ${theme.spacing(1.5)}; - left: 50%; - transform: translateX(-50%); - `; - } - if (widgetHandleAxis === 's') { - return css` - bottom: ${theme.spacing(1.5)}; - left: 50%; - transform: translateX(-50%); - `; - } - if (widgetHandleAxis === 'se') { - return css` - bottom: 0; - right: 0; - transform: translate(${theme.spacing(1)}, ${theme.spacing(1)}); - `; - } - if (widgetHandleAxis === 'sw') { - return css` - bottom: 0; - left: 0; - transform: translate(-${theme.spacing(1)}, ${theme.spacing(1)}); - `; - } - if (widgetHandleAxis === 'ne') { - return css` - right: 0; - top: 0; - transform: translate(${theme.spacing(1)}, -${theme.spacing(1)}); - `; - } - if (widgetHandleAxis === 'nw') { - return css` - left: 0; - top: 0; - transform: translate(-${theme.spacing(1)}, -${theme.spacing(1)}); - `; - } - }} + }}; `; const isVerticalHandle = ( @@ -192,7 +183,7 @@ export const PageLayoutGridResizeHandle = forwardRef< }, ref, ) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.background.secondary}; + background: ${themeCssVariables.background.secondary}; border-bottom-left-radius: 8px; - border-right: ${({ theme }) => `1px solid ${theme.border.color.medium}`}; + border-right: 1px solid ${themeCssVariables.border.color.medium}; border-top-left-radius: 8px; box-sizing: border-box; display: grid; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx index 682726aa261..45c7f940c6d 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx @@ -20,11 +20,12 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { useIsMobile } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ hasPinnedTab: boolean }>` display: grid; @@ -42,7 +43,7 @@ const StyledTabsAndDashboardContainer = styled.div` `; const StyledPageLayoutTabList = styled(PageLayoutTabList)` - padding-left: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; `; const StyledScrollWrapper = styled(ScrollWrapper)` diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx index 6be8c2a20f2..25efa63ed89 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { DragDropContext, type DropResult, @@ -47,17 +47,18 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import { CommandMenuPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { type PageLayoutType } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` box-sizing: border-box; display: flex; - height: ${({ theme }) => theme.spacing(10)}; + height: ${themeCssVariables.spacing[10]}; position: relative; user-select: none; width: 100%; &::after { - background-color: ${({ theme }) => theme.border.color.light}; + background-color: ${themeCssVariables.border.color.light}; bottom: 0; content: ''; height: 1px; @@ -70,7 +71,7 @@ const StyledContainer = styled.div` const StyledAddButton = styled.div` display: flex; align-items: center; - height: ${({ theme }) => theme.spacing(10)}; + height: ${themeCssVariables.spacing[10]}; margin-left: ${TAB_LIST_GAP}px; `; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListDroppableMoreButton.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListDroppableMoreButton.tsx index c3dda048116..adafb63bb16 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListDroppableMoreButton.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListDroppableMoreButton.tsx @@ -1,21 +1,23 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Droppable } from '@hello-pangea/dnd'; import { PAGE_LAYOUT_TAB_LIST_DROPPABLE_IDS } from '@/page-layout/components/PageLayoutTabListDroppableIds'; import { TabMoreButton } from '@/ui/layout/tab-list/components/TabMoreButton'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type PageLayoutTabListDroppableMoreButtonProps = { hiddenTabsCount: number; isActiveTabHidden: boolean; }; -const StyledTabMoreButton = styled(TabMoreButton)<{ isDraggingOver: boolean }>` - ${({ isDraggingOver, theme }) => - isDraggingOver && - ` - background-color: ${theme.background.transparent.blue}; +const StyledTabMoreButtonWrapper = styled.div<{ isDraggingOver: boolean }>` + ${({ isDraggingOver }) => + isDraggingOver + ? ` + background-color: ${themeCssVariables.background.transparent.blue}; pointer-events: none; - `} + ` + : ''} `; export const PageLayoutTabListDroppableMoreButton = ({ @@ -30,11 +32,12 @@ export const PageLayoutTabListDroppableMoreButton = ({ // eslint-disable-next-line react/jsx-props-no-spreading {...provided.droppableProps} > - + + + )} diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx index 89bdd818db7..89a936d6921 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableOverflowDropdown.tsx @@ -1,5 +1,4 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Draggable, type DraggableProvided, @@ -30,6 +29,7 @@ import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSe import { useContext } from 'react'; import { CommandMenuPages } from 'twenty-shared/types'; import { type PageLayoutType } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledOverflowDropdownListDraggableWrapper = styled.div` display: flex; @@ -65,7 +65,7 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({ onClose, pageLayoutType, }: PageLayoutTabListReorderableOverflowDropdownProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const context = useContext(TabListComponentInstanceContext); const instanceId = context?.instanceId; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx index 796910d1637..552c06a7f73 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListReorderableTab.tsx @@ -3,8 +3,9 @@ import { Draggable } from '@hello-pangea/dnd'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { StyledTabContainer, TabContent } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type PageLayoutTabListReorderableTabProps = { tab: SingleTabProps; @@ -14,9 +15,9 @@ type PageLayoutTabListReorderableTabProps = { onSelect: () => void; }; -const StyledTabContent = styled(TabContent)<{ isBeingEdited: boolean }>` - outline: ${({ isBeingEdited, theme }) => - isBeingEdited ? `1px solid ${theme.color.blue}` : 'none'}; +const StyledTabContentWrapper = styled.div<{ isBeingEdited: boolean }>` + outline: ${({ isBeingEdited }) => + isBeingEdited ? `1px solid ${themeCssVariables.color.blue}` : 'none'}; outline-offset: -1px; `; @@ -49,16 +50,17 @@ export const PageLayoutTabListReorderableTab = ({ cursor: draggableSnapshot.isDragging ? 'grabbing' : 'pointer', }} > - + + + )} diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListVisibleTabs.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListVisibleTabs.tsx index ed52dec5f70..103b4e8bd4a 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListVisibleTabs.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabListVisibleTabs.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type DraggableProvided, type DraggableRubric, diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabMenuItemSelectAvatar.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabMenuItemSelectAvatar.tsx index 4b413a7900e..2d3196c850c 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabMenuItemSelectAvatar.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabMenuItemSelectAvatar.tsx @@ -1,6 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { type MouseEvent, useState } from 'react'; +import { styled } from '@linaria/react'; +import { type MouseEvent, useContext, useState } from 'react'; import { TabAvatar } from '@/ui/layout/tab-list/components/TabAvatar'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; @@ -12,12 +11,14 @@ import { StyledMenuItemLabel, StyledMenuItemLeftContent, } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledTextContainer = styled.div` display: flex; align-items: center; flex: 1 0 0; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; max-width: 100%; text-overflow: ellipsis; overflow: hidden; @@ -26,7 +27,7 @@ const StyledTextContainer = styled.div` const StyledRightContent = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; type PageLayoutTabMenuItemSelectAvatarProps = { @@ -48,7 +49,7 @@ export const PageLayoutTabMenuItemSelectAvatar = ({ onEditClick, testId, }: PageLayoutTabMenuItemSelectAvatarProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isHovered, setIsHovered] = useState(false); return ( diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx index 9b4025f584a..b39b3ab682c 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutTabRenderClone.tsx @@ -4,11 +4,12 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { TabAvatar } from '@/ui/layout/tab-list/components/TabAvatar'; import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type DraggableProvided } from '@hello-pangea/dnd'; import { StyledTabContainer, TabContent } from 'twenty-ui/input'; import { MenuItemSelectAvatar } from 'twenty-ui/navigation'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledDraggableWrapper = styled.div` display: flex; @@ -28,7 +29,7 @@ export const PageLayoutTabRenderClone = ({ provided: DraggableProvided; activeTabId: string | null; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const pageLayoutTabListCurrentDragDroppableId = useAtomComponentStateValue( pageLayoutTabListCurrentDragDroppableIdComponentState, diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx index 2cc8bc9bb72..77c0d68d294 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx @@ -6,7 +6,7 @@ import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer' import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { DragDropContext, Draggable, @@ -15,26 +15,31 @@ import { } from '@hello-pangea/dnd'; import { useId } from 'react'; import { useIsMobile } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledVerticalListContainer = styled.div<{ variant: PageLayoutVerticalListViewerVariant; shouldUseWhiteBackground: boolean; }>` - background: ${({ theme, shouldUseWhiteBackground }) => + background: ${({ shouldUseWhiteBackground }) => shouldUseWhiteBackground - ? theme.background.primary - : theme.background.secondary}; + ? themeCssVariables.background.primary + : themeCssVariables.background.secondary}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; - padding: ${({ theme, variant }) => - variant === 'side-column' ? theme.spacing(1) : theme.spacing(2)}; + gap: ${themeCssVariables.spacing[4]}; + padding: ${({ variant }) => + variant === 'side-column' + ? themeCssVariables.spacing[1] + : themeCssVariables.spacing[2]}; `; const StyledDraggableWrapper = styled.div<{ isDragging: boolean }>` - background: ${({ theme, isDragging }) => - isDragging ? theme.background.transparent.light : 'transparent'}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${({ isDragging }) => + isDragging + ? themeCssVariables.background.transparent.light + : 'transparent'}; + border-radius: ${themeCssVariables.border.radius.sm}; transition: background 0.1s ease; `; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx index f72593f775f..cc882ff2a49 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useIsMobile } from 'twenty-ui/utilities'; import { getPageLayoutVerticalListViewerVariant } from '@/page-layout/components/utils/getPageLayoutVerticalListViewerVariant'; @@ -7,21 +7,22 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer'; import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledVerticalListContainer = styled.div<{ variant: PageLayoutVerticalListViewerVariant; shouldUseWhiteBackground: boolean; }>` - background: ${({ theme, shouldUseWhiteBackground }) => + background: ${({ shouldUseWhiteBackground }) => shouldUseWhiteBackground - ? theme.background.primary - : theme.background.secondary}; + ? themeCssVariables.background.primary + : themeCssVariables.background.secondary}; display: flex; flex-direction: column; - gap: ${({ theme, variant }) => - variant === 'side-column' ? 0 : theme.spacing(2)}; - padding: ${({ theme, variant }) => - variant === 'side-column' ? 0 : theme.spacing(2)}; + gap: ${({ variant }) => + variant === 'side-column' ? 0 : themeCssVariables.spacing[2]}; + padding: ${({ variant }) => + variant === 'side-column' ? 0 : themeCssVariables.spacing[2]}; `; type PageLayoutVerticalListViewerProps = { diff --git a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx index e84b33ad88a..fb37c1f4b46 100644 --- a/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutTabList.stories.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type DropResult, type ResponderProvided } from '@hello-pangea/dnd'; import type { Meta, StoryObj } from '@storybook/react-vite'; import { useMemo, useState } from 'react'; @@ -11,10 +11,11 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab'; import { calculateNewPosition } from '@/ui/layout/draggable-list/utils/calculateNewPosition'; import { PageLayoutType } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` - border: 1px solid ${({ theme }) => theme.border.color.strong}; - padding: ${({ theme }) => theme.spacing(4)}; + border: 1px solid ${themeCssVariables.border.color.strong}; + padding: ${themeCssVariables.spacing[4]}; width: 720px; `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx index f1ad00c2934..4e26e937826 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx @@ -2,7 +2,7 @@ import { CalendarEventsCard } from '@/activities/calendar/components/CalendarEve import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetInvalidConfigDisplay.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetInvalidConfigDisplay.tsx index dbc8efcd2ca..77ec361a0e9 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetInvalidConfigDisplay.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetInvalidConfigDisplay.tsx @@ -1,5 +1,5 @@ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { AppTooltip, Status } from 'twenty-ui/display'; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay.tsx index 9cc20b7641b..825fe7fef91 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay.tsx @@ -1,5 +1,5 @@ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { AppTooltip, Status } from 'twenty-ui/display'; import { WidgetType } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetActionFieldSeeAll.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetActionFieldSeeAll.tsx index ce9a61b6655..517dc9962ae 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetActionFieldSeeAll.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetActionFieldSeeAll.tsx @@ -11,8 +11,7 @@ import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue'; import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { Link } from 'react-router-dom'; import { AppPath, ViewFilterOperand } from 'twenty-shared/types'; @@ -25,18 +24,17 @@ import { } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; import { RelationType } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledLink = styled(Link)` display: flex; text-decoration: none; `; -const StyledSeeAllButton = styled(LightIconButton)<{ isMobile: boolean }>` - ${({ theme, isMobile }) => css` - opacity: ${isMobile ? 1 : 0}; - pointer-events: none; - transition: opacity ${theme.animation.duration.instant}s ease; - `} +const StyledSeeAllButtonWrapper = styled.div<{ isMobile: boolean }>` + opacity: ${({ isMobile }) => (isMobile ? '1' : '0')}; + pointer-events: none; + transition: opacity ${themeCssVariables.animation.duration.instant}s ease; .widget:hover & { opacity: 1; @@ -134,11 +132,9 @@ export const WidgetActionFieldSeeAll = () => { <>
- + + +
{ - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { deletePageLayoutWidget } = useDeletePageLayoutWidget(); const { handleEditWidget } = useEditPageLayoutWidget(); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx index 1aa8c7a17f2..0aba5fd279f 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetSkeletonLoader.tsx @@ -1,7 +1,8 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledContainer = styled.div` align-items: center; @@ -12,7 +13,7 @@ const StyledContainer = styled.div` `; export const WidgetSkeletonLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx index 5883ccd04a4..c241de658c3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx @@ -2,7 +2,7 @@ import { EmailsCard } from '@/activities/emails/components/EmailsCard'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidget.tsx index 66704194a03..f83b81d8e8b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field-rich-text/components/FieldRichTextWidget.tsx @@ -1,6 +1,6 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { FieldRichTextCard } from '@/ui/layout/show-page/components/FieldRichTextCard'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidget.tsx index fec38f50b03..d276ab4f589 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidget.tsx @@ -17,7 +17,7 @@ import { assertFieldWidgetOrThrow } from '@/page-layout/widgets/field/utils/asse import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue'; import { isDefined } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx index 1ade1d33bac..5cb31a5af6d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetDisplay.tsx @@ -18,7 +18,7 @@ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` width: 100%; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetEditAction.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetEditAction.tsx index 1bab456b058..7fabc444d31 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetEditAction.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetEditAction.tsx @@ -4,17 +4,15 @@ import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldCont import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; import { useOpenFieldWidgetFieldInputEditMode } from '@/page-layout/widgets/field/hooks/useOpenFieldWidgetFieldInputEditMode'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconPencil } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledEditButton = styled(LightIconButton)<{ isMobile: boolean }>` - ${({ theme, isMobile }) => css` - opacity: ${isMobile ? 1 : 0}; - pointer-events: none; - transition: opacity ${theme.animation.duration.instant}s ease; - `} +const StyledEditButtonWrapper = styled.div<{ isMobile: boolean }>` + opacity: ${({ isMobile }) => (isMobile ? '1' : '0')}; + pointer-events: none; + transition: opacity ${themeCssVariables.animation.duration.instant}s ease; .widget:hover & { opacity: 1; @@ -37,11 +35,12 @@ export const FieldWidgetEditAction = () => { }; return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCellContainer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCellContainer.tsx index 65e8b2fec29..453c9f0bfa6 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCellContainer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetInlineCellContainer.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useContext } from 'react'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { useFieldFocus } from '@/object-record/record-field/ui/hooks/useFieldFocus'; import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext'; import { RecordInlineCellValue } from '@/object-record/record-inline-cell/components/RecordInlineCellValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledValueContainer = styled.div<{ readonly: boolean }>` display: flex; @@ -18,7 +19,7 @@ const StyledInlineCellBaseContainer = styled.div<{ readonly: boolean }>` width: 100%; display: flex; height: fit-content; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; user-select: none; align-items: center; cursor: ${({ readonly }) => (readonly ? 'default' : 'pointer')}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationCard.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationCard.tsx index d5266c60bf8..ef82ad4f4b7 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationCard.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Fragment, useState } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -25,9 +25,10 @@ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledShowMoreButtonContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; `; type FieldWidgetMorphRelationCardProps = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationField.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationField.tsx index f9b381eb56a..c8cc564c172 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationField.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetMorphRelationField.tsx @@ -3,17 +3,18 @@ import { useGetMorphRelationRelatedRecordsWithObjectNameSingular } from '@/objec import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldMorphRelationMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` box-sizing: border-box; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; width: 100%; `; const StyledRelationChipsContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; flex-wrap: wrap; `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationCard.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationCard.tsx index 613998efc6e..187ef4cb3c6 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationCard.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Fragment, useState } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -23,9 +23,10 @@ import { useCurrentWidget } from '@/page-layout/widgets/hooks/useCurrentWidget'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledShowMoreButtonContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; `; type FieldWidgetRelationCardProps = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx index 4f6d7b15a76..a4eb85ba3e3 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationEditAction.tsx @@ -21,11 +21,11 @@ import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/reco import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { CustomError } from 'twenty-shared/utils'; import { IconPencil } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type FieldWidgetRelationEditActionProps = { fieldDefinition: @@ -34,17 +34,17 @@ type FieldWidgetRelationEditActionProps = { recordId: string; }; -const StyledEditButton = styled(LightIconButton)<{ +const StyledEditButtonWrapper = styled.div<{ isDropdownOpen: boolean; isMobile: boolean; }>` - ${({ isDropdownOpen, isMobile, theme }) => - !isDropdownOpen && - css` - opacity: ${isMobile ? 1 : 0}; - pointer-events: none; - transition: opacity ${theme.animation.duration.instant}s ease; - `} + opacity: ${({ isDropdownOpen, isMobile }) => + isDropdownOpen ? '1' : isMobile ? '1' : '0'}; + pointer-events: ${({ isDropdownOpen }) => (isDropdownOpen ? 'auto' : 'none')}; + transition: ${({ isDropdownOpen }) => + isDropdownOpen + ? 'none' + : `opacity ${themeCssVariables.animation.duration.instant}s ease`}; .widget:hover & { opacity: 1; @@ -107,12 +107,12 @@ export const FieldWidgetRelationEditAction = ({ const isMobile = useIsMobile(); const dropdownTriggerClickableComponent = ( - + > + + ); return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationField.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationField.tsx index 842e9bb9ea9..f2a7347bab6 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationField.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetRelationField.tsx @@ -2,18 +2,19 @@ import { RecordChip } from '@/object-record/components/RecordChip'; import { type FieldDefinition } from '@/object-record/record-field/ui/types/FieldDefinition'; import { type FieldRelationMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` box-sizing: border-box; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; width: 100%; `; const StyledRelationChipsContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; flex-wrap: wrap; `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetShowMoreButton.tsx b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetShowMoreButton.tsx index 597277cc6a3..3d1926b1fc0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetShowMoreButton.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/field/components/FieldWidgetShowMoreButton.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconChevronDown } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type FieldWidgetShowMoreButtonProps = { remainingCount: number; @@ -12,20 +13,20 @@ const StyledButton = styled.button` display: flex; width: 100%; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; height: 24px; box-sizing: border-box; padding: 0; border: none; background: transparent; - color: ${({ theme }) => theme.font.color.tertiary}; - font-family: ${({ theme }) => theme.font.family}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + color: ${themeCssVariables.font.color.tertiary}; + font-family: ${themeCssVariables.font.family}; + font-weight: ${themeCssVariables.font.weight.regular}; cursor: pointer; - transition: color ${({ theme }) => theme.animation.duration.instant}s ease; + transition: color ${themeCssVariables.animation.duration.instant}s ease; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationEditor.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationEditor.tsx index 3746409f45f..d8918802d3b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationEditor.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationEditor.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { DragDropContext, Draggable, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx index 231677c4c55..4417f785f22 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupEditor.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Droppable, type DraggableProvided } from '@hello-pangea/dnd'; import { useLingui } from '@lingui/react/macro'; @@ -16,6 +16,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; import { IconNewSection } from 'twenty-ui/display'; import { MenuItem, MenuItemDraggable } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledFieldsDroppable = styled.div` display: flex; @@ -23,12 +24,12 @@ const StyledFieldsDroppable = styled.div` `; const StyledGroupContainer = styled.div<{ isDragging: boolean }>` - background: ${({ isDragging, theme }) => - isDragging ? theme.background.primary : 'transparent'}; + background: ${({ isDragging }) => + isDragging ? themeCssVariables.background.primary : 'transparent'}; border: 1px solid - ${({ isDragging, theme }) => - isDragging ? theme.color.blue : 'transparent'}; - border-radius: ${({ theme }) => theme.border.radius.md}; + ${({ isDragging }) => + isDragging ? themeCssVariables.color.blue : 'transparent'}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; width: 100%; @@ -48,7 +49,7 @@ const StyledMenuItemDraggableWrapper = styled.div` const StyledDropdownContainer = styled.div` position: absolute; - right: ${({ theme }) => theme.spacing(1)}; + right: ${themeCssVariables.spacing[1]}; top: 50%; transform: translateY(-50%); z-index: 1; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupRenameInput.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupRenameInput.tsx index bb7ebd73dc1..543ae8f26da 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupRenameInput.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsConfigurationGroupRenameInput.tsx @@ -1,16 +1,17 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { Key } from 'ts-key-enum'; import { TextInput } from '@/ui/input/components/TextInput'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]}; width: 100%; box-sizing: border-box; `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx index 25e63f5e689..dd0b04967a2 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx @@ -28,7 +28,7 @@ import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingC import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { AnimatedPlaceholder, @@ -39,6 +39,7 @@ import { EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from 'twenty-ui/layout'; import { type FieldsConfiguration } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` box-sizing: border-box; @@ -49,12 +50,12 @@ const StyledContainer = styled.div` const StyledPropertyBox = styled.div` align-self: stretch; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(3)}; - padding-bottom: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[3]}; + padding-bottom: ${themeCssVariables.spacing[3]}; `; type FieldsWidgetProps = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetGroupContainer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetGroupContainer.tsx index 437cc9736c2..605d4de240e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetGroupContainer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidgetGroupContainer.tsx @@ -1,9 +1,9 @@ -import isPropValid from '@emotion/is-prop-valid'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useState } from 'react'; +import { styled } from '@linaria/react'; +import { useContext, useState } from 'react'; import { IconChevronDown } from 'twenty-ui/display'; import { AnimatedExpandableContainer, Section } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledHeader = styled.header` align-items: center; @@ -14,18 +14,17 @@ const StyledHeader = styled.header` `; const StyledTitleLabel = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.tertiary}; + font-weight: ${themeCssVariables.font.weight.medium}; `; -const StyledChevronIcon = styled(IconChevronDown, { - shouldForwardProp: (prop) => isPropValid(prop) && prop !== 'isExpanded', -})<{ isExpanded: boolean }>` - color: ${({ theme }) => theme.font.color.tertiary}; +const StyledChevronWrapper = styled.div<{ isExpanded: boolean }>` + color: ${themeCssVariables.font.color.tertiary}; transform: ${({ isExpanded }) => isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'}; - transition: ${({ theme }) => - `transform ${theme.animation.duration.normal}s ease`}; + transition: transform + calc(${themeCssVariables.animation.duration.normal} * 1s) ease; + display: flex; `; type FieldsWidgetGroupContainerProps = { @@ -38,7 +37,7 @@ export const FieldsWidgetGroupContainer = ({ title, }: FieldsWidgetGroupContainerProps) => { const [isExpanded, setIsExpanded] = useState(true); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const handleToggleGroup = () => setIsExpanded((previousIsExpanded) => !previousIsExpanded); @@ -47,11 +46,12 @@ export const FieldsWidgetGroupContainer = ({
{title} - + + + { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const tickFontSize = axisConfig.tickFontSize; const legendFontSize = axisConfig.legendFontSize; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/BottomAxisTicks.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/BottomAxisTicks.tsx index 4820ca3364d..5f640b1871c 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/BottomAxisTicks.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/BottomAxisTicks.tsx @@ -1,4 +1,5 @@ -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type BottomAxisTicksProps = { bottomTickValues: (string | number)[]; @@ -19,7 +20,7 @@ export const BottomAxisTicks = ({ tickPadding, tickFontSize, }: BottomAxisTicksProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( <> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/LeftAxisTicks.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/LeftAxisTicks.tsx index 165b5608c37..15e11a87927 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/LeftAxisTicks.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/LeftAxisTicks.tsx @@ -1,4 +1,5 @@ -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type LeftAxisTicksProps = { leftTickValues: (string | number)[]; @@ -15,7 +16,7 @@ export const LeftAxisTicks = ({ tickPadding, tickFontSize, }: LeftAxisTicksProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( <> diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/ZeroLine.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/ZeroLine.tsx index d1da28b1542..f881863cf0e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/ZeroLine.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/chart-core/layers/ZeroLine.tsx @@ -1,4 +1,5 @@ -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type ZeroLineProps = { isVertical: boolean; @@ -13,7 +14,7 @@ export const ZeroLine = ({ innerWidth, innerHeight, }: ZeroLineProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const styles = calculateGraphLabelStyles(label, offset, isVerticalLayout); return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartContainer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartContainer.tsx index 749fa44f251..a28a8aadf38 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartContainer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetChartContainer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; type GraphWidgetChartContainerProps = { $isClickable?: boolean; @@ -11,13 +11,13 @@ const StyledGraphWidgetChartContainer = styled.div - $isClickable && - $cursorSelector && - ` + $isClickable && $cursorSelector + ? ` ${$cursorSelector} { cursor: pointer; } - `} + ` + : ''} `; export const GraphWidgetChartContainer = StyledGraphWidgetChartContainer; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip.tsx index a6a553dc363..51580b2c41e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip.tsx @@ -3,10 +3,11 @@ import { type GraphWidgetTooltipItem, } from '@/page-layout/widgets/graph/components/GraphWidgetTooltip'; import { useGraphWidgetTooltipFloating } from '@/page-layout/widgets/graph/hooks/useGraphWidgetTooltipFloating'; -import { useTheme } from '@emotion/react'; import { FloatingPortal, type VirtualElement } from '@floating-ui/react'; import { animated, useSpring } from '@react-spring/web'; import { isDefined } from 'twenty-shared/utils'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type GraphWidgetFloatingTooltipProps = { reference: Element | VirtualElement | null; @@ -33,7 +34,7 @@ export const GraphWidgetFloatingTooltip = ({ onMouseLeave, disablePointerEvents = false, }: GraphWidgetFloatingTooltipProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { refs, x, y, isPositioned } = useGraphWidgetTooltipFloating( reference, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx index 6b62e069481..250da1a8bc5 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/GraphWidgetLegend.tsx @@ -11,16 +11,17 @@ import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDi import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AnimatePresence, motion } from 'framer-motion'; -import { useRef, useState } from 'react'; +import { useContext, useRef, useState } from 'react'; import { IconChevronLeft, IconChevronRight, OverflowingTextWithTooltip, } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; export type GraphWidgetLegendItem = { id: string; @@ -42,26 +43,28 @@ const StyledAnimationClipContainer = styled.div` position: relative; `; -const StyledLegendMotionWrapper = styled(motion.div)` +const StyledLegendMotionWrapperBase = styled.div` width: 100%; `; +const StyledLegendMotionWrapper = motion.create(StyledLegendMotionWrapperBase); -const StyledItemsWrapper = styled(motion.div)<{ centered?: boolean }>` +const StyledItemsWrapperBase = styled.div<{ centered?: boolean }>` display: flex; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; flex-wrap: nowrap; flex: 1; min-width: 0; justify-content: ${({ centered }) => (centered ? 'center' : 'flex-start')}; `; +const StyledItemsWrapper = motion.create(StyledItemsWrapperBase); const StyledLegendContainer = styled.div<{ needsPagination: boolean }>` display: flex; flex-wrap: nowrap; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; justify-content: ${({ needsPagination }) => needsPagination ? 'flex-start' : 'center'}; - padding-top: ${({ theme }) => theme.spacing(3)}; + padding-top: ${themeCssVariables.spacing[3]}; overflow: hidden; width: 100%; align-items: center; @@ -75,9 +78,9 @@ const StyledLegendItem = styled.div<{ align-items: center; cursor: ${({ isInteractive }) => (isInteractive ? 'pointer' : 'default')}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + gap: ${themeCssVariables.spacing[1]}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; flex-shrink: ${({ canShrink }) => (canShrink ? 1 : 0)}; min-width: 0; `; @@ -86,8 +89,9 @@ const StyledLegendLabel = styled.div<{ fixedWidth?: boolean; isHidden?: boolean; }>` - color: ${({ theme }) => theme.font.color.secondary}; - ${({ fixedWidth }) => fixedWidth && `width: ${LEGEND_LABEL_MAX_WIDTH}px;`} + color: ${themeCssVariables.font.color.secondary}; + width: ${({ fixedWidth }) => + fixedWidth ? `${LEGEND_LABEL_MAX_WIDTH}px` : 'auto'}; overflow: hidden; text-decoration: ${({ isHidden }) => (isHidden ? 'line-through' : 'none')}; opacity: ${({ isHidden }) => @@ -98,7 +102,8 @@ const StyledLegendLabel = styled.div<{ } `; -const StyledLegendDot = styled(GraphWidgetLegendDot)<{ isHidden?: boolean }>` +const StyledLegendDotWrapper = styled.div<{ isHidden?: boolean }>` + display: flex; opacity: ${({ isHidden }) => isHidden ? LEGEND_HIGHLIGHT_DIMMED_OPACITY : 1}; `; @@ -108,12 +113,12 @@ const StyledPaginationContainer = styled.div` display: flex; flex-direction: row; flex-shrink: 0; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; const StyledPaginationIndicator = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; `; const legendEnterExitVariants = { @@ -144,7 +149,7 @@ export const GraphWidgetLegend = ({ const [animationDirection, setAnimationDirection] = useState('forward'); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const isPageLayoutInEditMode = useAtomComponentStateValue( isPageLayoutInEditModeComponentState, @@ -314,10 +319,9 @@ export const GraphWidgetLegend = ({ onMouseEnter={() => handleLegendItemMouseEnter(item.id)} onMouseLeave={handleLegendItemMouseLeave} > - + + + theme.background.primary}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; + background: ${themeCssVariables.background.primary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; + box-shadow: ${themeCssVariables.boxShadow.strong}; display: flex; flex-direction: column; gap: 2px; @@ -25,47 +27,47 @@ const StyledTooltip = styled.div` const StyledTooltipContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[3]}; + padding: ${themeCssVariables.spacing[2]}; `; const StyledTooltipRow = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledTooltipRowContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; max-height: ${GRAPH_TOOLTIP_SCROLL_MAX_HEIGHT_PX}px; overflow-y: auto; `; const StyledTooltipLink = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; cursor: pointer; display: flex; justify-content: space-between; - height: ${({ theme }) => theme.spacing(6)}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding-inline: ${({ theme }) => theme.spacing(2)}; + height: ${themeCssVariables.spacing[6]}; + font-weight: ${themeCssVariables.font.weight.regular}; + padding-inline: ${themeCssVariables.spacing[2]}; line-height: 140%; `; const StyledTooltipSeparator = styled.div` - background-color: ${({ theme }) => theme.border.color.light}; + background-color: ${themeCssVariables.border.color.light}; min-height: 1px; width: 100%; `; const StyledTooltipHeader = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.medium}; line-height: 140%; overflow: hidden; text-overflow: ellipsis; @@ -76,37 +78,45 @@ const StyledTooltipRowRightContent = styled.div` align-items: center; display: flex; justify-content: space-between; - font-size: ${({ theme }) => theme.font.size.xs}; - color: ${({ theme }) => theme.font.color.extraLight}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - gap: ${({ theme }) => theme.spacing(2)}; + font-size: ${themeCssVariables.font.size.xs}; + color: ${themeCssVariables.font.color.extraLight}; + font-weight: ${themeCssVariables.font.weight.regular}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; width: 100%; `; const StyledTooltipLabel = styled.span<{ isHighlighted?: boolean }>` - color: ${({ theme, isHighlighted }) => - isHighlighted ? theme.font.color.secondary : theme.font.color.tertiary}; + color: ${({ isHighlighted }) => + isHighlighted + ? themeCssVariables.font.color.secondary + : themeCssVariables.font.color.tertiary}; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-weight: ${({ theme, isHighlighted }) => - isHighlighted ? theme.font.weight.medium : theme.font.weight.regular}; + font-weight: ${({ isHighlighted }) => + isHighlighted + ? themeCssVariables.font.weight.medium + : themeCssVariables.font.weight.regular}; `; const StyledNoDataMessage = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.xs}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.xs}; `; const StyledTooltipValue = styled.span<{ isHighlighted?: boolean }>` - color: ${({ theme, isHighlighted }) => - isHighlighted ? theme.font.color.tertiary : theme.font.color.extraLight}; + color: ${({ isHighlighted }) => + isHighlighted + ? themeCssVariables.font.color.tertiary + : themeCssVariables.font.color.extraLight}; flex-shrink: 0; - font-weight: ${({ theme, isHighlighted }) => - isHighlighted ? theme.font.weight.semiBold : theme.font.weight.medium}; + font-weight: ${({ isHighlighted }) => + isHighlighted + ? themeCssVariables.font.weight.semiBold + : themeCssVariables.font.weight.medium}; white-space: nowrap; `; @@ -114,10 +124,10 @@ const StyledHorizontalSectionPadding = styled.div<{ addTop?: boolean; addBottom?: boolean; }>` - padding-inline: ${({ theme }) => theme.spacing(1)}; - margin-top: ${({ addTop, theme }) => (addTop ? theme.spacing(1) : 0)}; - margin-bottom: ${({ addBottom, theme }) => - addBottom ? theme.spacing(1) : 0}; + padding-inline: ${themeCssVariables.spacing[1]}; + margin-top: ${({ addTop }) => (addTop ? themeCssVariables.spacing[1] : 0)}; + margin-bottom: ${({ addBottom }) => + addBottom ? themeCssVariables.spacing[1] : 0}; `; export type GraphWidgetTooltipItem = { @@ -141,7 +151,7 @@ export const GraphWidgetTooltip = ({ highlightedKey, onGraphWidgetTooltipClick, }: GraphWidgetTooltipProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const filteredItems = items.filter( (item) => item.value !== 0 && isNonEmptyString(item.formattedValue), diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/NoDataLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/NoDataLayer.tsx index 0148028c19e..500b260a0e0 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/components/NoDataLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/components/NoDataLayer.tsx @@ -1,5 +1,6 @@ -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; import { useLingui } from '@lingui/react/macro'; +import { ThemeContext } from 'twenty-ui/theme'; type NoDataLayerProps = { innerWidth: number; @@ -12,7 +13,7 @@ export const NoDataLayer = ({ innerHeight, hasNoData, }: NoDataLayerProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); if (!hasNoData) { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx index cd0b86a7ccd..bdd2a958f62 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetAggregateChart/components/GraphWidgetAggregateChart.tsx @@ -1,6 +1,5 @@ import { formatNumberChartTrend } from '@/page-layout/widgets/graph/graphWidgetAggregateChart/utils/formatNumberChartTrend'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { H1Title, @@ -8,6 +7,9 @@ import { IconTrendingDown, IconTrendingUp, } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type GraphWidgetAggregateChartProps = { value: string | number; @@ -17,10 +19,10 @@ type GraphWidgetAggregateChartProps = { }; const StyledTrendPercentageValue = styled.span` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - margin-right: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.regular}; + margin-right: ${themeCssVariables.spacing[2]}; `; const StyledContainer = styled.div` @@ -38,7 +40,7 @@ const StyledTrendIconContainer = styled.div` `; const StyledH1Title = styled(H1Title)` - font-size: ${({ theme }) => theme.font.size.xxl}; + font-size: ${themeCssVariables.font.size.xxl}; margin: 0; `; @@ -48,7 +50,7 @@ export const GraphWidgetAggregateChart = ({ prefix, suffix, }: GraphWidgetAggregateChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const formattedPercentage = isDefined(trendPercentage) ? formatNumberChartTrend(trendPercentage) diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx index 86f987111c2..65ec5a5d908 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChart.tsx @@ -15,11 +15,11 @@ import { type GraphValueFormatOptions, } from '@/page-layout/widgets/graph/utils/graphFormatters'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { type MouseEvent } from 'react'; +import { styled } from '@linaria/react'; +import { type MouseEvent, useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { BarChartLayout } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; type BarChartProps = { data: BarChartDatum[]; @@ -76,7 +76,7 @@ export const BarChart = ({ allowDataTransitions, hasNoData = false, }: BarChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const graphWidgetHighlightedLegendId = useAtomComponentStateValue( graphWidgetHighlightedLegendIdComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayer.tsx index 3ddec628990..5b4415a8ae7 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayer.tsx @@ -1,7 +1,7 @@ import { BarChartBaseLayerEffect } from '@/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayerEffect'; import { type BarPosition } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarPosition'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useRef } from 'react'; import { type BarChartLayout } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayerEffect.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayerEffect.tsx index 9f204ef9305..a11111e0d82 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayerEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartBaseLayerEffect.tsx @@ -7,9 +7,15 @@ import { computeBaselineBar } from '@/page-layout/widgets/graph/graphWidgetBarCh import { interpolateBars } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/interpolateBars'; import { renderBars } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/renderBars'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; -import { useTheme } from '@emotion/react'; -import { useCallback, useEffect, useState, type RefObject } from 'react'; +import { + type RefObject, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; import { BarChartLayout } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; type BarChartBaseLayerEffectProps = { bars: BarPosition[]; @@ -45,7 +51,7 @@ export const BarChartBaseLayerEffect = ({ allowDataTransitions, canvasRef, }: BarChartBaseLayerEffectProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const borderRadius = parseInt(theme.border.radius.sm); const gridColor = theme.border.color.light; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayer.tsx index 8af38591602..f085387d6c1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayer.tsx @@ -1,7 +1,7 @@ import { BarChartHoverLayerEffect } from '@/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayerEffect'; import { type BarChartSlice } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartSlice'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useRef } from 'react'; import { type BarChartLayout } from '~/generated-metadata/graphql'; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayerEffect.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayerEffect.tsx index cacf9097858..ef84d04802d 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayerEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartHoverLayerEffect.tsx @@ -2,9 +2,9 @@ import { CHART_CORE_CONSTANTS } from '@/page-layout/widgets/graph/chart-core/con import { type BarChartSlice } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartSlice'; import { renderSliceHighlight } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/renderSliceHighlight'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; -import { useTheme } from '@emotion/react'; -import { useEffect, useState, type RefObject } from 'react'; +import { type RefObject, useContext, useEffect, useState } from 'react'; import { BarChartLayout } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; type BarChartHoverLayerEffectProps = { hoveredSlice: BarChartSlice | null; @@ -23,7 +23,7 @@ export const BarChartHoverLayerEffect = ({ layout, canvasRef, }: BarChartHoverLayerEffectProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [dpr] = useState( () => (typeof window !== 'undefined' ? window.devicePixelRatio : undefined) || diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartLayers.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartLayers.tsx index fef5d30817e..d75b9534a4a 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartLayers.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartLayers.tsx @@ -7,7 +7,7 @@ import { BarChartTotalsLayer } from '@/page-layout/widgets/graph/graphWidgetBarC import { type BarChartSlice } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartSlice'; import { type BarPosition } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarPosition'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { BarChartLayout } from '~/generated-metadata/graphql'; const StyledNoDataOverlay = styled.svg` diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTotalsLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTotalsLayer.tsx index 0cf8a455198..c0a9673e549 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTotalsLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/BarChartTotalsLayer.tsx @@ -5,7 +5,7 @@ import { computeBarChartGroupedLabels } from '@/page-layout/widgets/graph/graphW import { computeBarChartStackedLabels } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/computeBarChartStackedLabels'; import { type ChartMargins } from '@/page-layout/widgets/graph/types/ChartMargins'; import { type GraphLabelData } from '@/page-layout/widgets/graph/types/GraphLabelData'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { BarChartLayout } from '~/generated-metadata/graphql'; type BarChartTotalsLayerProps = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx index b4dc7ab7280..f43fbb85d24 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/components/GraphWidgetBarChart.tsx @@ -22,12 +22,12 @@ import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDi import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useMemo, useRef, useState } from 'react'; +import { styled } from '@linaria/react'; +import { useContext, useMemo, useRef, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useDebouncedCallback } from 'use-debounce'; import { BarChartLayout } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; type GraphWidgetBarChartProps = { colorMode: GraphColorMode; @@ -84,7 +84,7 @@ export const GraphWidgetBarChart = ({ customFormatter, onSliceClick, }: GraphWidgetBarChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); const [chartWidth, setChartWidth] = useState(0); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts index bff6fbee287..24d4e28ce93 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetBarChart/hooks/useBarChartTheme.ts @@ -1,9 +1,10 @@ import { COMMON_CHART_CONSTANTS } from '@/page-layout/widgets/graph/constants/CommonChartConstants'; import { parseFontSizeToPx } from '@/page-layout/widgets/graph/utils/parseFontSizeToPx'; -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const useBarChartTheme = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const tickFontSize = COMMON_CHART_CONSTANTS.AXIS_FONT_SIZE; const legendFontSize = parseFontSizeToPx(theme.font.size.sm, tickFontSize); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetGaugeChart/components/GraphWidgetGaugeChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetGaugeChart/components/GraphWidgetGaugeChart.tsx index 66e755bd36b..4be42384767 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetGaugeChart/components/GraphWidgetGaugeChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetGaugeChart/components/GraphWidgetGaugeChart.tsx @@ -10,8 +10,7 @@ import { formatGraphValue, type GraphValueFormatOptions, } from '@/page-layout/widgets/graph/utils/graphFormatters'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { type RadialBarCustomLayerProps, @@ -19,6 +18,8 @@ import { } from '@nivo/radial-bar'; import { isDefined } from 'twenty-shared/utils'; import { H1Title, H1TitleFontColor } from 'twenty-ui/display'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type GraphWidgetGaugeChartProps = { data: GaugeChartData; @@ -43,12 +44,13 @@ const StyledChartContainer = styled.div<{ $isClickable?: boolean }>` width: 100%; ${({ $isClickable }) => - $isClickable && - ` + $isClickable + ? ` svg g path[fill^="url(#"] { cursor: pointer; } - `} + ` + : ''} `; const StyledH1Title = styled(H1Title)` @@ -69,7 +71,7 @@ export const GraphWidgetGaugeChart = ({ customFormatter, onGaugeClick, }: GraphWidgetGaugeChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); const formatOptions: GraphValueFormatOptions = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx index d9a44d17528..ca3cf1e04d9 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/CustomCrosshairLayer.tsx @@ -1,11 +1,11 @@ import { LINE_CHART_CONSTANTS } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartConstants'; import { graphWidgetLineCrosshairXComponentState } from '@/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineCrosshairXComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useTheme } from '@emotion/react'; import { type LineSeries, type Point } from '@nivo/line'; import { motion } from 'framer-motion'; -import { useCallback, useMemo, type MouseEvent } from 'react'; +import { type MouseEvent, useCallback, useContext, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { ThemeContext } from 'twenty-ui/theme'; export type SliceHoverData = { sliceX: number; @@ -40,7 +40,7 @@ export const CustomCrosshairLayer = ({ onSliceClick, onRectLeave, }: CustomCrosshairLayerProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const graphWidgetLineCrosshairX = useAtomComponentStateValue( graphWidgetLineCrosshairXComponentState, ); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx index 524050ca25c..61e760994f1 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/components/GraphWidgetLineChart.tsx @@ -26,8 +26,7 @@ import { } from '@/page-layout/widgets/graph/utils/graphFormatters'; import { NodeDimensionEffect } from '@/ui/utilities/dimensions/components/NodeDimensionEffect'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ResponsiveLine, type LineCustomSvgLayerProps, @@ -35,9 +34,10 @@ import { type Point, type SliceTooltipProps, } from '@nivo/line'; -import { useCallback, useRef, useState } from 'react'; +import { useCallback, useContext, useRef, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useDebouncedCallback } from 'use-debounce'; +import { ThemeContext } from 'twenty-ui/theme'; type CrosshairLayerProps = LineCustomSvgLayerProps; type PointLabelsLayerProps = LineCustomSvgLayerProps; @@ -92,7 +92,7 @@ export const GraphWidgetLineChart = ({ customFormatter, onSliceClick, }: GraphWidgetLineChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); const chartTheme = useLineChartTheme(); const containerRef = useRef(null); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts index 75b9fba5c9f..806715952d2 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetLineChart/hooks/useLineChartTheme.ts @@ -1,8 +1,9 @@ +import { useContext } from 'react'; import { parseFontSizeToPx } from '@/page-layout/widgets/graph/utils/parseFontSizeToPx'; -import { useTheme } from '@emotion/react'; +import { ThemeContext } from 'twenty-ui/theme'; export const useLineChartTheme = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const tickFontSize = 12; const legendFontSize = parseFontSizeToPx(theme.font.size.sm, tickFontSize); diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx index ef8d7c46129..709b6bf82ce 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/GraphWidgetPieChart.tsx @@ -14,24 +14,25 @@ import { type GraphColorMode } from '@/page-layout/widgets/graph/types/GraphColo import { createGraphColorRegistry } from '@/page-layout/widgets/graph/utils/createGraphColorRegistry'; import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ResponsivePie, type ComputedDatum, type PieCustomLayerProps, } from '@nivo/pie'; import { + type MouseEvent as ReactMouseEvent, useCallback, + useContext, useMemo, useRef, - type MouseEvent as ReactMouseEvent, } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type PieChartConfiguration, type PieChartDataItem, } from '~/generated-metadata/graphql'; +import { ThemeContext } from 'twenty-ui/theme'; type GraphWidgetPieChartProps = { data: PieChartDataItemWithColor[]; @@ -88,7 +89,7 @@ export const GraphWidgetPieChart = ({ showDataLabels = false, showCenterMetric = true, }: GraphWidgetPieChartProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const colorRegistry = createGraphColorRegistry(theme); const containerRef = useRef(null); const setGraphWidgetPieTooltip = useSetAtomComponentState( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/PieChartCenterMetricLayer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/PieChartCenterMetricLayer.tsx index cd82b0a5161..11886700c2b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/PieChartCenterMetricLayer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/graph/graphWidgetPieChart/components/PieChartCenterMetricLayer.tsx @@ -1,9 +1,11 @@ import { usePieChartCenterMetricData } from '@/page-layout/widgets/graph/graphWidgetPieChart/hooks/usePieChartCenterMetricData'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { AnimatePresence, motion } from 'framer-motion'; import { type PieChartConfiguration } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type PieChartCenterMetricProps = { objectMetadataItemId: string; @@ -12,7 +14,7 @@ type PieChartCenterMetricProps = { hasNoData?: boolean; }; -const StyledCenterMetricContainer = styled(motion.div)` +const StyledCenterMetricContainerBase = styled.div` align-items: center; display: flex; flex-direction: column; @@ -23,21 +25,24 @@ const StyledCenterMetricContainer = styled(motion.div)` top: 50%; transform: translate(-50%, -50%); `; +const StyledCenterMetricContainer = motion.create( + StyledCenterMetricContainerBase, +); const StyledValue = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; font-size: clamp(12px, 10cqmin, 48px); - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; font-size: clamp(10px, 5cqmin, 24px); `; const StyledNoDataText = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.md}; `; export const PieChartCenterMetric = ({ @@ -46,7 +51,7 @@ export const PieChartCenterMetric = ({ show, hasNoData = false, }: PieChartCenterMetricProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); const { centerMetricValue, centerMetricLabel } = usePieChartCenterMetricData({ diff --git a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx index b6e7664be92..fc1668cb563 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/iframe/components/IframeWidget.tsx @@ -3,14 +3,15 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetNoDataDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetNoDataDisplay'; import { WidgetSkeletonLoader } from '@/page-layout/widgets/components/WidgetSkeletonLoader'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ $isEditMode: boolean }>` box-sizing: border-box; - border-radius: ${({ theme }) => theme.border.radius.md}; - background: ${({ theme }) => theme.background.primary}; + border-radius: ${themeCssVariables.border.radius.md}; + background: ${themeCssVariables.background.primary}; display: flex; flex-direction: column; height: 100%; @@ -34,9 +35,9 @@ const StyledLoadingContainer = styled.div` left: 0; right: 0; bottom: 0; - padding-top: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(2)}; - background: ${({ theme }) => theme.background.primary}; + padding-top: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[2]}; + background: ${themeCssVariables.background.primary}; pointer-events: none; z-index: 1; `; @@ -47,7 +48,7 @@ const StyledErrorContainer = styled.div` align-items: center; justify-content: center; height: 100%; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; text-align: center; `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx index 7f5b1ed2475..d65478bef03 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx @@ -2,7 +2,7 @@ import { NotesCard } from '@/activities/notes/components/NotesCard'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorIcon.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorIcon.tsx index d2efe008f9b..6260eddd954 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorIcon.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorIcon.tsx @@ -1,17 +1,19 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type BlockNoteColor } from '@/page-layout/widgets/standalone-rich-text/types/BlockNoteColor'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledColorIcon = styled.div<{ textColorValue: string; backgroundColorValue: string; }>` background-color: ${({ backgroundColorValue }) => backgroundColorValue}; - border-radius: ${({ theme }) => theme.border.radius.xs}; + border-radius: ${themeCssVariables.border.radius.xs}; color: ${({ textColorValue }) => textColorValue}; font-size: 12px; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; height: 16px; line-height: 16px; pointer-events: none; @@ -28,7 +30,7 @@ export const DashboardColorIcon = ({ textColor, backgroundColor, }: DashboardColorIconProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const getThemeColorForTextColor = (color: BlockNoteColor): string => { if (color === 'default') { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorSelectionMenu.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorSelectionMenu.tsx index e6df21df1c6..b028dcd62da 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorSelectionMenu.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardColorSelectionMenu.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { IconCheck } from 'twenty-ui/display'; @@ -10,35 +10,37 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { useTheme } from '@emotion/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledColorMenuItem = styled.div` align-items: center; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; cursor: pointer; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - min-height: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + min-height: ${themeCssVariables.spacing[6]}; + padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } `; const StyledColorName = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; flex: 1; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; `; const StyledCheckIcon = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - height: ${({ theme }) => theme.spacing(4)}; + height: ${themeCssVariables.spacing[4]}; justify-content: center; - width: ${({ theme }) => theme.spacing(4)}; + width: ${themeCssVariables.spacing[4]}; `; type DashboardColorSelectionMenuProps = { @@ -55,7 +57,7 @@ export const DashboardColorSelectionMenu = ({ onBackgroundColorSelect, }: DashboardColorSelectionMenuProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardEditorSideMenu.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardEditorSideMenu.tsx index 617b4186a44..d82d9307fea 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardEditorSideMenu.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardEditorSideMenu.tsx @@ -9,20 +9,21 @@ import { useBlockNoteEditor, useComponentsContext, } from '@blocknote/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { IconColorSwatch, IconPlus, IconTrash } from 'twenty-ui/display'; import { isDefined } from 'twenty-shared/utils'; import { CustomSideMenuOptions } from '@/blocknote-editor/components/CustomSideMenuOptions'; import { type DASHBOARD_BLOCK_SCHEMA } from '@/page-layout/widgets/standalone-rich-text/constants/DashboardBlockSchema'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type DashboardEditorSideMenuProps = { editor: typeof DASHBOARD_BLOCK_SCHEMA.BlockNoteEditor; }; const StyledDivToCreateGap = styled.div` - width: ${({ theme }) => theme.spacing(2)}; + width: ${themeCssVariables.spacing[2]}; `; const DashboardAddBlockItem = ({ diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar.tsx index ede1566b593..34f4801f93e 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar.tsx @@ -12,7 +12,7 @@ import { flip, offset, shift } from '@floating-ui/react'; import { DashboardFormattingToolbarColorButton } from '@/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbarColorButton'; import { FORMATTING_TOOLBAR_FLOATING_CONFIG } from '@/page-layout/widgets/standalone-rich-text/constants/FormattingToolbarFloatingConfig'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledToolbarContainer = styled.div` & .bn-formatting-toolbar .mantine-Button-root { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbarColorButton.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbarColorButton.tsx index c2c9d81f97b..b29fa9a1997 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbarColorButton.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbarColorButton.tsx @@ -1,5 +1,5 @@ import { useActiveStyles, useBlockNoteEditor } from '@blocknote/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { autoUpdate, flip, @@ -18,21 +18,22 @@ import { extractColorFromProps } from '@/page-layout/widgets/standalone-rich-tex import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledColorButton = styled.button` align-items: center; background: transparent; border: none; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; cursor: pointer; display: flex; height: 24px; justify-content: center; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; width: 24px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } `; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardsBlockEditor.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardsBlockEditor.tsx index 47ef02e371a..d78ceaef067 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardsBlockEditor.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardsBlockEditor.tsx @@ -1,9 +1,8 @@ import { filterSuggestionItems } from '@blocknote/core/extensions'; import { BlockNoteView } from '@blocknote/mantine'; import { SuggestionMenuController } from '@blocknote/react'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { type ClipboardEvent } from 'react'; +import { styled } from '@linaria/react'; +import { type ClipboardEvent, useContext } from 'react'; import { CustomSlashMenu, @@ -13,6 +12,8 @@ import { DashboardEditorSideMenu } from '@/page-layout/widgets/standalone-rich-t import { DashboardFormattingToolbar } from '@/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar'; import { type DASHBOARD_BLOCK_SCHEMA } from '@/page-layout/widgets/standalone-rich-text/constants/DashboardBlockSchema'; import { getDashboardSlashMenu } from '@/page-layout/widgets/standalone-rich-text/utils/getDashboardSlashMenu'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; type DashboardsBlockEditorProps = { editor: typeof DASHBOARD_BLOCK_SCHEMA.BlockNoteEditor; @@ -34,11 +35,11 @@ const StyledEditor = styled.div` & .editor { background: transparent; font-size: 13px; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; user-select: text; } & .editor [class^='_inlineContent']:before { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; font-style: normal !important; } & .editor .bn-inline-content:has(> .ProseMirror-trailingBreak):before { @@ -61,8 +62,8 @@ const StyledEditor = styled.div` align-items: center; } & .bn-drag-handle-menu { - background: ${({ theme }) => theme.background.transparent.secondary}; - backdrop-filter: ${({ theme }) => theme.blur.medium}; + background: ${themeCssVariables.background.transparent.secondary}; + backdrop-filter: ${themeCssVariables.blur.medium}; box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.04), 2px 4px 16px rgba(0, 0, 0, 0.12); @@ -70,7 +71,7 @@ const StyledEditor = styled.div` min-height: 96px; padding: 4px; border-radius: 8px; - border: 1px solid ${({ theme }) => theme.border.color.medium}; + border: 1px solid ${themeCssVariables.border.color.medium}; } & .bn-editor { @@ -88,9 +89,9 @@ const StyledEditor = styled.div` & .bn-suggestion-menu { padding: 4px; border-radius: 8px; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - background: ${({ theme }) => theme.background.transparent.secondary}; - backdrop-filter: ${({ theme }) => theme.blur.medium}; + border: 1px solid ${themeCssVariables.border.color.medium}; + background: ${themeCssVariables.background.transparent.secondary}; + backdrop-filter: ${themeCssVariables.blur.medium}; } & .mantine-Menu-item { @@ -99,17 +100,17 @@ const StyledEditor = styled.div` min-height: 32px; font-style: normal; - font-family: ${({ theme }) => theme.font.family}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - color: ${({ theme }) => theme.font.color.secondary}; + font-family: ${themeCssVariables.font.family}; + font-weight: ${themeCssVariables.font.weight.regular}; + color: ${themeCssVariables.font.color.secondary}; } & .mantine-ActionIcon-root:hover { box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.08), 0px 2px 4px rgba(0, 0, 0, 0.04); - background: ${({ theme }) => theme.background.transparent.primary}; + background: ${themeCssVariables.background.transparent.primary}; backdrop-filter: blur(20px); - border: 1px solid ${({ theme }) => theme.border.color.light}; + border: 1px solid ${themeCssVariables.border.color.light}; } & .bn-side-menu .mantine-UnstyledButton-root:not(.mantine-Menu-item) svg { height: 16px; @@ -124,17 +125,17 @@ const StyledEditor = styled.div` } & .bn-inline-content a { - color: ${({ theme }) => theme.color.blue}; + color: ${themeCssVariables.color.blue}; } & .bn-inline-content code { font-family: monospace; - color: ${({ theme }) => theme.font.color.danger}; + color: ${themeCssVariables.font.color.danger}; padding: 2px 4px; border-radius: 4px; - border: 1px solid ${({ theme }) => theme.font.color.extraLight}; + border: 1px solid ${themeCssVariables.font.color.extraLight}; font-size: 0.9rem; - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } `; @@ -147,7 +148,7 @@ export const DashboardsBlockEditor = ({ readonly, boundaryElement, }: DashboardsBlockEditorProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const blockNoteTheme = theme.name === 'light' ? 'light' : 'dark'; const handleFocus = () => { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx index b9f727b09a2..cbaa282da50 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/StandaloneRichTextWidget.tsx @@ -12,13 +12,14 @@ import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingC import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { FeatureFlagKey, PageLayoutType, type StandaloneRichTextConfiguration, } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ isPageLayoutInEditMode?: boolean }>` box-sizing: border-box; @@ -27,8 +28,8 @@ const StyledContainer = styled.div<{ isPageLayoutInEditMode?: boolean }>` height: 100%; width: 100%; overflow: hidden; - padding-left: ${({ theme, isPageLayoutInEditMode }) => - isPageLayoutInEditMode ? theme.spacing(5) : 0}; + padding-left: ${({ isPageLayoutInEditMode }) => + isPageLayoutInEditMode ? themeCssVariables.spacing[5] : 0}; `; type StandaloneRichTextWidgetProps = { diff --git a/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx index 3996aee0131..c64fcecc99c 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx @@ -2,7 +2,7 @@ import { TasksCard } from '@/activities/tasks/components/TasksCard'; import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx b/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx index 0a413805b42..b9eb0190512 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx @@ -2,7 +2,7 @@ import { TimelineCard } from '@/activities/timeline-activities/components/Timeli import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` box-sizing: border-box; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx index 0e9728f6b42..ed7f516ac24 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx @@ -1,18 +1,35 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; -import { isDefined } from 'twenty-shared/utils'; +import { styled } from '@linaria/react'; import { type WidgetCardVariant } from '~/modules/page-layout/widgets/types/WidgetCardVariant'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { isDefined } from 'twenty-shared/utils'; -const StyledWidgetCard = styled.div<{ +type WidgetCardStyledProps = { variant: WidgetCardVariant; isEditable: boolean; - onClick?: () => void; isEditing: boolean; isDragging: boolean; isResizing: boolean; headerLess?: boolean; isLastWidget?: boolean; -}>` + hasClickHandler: boolean; +}; + +const computeBorderColor = ( + props: Pick< + WidgetCardStyledProps, + 'variant' | 'isEditable' | 'isEditing' | 'isDragging' + >, +): string => { + if (props.isEditable && (props.isEditing || props.isDragging)) { + return themeCssVariables.color.blue; + } + if (props.variant === 'dashboard') { + return themeCssVariables.border.color.light; + } + return 'transparent'; +}; + +const StyledWidgetCard = styled.div` box-sizing: border-box; display: flex; flex-direction: column; @@ -20,123 +37,130 @@ const StyledWidgetCard = styled.div<{ height: 100%; width: 100%; - ${({ - theme, - variant, - isEditable, - isEditing, - isDragging, - isResizing, - onClick, - headerLess, - isLastWidget, - }) => { - if (variant === 'dashboard' && !isEditable) { - return css` - background: ${theme.background.secondary}; - border: 1px solid ${theme.border.color.light}; - border-radius: ${theme.border.radius.md}; - padding: ${headerLess ? 0 : theme.spacing(2)}; - `; + background: ${(props) => { + if (props.isEditable && props.isDragging) { + return `linear-gradient(0deg, ${themeCssVariables.background.transparent.lighter} 0%, ${themeCssVariables.background.transparent.lighter} 100%), ${themeCssVariables.background.secondary}`; } - - if (variant === 'dashboard' && isEditable) { - return css` - background: ${theme.background.secondary}; - border: 1px solid ${theme.border.color.light}; - border-radius: ${theme.border.radius.md}; - padding: ${headerLess ? 0 : theme.spacing(2)}; - - ${!isDragging && - !isEditing && - !isResizing && - css` - &:hover { - border: 1px solid ${theme.border.color.strong}; - cursor: ${isDefined(onClick) ? 'pointer' : 'default'}; - } - `} - - ${isEditing && - !isDragging && - css` - border: 1px solid ${theme.color.blue} !important; - `} - - ${isDragging && - css` - background: linear-gradient( - 0deg, - ${theme.background.transparent.lighter} 0%, - ${theme.background.transparent.lighter} 100% - ), - ${theme.background.secondary}; - border: 1px solid ${theme.color.blue} !important; - `} - `; - } - - if (variant === 'side-column' && !isEditable) { - return css` - padding: ${theme.spacing(3)}; - - ${isLastWidget !== true && - css` - border-bottom: 1px solid ${theme.border.color.light}; - `} - `; - } - - if (variant === 'record-page' && !isEditable) { - return css` - background: ${theme.background.primary}; - border: 1px solid transparent; - border-radius: ${theme.border.radius.md}; - padding: ${theme.spacing(2)}; - `; - } - if ( - (variant === 'side-column' && isEditable) || - (variant === 'record-page' && isEditable) + props.variant === 'dashboard' || + (props.variant === 'side-column' && props.isEditable) ) { - return css` - background: ${variant === 'side-column' - ? theme.background.secondary - : theme.background.primary}; - border: 1px solid transparent; - border-radius: ${theme.border.radius.md}; - padding: ${theme.spacing(2)}; - - ${!isDragging && - !isEditing && - !isResizing && - css` - &:hover { - border: 1px solid ${theme.border.color.strong}; - cursor: ${isDefined(onClick) ? 'pointer' : 'default'}; - } - `} - - ${isEditing && - !isDragging && - css` - border: 1px solid ${theme.color.blue} !important; - `} - - ${isDragging && - css` - background: linear-gradient( - 0deg, - ${theme.background.transparent.lighter} 0%, - ${theme.background.transparent.lighter} 100% - ), - ${theme.background.secondary}; - border: 1px solid ${theme.color.blue} !important; - `} - `; + return themeCssVariables.background.secondary; } - }} + if (props.variant === 'record-page') { + return themeCssVariables.background.primary; + } + return 'none'; + }}; + + border-style: ${({ variant, isEditable }) => + variant === 'dashboard' || variant === 'record-page' || isEditable + ? 'solid' + : 'none'}; + + border-width: ${({ variant, isEditable }) => + variant === 'dashboard' || variant === 'record-page' || isEditable + ? '1px' + : '0'}; + + border-color: ${(props) => computeBorderColor(props)}; + + border-radius: ${({ variant, isEditable }) => + variant === 'dashboard' || variant === 'record-page' || isEditable + ? themeCssVariables.border.radius.md + : '0'}; + + padding: ${({ variant, isEditable, headerLess }) => { + if (variant === 'dashboard' && headerLess === true) return '0'; + if (variant === 'dashboard') return themeCssVariables.spacing[2]; + if (variant === 'side-column' && !isEditable) + return themeCssVariables.spacing[3]; + if (variant === 'record-page' || isEditable) + return themeCssVariables.spacing[2]; + return '0'; + }}; + + border-bottom: ${(props) => { + const { variant, isEditable, isLastWidget } = props; + if (variant === 'side-column' && !isEditable) { + return isLastWidget !== true + ? `1px solid ${themeCssVariables.border.color.light}` + : 'none'; + } + return `1px solid ${computeBorderColor(props)}`; + }}; + + cursor: ${({ + isEditable, + isDragging, + isEditing, + isResizing, + hasClickHandler, + }) => + isEditable && !isDragging && !isEditing && !isResizing && hasClickHandler + ? 'pointer' + : 'default'}; + + &:hover { + border-color: ${(props) => { + if ( + props.isEditable && + !props.isDragging && + !props.isEditing && + !props.isResizing + ) { + return themeCssVariables.border.color.strong; + } + return computeBorderColor(props); + }}; + } `; -export { StyledWidgetCard as WidgetCard }; +export type WidgetCardProps = { + variant: WidgetCardVariant; + isEditable: boolean; + isEditing: boolean; + isDragging: boolean; + isResizing: boolean; + headerLess?: boolean; + isLastWidget?: boolean; + onClick?: React.MouseEventHandler; + className?: string; + children?: React.ReactNode; + onMouseEnter?: React.MouseEventHandler; + onMouseLeave?: React.MouseEventHandler; +}; + +export const WidgetCard = ({ + variant, + isEditable, + isEditing, + isDragging, + isResizing, + headerLess, + isLastWidget, + onClick, + className, + children, + onMouseEnter, + onMouseLeave, +}: WidgetCardProps) => { + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx index bc43b962c76..e79cde2f31b 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx @@ -1,56 +1,75 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type WidgetCardVariant } from '~/modules/page-layout/widgets/types/WidgetCardVariant'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledWidgetCardContent = styled.div<{ +type WidgetCardContentStyledProps = { variant: WidgetCardVariant; hasHeader: boolean; isEditable: boolean; -}>` +}; + +const StyledWidgetCardContent = styled.div` box-sizing: border-box; display: grid; grid-template-columns: minmax(0, 1fr); height: 100%; overflow: hidden; - ${({ theme, variant, isEditable, hasHeader }) => { - if (!hasHeader) { - return; - } - - if (variant === 'side-column' && !isEditable) { - return css` - margin-top: ${theme.spacing(2)}; - - :empty { - margin-top: 0; - } - `; - } - - return css` - margin-top: ${theme.spacing(2)}; - `; - }} - - ${({ theme, variant, isEditable }) => { - if (variant === 'dashboard') { - return css` - padding: ${theme.spacing(2)}; - `; - } + margin-top: ${({ hasHeader }) => + hasHeader ? themeCssVariables.spacing[2] : '0'}; + padding: ${({ variant, isEditable }) => { + if (variant === 'dashboard') return themeCssVariables.spacing[2]; if ( variant === 'record-page' || (variant === 'side-column' && isEditable) ) { - return css` - border: 1px solid ${theme.border.color.medium}; - border-radius: ${theme.border.radius.md}; - padding: ${theme.spacing(2)}; - `; + return themeCssVariables.spacing[2]; } - }} + return '0'; + }}; + + border: ${({ variant, isEditable }) => + variant === 'record-page' || (variant === 'side-column' && isEditable) + ? `1px solid ${themeCssVariables.border.color.medium}` + : 'none'}; + + border-radius: ${({ variant, isEditable }) => + variant === 'record-page' || (variant === 'side-column' && isEditable) + ? themeCssVariables.border.radius.md + : '0'}; + + &:empty { + margin-top: ${({ hasHeader, variant, isEditable }) => { + if (hasHeader && variant === 'side-column' && !isEditable) return '0'; + return hasHeader ? themeCssVariables.spacing[2] : '0'; + }}; + } `; -export { StyledWidgetCardContent as WidgetCardContent }; +type WidgetCardContentProps = { + variant: WidgetCardVariant; + hasHeader: boolean; + isEditable: boolean; + className?: string; + children?: React.ReactNode; +}; + +export const WidgetCardContent = ({ + variant, + hasHeader, + isEditable, + className, + children, +}: WidgetCardContentProps) => { + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx index a2ebaea68c3..1a8f9606b88 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardHeader.tsx @@ -2,10 +2,9 @@ import { WidgetActionRenderer } from '@/page-layout/widgets/components/WidgetAct import { widgetCardHoveredComponentFamilyState } from '@/page-layout/widgets/states/widgetCardHoveredComponentFamilyState'; import { type WidgetAction } from '@/page-layout/widgets/types/WidgetAction'; import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; -import { type ReactNode } from 'react'; +import { type ReactNode, useContext } from 'react'; import { IconTrash, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; @@ -13,6 +12,8 @@ import { type WidgetCardVariant } from '@/page-layout/widgets/types/WidgetCardVa import { WidgetGrip } from '@/page-layout/widgets/widget-card/components/WidgetGrip'; import { AnimatePresence, motion } from 'framer-motion'; import { isDefined, isNonEmptyArray } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; export type WidgetCardHeaderProps = { variant: WidgetCardVariant; @@ -32,47 +33,40 @@ export type WidgetCardHeaderProps = { const StyledWidgetCardHeader = styled.div` align-items: center; display: flex; - height: ${({ theme }) => theme.spacing(6)}; + height: ${themeCssVariables.spacing[6]}; flex-shrink: 0; `; const StyledTitleContainer = styled.div<{ variant: WidgetCardVariant }>` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; flex: 1; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; user-select: none; overflow: hidden; - ${({ theme, variant }) => { - switch (variant) { - case 'side-column': - return undefined; - default: - return css` - padding-inline: ${theme.spacing(1)}; - `; - } - }} + padding-inline: ${({ variant }) => + variant === 'side-column' ? '0' : themeCssVariables.spacing[1]}; `; const StyledRightContainer = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; const StyledActionsContainer = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; -const StyledIconButtonContainer = styled(motion.div)` +const StyledIconButtonContainerBase = styled.div` display: flex; align-items: center; justify-content: center; `; +const StyledIconButtonContainer = motion.create(StyledIconButtonContainerBase); export const WidgetCardHeader = ({ widgetId, @@ -88,7 +82,7 @@ export const WidgetCardHeader = ({ actions, className, }: WidgetCardHeaderProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const widgetCardHovered = useAtomComponentFamilyStateValue( widgetCardHoveredComponentFamilyState, diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetGrip.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetGrip.tsx index b3a317c1227..ac3826f80a5 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetGrip.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetGrip.tsx @@ -1,9 +1,11 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; import { IconGripVertical } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; -const StyledGripContainer = styled(motion.div)` +const StyledGripContainerBase = styled.div` width: 20px; height: 20px; display: flex; @@ -11,18 +13,19 @@ const StyledGripContainer = styled(motion.div)` justify-content: center; cursor: grab; user-select: none; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; &:active { cursor: grabbing; - background: ${({ theme }) => theme.background.tertiary}; + background: ${themeCssVariables.background.tertiary}; } &:hover { - background: ${({ theme }) => theme.background.tertiary}; + background: ${themeCssVariables.background.tertiary}; } `; +const StyledGripContainer = motion.create(StyledGripContainerBase); type WidgetGripProps = { className?: string; @@ -30,7 +33,7 @@ type WidgetGripProps = { }; export const WidgetGrip = ({ className, onClick }: WidgetGripProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( {!isMobile && ( - - {}} - keyboard={[getOsControlSymbol(), 'K']} - /> - {}} - Icon={IconSettings} - /> - + + + {}} + keyboard={[getOsControlSymbol(), 'K']} + /> + {}} + Icon={IconSettings} + /> + + )} theme.background.overlayPrimary}; + background: ${themeCssVariables.background.overlayPrimary}; display: flex; height: 100dvh; justify-content: center; @@ -24,9 +25,10 @@ const StyledDialogOverlay = styled(motion.div)` width: 100vw; z-index: ${RootStackingContextZIndices.Dialog}; `; +const StyledDialogOverlay = motion.create(StyledDialogOverlayBase); -const StyledDialogContainer = styled(motion.div)` - background: ${({ theme }) => theme.background.primary}; +const StyledDialogContainerBase = styled.div` + background: ${themeCssVariables.background.primary}; border-radius: 8px; display: flex; flex-direction: column; @@ -35,26 +37,27 @@ const StyledDialogContainer = styled(motion.div)` position: relative; width: 100%; `; +const StyledDialogContainer = motion.create(StyledDialogContainerBase); const StyledDialogTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(6)}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[6]}; text-align: center; `; const StyledDialogMessage = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - margin-bottom: ${({ theme }) => theme.spacing(6)}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.regular}; + margin-bottom: ${themeCssVariables.spacing[6]}; text-align: center; `; const StyledDialogButton = styled(Button)` justify-content: center; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; export type DialogButtonOptions = Omit< diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx index 88c4e08fd7c..aff15425617 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx @@ -1,10 +1,14 @@ import { sanitizeMessageToRenderInSnackbar } from '@/ui/feedback/snack-bar-manager/utils/sanitizeMessageToRenderInSnackbar'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { isUndefined } from '@sniptt/guards'; -import { type ComponentPropsWithoutRef, type ReactNode, useMemo } from 'react'; +import { + type ComponentPropsWithoutRef, + type ReactNode, + useContext, + useMemo, +} from 'react'; import { Link } from 'react-router-dom'; import { isDefined } from 'twenty-shared/utils'; import { @@ -15,7 +19,8 @@ import { } from 'twenty-ui/display'; import { ProgressBar, useProgressAnimation } from 'twenty-ui/feedback'; import { LightButton, LightIconButton } from 'twenty-ui/input'; -import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export enum SnackBarVariant { Default = 'default', @@ -43,16 +48,16 @@ export type SnackBarProps = Pick, 'id'> & { }; const StyledContainer = styled.div` - backdrop-filter: ${({ theme }) => theme.blur.medium}; - background-color: ${({ theme }) => theme.background.transparent.primary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; + backdrop-filter: ${themeCssVariables.blur.medium}; + background-color: ${themeCssVariables.background.transparent.primary}; + border-radius: ${themeCssVariables.border.radius.md}; + box-shadow: ${themeCssVariables.boxShadow.strong}; box-sizing: border-box; cursor: pointer; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; position: relative; width: 296px; - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; @media (max-width: ${MOBILE_VIEWPORT}px) { border-radius: 0; @@ -72,16 +77,16 @@ const StyledProgressBar = styled(ProgressBar)` const StyledHeader = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledMessage = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.sm}; `; const StyledIcon = styled.div` @@ -96,9 +101,9 @@ const StyledActions = styled.div` `; const StyledDescription = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - padding-left: ${({ theme }) => theme.spacing(6)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + padding-left: ${themeCssVariables.spacing[6]}; overflow: hidden; text-overflow: ellipsis; width: 200px; @@ -106,20 +111,20 @@ const StyledDescription = styled.div` const StyledLink = styled(Link)` display: block; - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - padding-left: ${({ theme }) => theme.spacing(6)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + padding-left: ${themeCssVariables.spacing[6]}; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 200px; &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledActionButton = styled.div` - padding-left: ${({ theme }) => theme.spacing(6)}; + padding-left: ${themeCssVariables.spacing[6]}; `; const defaultAriaLabelByVariant: Record< @@ -149,7 +154,7 @@ export const SnackBar = ({ role = 'status', variant = SnackBarVariant.Default, }: SnackBarProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { i18n, t } = useLingui(); const { animation: progressAnimation, value: progressValue } = useProgressAnimation({ diff --git a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx index aacfb551320..2cd703ded11 100644 --- a/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/snack-bar-manager/components/SnackBarProvider.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AnimatePresence, motion } from 'framer-motion'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -9,13 +9,14 @@ import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingC import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; import { SnackBar } from './SnackBar'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSnackBarContainer = styled.div` - bottom: ${({ theme }) => theme.spacing(3)}; + bottom: ${themeCssVariables.spacing[3]}; display: flex; flex-direction: column; position: fixed; - right: ${({ theme }) => theme.spacing(3)}; + right: ${themeCssVariables.spacing[3]}; z-index: ${RootStackingContextZIndices.SnackBar}; @media (max-width: ${MOBILE_VIEWPORT}px) { diff --git a/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx index c95f31fad2a..019a1980a98 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/CurrencyDisplay.tsx @@ -1,5 +1,4 @@ -import { useTheme } from '@emotion/react'; -import { useId, useState } from 'react'; +import { useContext, useId, useState } from 'react'; import { createPortal } from 'react-dom'; import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/display'; @@ -14,6 +13,7 @@ import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay'; import { isDefined, formatToShortNumber } from 'twenty-shared/utils'; import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/formatNumber'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; +import { ThemeContext } from 'twenty-ui/theme'; type CurrencyDisplayProps = { currencyValue: FieldCurrencyValue | null | undefined; @@ -24,7 +24,7 @@ export const CurrencyDisplay = ({ currencyValue, fieldDefinition, }: CurrencyDisplayProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const instanceId = useId(); const [shouldRenderTooltip, setShouldRenderTooltip] = useState(false); diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index 412eef8ac31..6a31e9b95f4 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -2,16 +2,17 @@ import { type FieldDateMetadataSettings } from '@/object-record/record-field/ui/ import { TimeZoneAbbreviation } from '@/ui/input/components/internal/date/components/TimeZoneAbbreviation'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { UserContext } from '@/users/contexts/UserContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isNonEmptyString } from '@sniptt/guards'; import { useContext } from 'react'; import { Temporal } from 'temporal-polyfill'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { formatDateTimeString } from '~/utils/string/formatDateTimeString'; import { EllipsisDisplay } from './EllipsisDisplay'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledTimeZoneSpacer = styled.span` - min-width: ${({ theme }) => theme.spacing(1)}; + min-width: ${themeCssVariables.spacing[1]}; `; type DateTimeDisplayProps = { diff --git a/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx b/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx index aa220eed5df..3e110798fb3 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/FileChip.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { FileIcon } from '@/file/components/FileIcon'; import { type FieldFilesValue } from '@/object-record/record-field/ui/types/FieldMetadata'; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/GlobalFilePreviewModal.tsx b/packages/twenty-front/src/modules/ui/field/display/components/GlobalFilePreviewModal.tsx index ad958e15b72..3af748ffe4d 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/GlobalFilePreviewModal.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/GlobalFilePreviewModal.tsx @@ -4,13 +4,14 @@ import { Modal } from '@/ui/layout/modal/components/Modal'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { lazy, Suspense, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { isDefined } from 'twenty-shared/utils'; import { IconDownload, IconX } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const DocumentViewer = lazy(() => import('@/activities/files/components/DocumentViewer').then((module) => ({ @@ -22,14 +23,15 @@ const GLOBAL_FILE_PREVIEW_MODAL_ID = 'global-file-preview-modal'; const StyledModalHeader = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 60px; justify-content: space-between; overflow: hidden; - padding: ${({ theme }) => theme.spacing(0, 4, 0, 4)}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[4]} + ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[4]}; text-overflow: ellipsis; white-space: nowrap; `; @@ -37,26 +39,26 @@ const StyledModalHeader = styled.div` const StyledHeader = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; width: 100%; `; const StyledModalTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.xl}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.xl}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledButtonContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledModalContent = styled.div` height: 100%; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; `; const StyledLoadingContainer = styled.div` @@ -67,7 +69,7 @@ const StyledLoadingContainer = styled.div` `; const StyledLoadingText = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export const GlobalFilePreviewModal = (): JSX.Element | null => { diff --git a/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx b/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx index 5d796786b9a..04a039862f5 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/UploadFileChip.tsx @@ -1,24 +1,26 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconArrowUp } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledContainer = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background-color: ${themeCssVariables.background.transparent.light}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - height: ${({ theme }) => theme.spacing(5)}; - padding: 0 ${({ theme }) => theme.spacing(1)}; - margin-right: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; + height: ${themeCssVariables.spacing[5]}; + padding: 0 ${themeCssVariables.spacing[1]}; + margin-right: ${themeCssVariables.spacing[1]}; `; const StyledIconBox = styled.div` align-items: center; - background-color: ${({ theme }) => theme.font.color.tertiary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.background.primary}; + background-color: ${themeCssVariables.font.color.tertiary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.background.primary}; display: flex; height: 14px; justify-content: center; @@ -27,7 +29,7 @@ const StyledIconBox = styled.div` const StyledStaticLoader = styled.div` align-items: center; - border: 1px solid ${({ theme }) => theme.font.color.tertiary}; + border: 1px solid ${themeCssVariables.font.color.tertiary}; border-radius: 12px; box-sizing: border-box; display: flex; @@ -41,7 +43,7 @@ type UploadFileChipProps = { }; export const UploadFileChip = ({ isLoading = true }: UploadFileChipProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx index 0a0207972d8..f34b1559aae 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/AddressInput.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { PlaceAutocompleteSelect } from '@/geo-map/components/PlaceAutocompleteSelect'; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/BooleanInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/BooleanInput.tsx index 8da3b567257..28cbf8bd2dd 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/BooleanInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/BooleanInput.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useState } from 'react'; import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledEditableBooleanFieldContainer = styled.div<{ readonly?: boolean }>` align-items: center; @@ -11,8 +12,10 @@ const StyledEditableBooleanFieldContainer = styled.div<{ readonly?: boolean }>` height: 100%; width: 100%; - color: ${({ theme, readonly }) => - readonly ? theme.font.color.tertiary : theme.font.color.primary}; + color: ${({ readonly }) => + readonly + ? themeCssVariables.font.color.tertiary + : themeCssVariables.font.color.primary}; `; type BooleanInputProps = { diff --git a/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx index 00cbb6c5830..472b8c85048 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/CurrencyInput.tsx @@ -1,6 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useEffect, useRef, useState } from 'react'; +import { styled } from '@linaria/react'; +import { useContext, useEffect, useRef, useState } from 'react'; import { useRegisterInputEvents } from '@/object-record/record-field/ui/meta-types/input/hooks/useRegisterInputEvents'; import { CURRENCIES } from '@/settings/data-model/constants/Currencies'; @@ -8,13 +7,14 @@ import { CurrencyPickerDropdownButton } from '@/ui/input/components/internal/cur import { type Currency } from '@/ui/input/components/internal/types/Currency'; import { IMaskInput } from 'react-imask'; import { type IconComponent } from 'twenty-ui/display'; -import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; +import { TEXT_INPUT_STYLE, ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export const StyledIMaskInput = styled(IMaskInput)` margin: 0; ${TEXT_INPUT_STYLE} width: 100%; - padding: ${({ theme }) => `${theme.spacing(0)} ${theme.spacing(1.5)}`}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1.5]}; `; const StyledContainer = styled.div` @@ -29,10 +29,10 @@ const StyledIcon = styled.div` display: flex; & > svg { - padding-left: ${({ theme }) => theme.spacing(1)}; - color: ${({ theme }) => theme.font.color.tertiary}; - height: ${({ theme }) => theme.icon.size.md}px; - width: ${({ theme }) => theme.icon.size.md}px; + padding-left: ${themeCssVariables.spacing[1]}; + color: ${themeCssVariables.font.color.tertiary}; + height: ${themeCssVariables.icon.size.md}px; + width: ${themeCssVariables.icon.size.md}px; } `; @@ -67,7 +67,7 @@ export const CurrencyInput = ({ onSelect, decimals, }: CurrencyInputProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [internalText, setInternalText] = useState(value); diff --git a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx index 9319e321c3d..5c14a0c7aad 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/DoubleTextInput.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useRef, @@ -17,14 +17,15 @@ import { isDefined } from 'twenty-shared/utils'; import { splitFullName } from '~/utils/format/spiltFullName'; import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; import { StyledTextInput } from './TextInput'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; justify-content: space-between; & > input:last-child { - border-left: 1px solid ${({ theme }) => theme.border.color.strong}; - padding-left: ${({ theme }) => theme.spacing(2)}; + border-left: 1px solid ${themeCssVariables.border.color.strong}; + padding-left: ${themeCssVariables.spacing[2]}; } `; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/FieldInputContainer.tsx b/packages/twenty-front/src/modules/ui/field/input/components/FieldInputContainer.tsx index 9816b766a9f..2af947e54f6 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/FieldInputContainer.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/FieldInputContainer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; // eslint-disable-next-line twenty/styled-components-prefixed-with-styled export const FieldInputContainer = styled.div` diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx index 26accf9aa66..1a7b2a6d9a1 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/TextAreaInput.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useRef, useState, type ChangeEvent } from 'react'; import TextareaAutosize from 'react-textarea-autosize'; @@ -7,6 +7,7 @@ import { useRegisterInputEvents } from '@/object-record/record-field/ui/meta-typ import { isDefined } from 'twenty-shared/utils'; import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type TextAreaInputProps = { instanceId: string; @@ -32,7 +33,7 @@ const StyledTextArea = styled(TextareaAutosize)` justify-content: center; resize: none; max-height: 400px; - width: calc(100% - ${({ theme }) => theme.spacing(7)}); + width: calc(100% - ${themeCssVariables.spacing[7]}); line-height: 18px; `; diff --git a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx index 7132303987f..cebe1af1dd1 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/TextInput.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useRef, useState, type ChangeEvent } from 'react'; import { LightCopyIconButton } from '@/object-record/record-field/ui/components/LightCopyIconButton'; import { useRegisterInputEvents } from '@/object-record/record-field/ui/meta-types/input/hooks/useRegisterInputEvents'; import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export const StyledTextInput = styled.input` margin: 0; @@ -11,7 +12,7 @@ export const StyledTextInput = styled.input` width: 100%; &:disabled { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } `; diff --git a/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx b/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx index 8583630297b..fc7369e88b2 100644 --- a/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/IconPicker.tsx @@ -1,5 +1,6 @@ -import styled from '@emotion/styled'; -import { type ReactNode, useCallback, useMemo, useState } from 'react'; +import { css } from '@linaria/core'; +import { styled } from '@linaria/react'; +import React, { type ReactNode, useCallback, useMemo, useState } from 'react'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -31,6 +32,7 @@ import { type IconButtonVariant, LightIconButton, } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type IconPickerProps = { disabled?: boolean; @@ -53,20 +55,53 @@ const StyledMenuIconItemsContainer = styled.div` display: flex; flex-direction: row; flex-wrap: wrap; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; `; -const StyledLightIconButton = styled(LightIconButton)<{ +const selectedIconButtonStyle = css` + background: ${themeCssVariables.background.transparent.medium}; +`; + +const focusedIconButtonStyle = css` + background: ${themeCssVariables.background.transparent.light}; +`; + +type StyledLightIconButtonProps = React.ComponentProps< + typeof LightIconButton +> & { isSelected?: boolean; isFocused?: boolean; -}>` - background: ${({ theme, isSelected, isFocused }) => - isSelected - ? theme.background.transparent.medium - : isFocused - ? theme.background.transparent.light - : 'transparent'}; -`; +}; + +const StyledLightIconButton = ({ + isSelected, + isFocused, + className, + 'aria-label': ariaLabel, + size, + title, + Icon, + onClick, + testId, + active, + accent, + disabled, + focus, +}: StyledLightIconButtonProps) => ( + +); const StyledLoadingMore = styled.div` display: flex; diff --git a/packages/twenty-front/src/modules/ui/input/components/ImageInput.tsx b/packages/twenty-front/src/modules/ui/input/components/ImageInput.tsx index c8486c2ea65..bbfe072272c 100644 --- a/packages/twenty-front/src/modules/ui/input/components/ImageInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/ImageInput.tsx @@ -1,13 +1,14 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; -import React, { useState } from 'react'; +import React, { useContext, useState } from 'react'; import { getImageAbsoluteURI, isDefined } from 'twenty-shared/utils'; import { IconPhotoUp, IconTrash, IconUpload, IconX } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledContainer = styled.div` display: flex; @@ -16,11 +17,13 @@ const StyledContainer = styled.div` const StyledPicture = styled.button<{ withPicture: boolean }>` align-items: center; - background: ${({ theme, disabled }) => - disabled ? theme.background.secondary : theme.background.transparent.light}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.light}; + background: ${({ disabled }) => + disabled + ? themeCssVariables.background.secondary + : themeCssVariables.background.transparent.light}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.light}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; display: flex; height: 66px; @@ -38,17 +41,17 @@ const StyledPicture = styled.button<{ withPicture: boolean }>` } &:hover svg { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } - ${({ theme, withPicture, disabled }) => { + ${({ withPicture, disabled }) => { if ((withPicture || disabled) === true) { return ''; } return ` &:hover { - background: ${theme.background.transparent.medium}; + background: ${themeCssVariables.background.transparent.medium}; } `; }}; @@ -59,27 +62,27 @@ const StyledContent = styled.div` flex: 1; flex-direction: column; justify-content: start; - margin-left: ${({ theme }) => theme.spacing(4)}; + margin-left: ${themeCssVariables.spacing[4]}; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; const StyledButtonContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledText = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; `; const StyledErrorText = styled.span` - color: ${({ theme }) => theme.font.color.danger}; - font-size: ${({ theme }) => theme.font.size.xs}; - margin-top: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.danger}; + font-size: ${themeCssVariables.font.size.xs}; + margin-top: ${themeCssVariables.spacing[1]}; `; const StyledHiddenFileInput = styled.input` @@ -108,7 +111,7 @@ export const ImageInput = ({ className, }: ImageInputProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const hiddenFileInput = React.useRef(null); const onUploadButtonClick = () => { hiddenFileInput.current?.click(); diff --git a/packages/twenty-front/src/modules/ui/input/components/InputErrorHelper.tsx b/packages/twenty-front/src/modules/ui/input/components/InputErrorHelper.tsx index 85eddd811ba..0957907750c 100644 --- a/packages/twenty-front/src/modules/ui/input/components/InputErrorHelper.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/InputErrorHelper.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import React from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInputErrorHelper = styled.div` - color: ${({ theme }) => theme.color.red}; - font-size: ${({ theme }) => theme.font.size.xs}; + color: ${themeCssVariables.color.red}; + font-size: ${themeCssVariables.font.size.xs}; position: absolute; margin-top: 1px; `; diff --git a/packages/twenty-front/src/modules/ui/input/components/InputHint.tsx b/packages/twenty-front/src/modules/ui/input/components/InputHint.tsx index a910a5f4b5f..467bc891a46 100644 --- a/packages/twenty-front/src/modules/ui/input/components/InputHint.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/InputHint.tsx @@ -1,13 +1,16 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledInputHint = styled.div<{ danger?: boolean; }>` - color: ${({ danger, theme }) => - danger ? theme.font.color.danger : theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - margin-top: ${({ theme }) => theme.spacing(0.5)}; + color: ${({ danger }) => + danger + ? themeCssVariables.font.color.danger + : themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.regular}; + margin-top: ${themeCssVariables.spacing[0.5]}; `; export { StyledInputHint as InputHint }; diff --git a/packages/twenty-front/src/modules/ui/input/components/InputLabel.tsx b/packages/twenty-front/src/modules/ui/input/components/InputLabel.tsx index d4463301ff6..7df934a1f37 100644 --- a/packages/twenty-front/src/modules/ui/input/components/InputLabel.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/InputLabel.tsx @@ -1,14 +1,12 @@ -import styled from '@emotion/styled'; -import { type HTMLAttributes } from 'react'; -import { Label } from 'twenty-ui/display'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -type InputLabelProps = HTMLAttributes & { - htmlFor?: string; -}; - -const StyledInputLabel = styled(Label)` +const StyledLabel = styled.label` + color: ${themeCssVariables.font.color.light}; display: block; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-size: 11px; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; -export const InputLabel = StyledInputLabel; +export const InputLabel = StyledLabel; diff --git a/packages/twenty-front/src/modules/ui/input/components/MultiSelectControl.tsx b/packages/twenty-front/src/modules/ui/input/components/MultiSelectControl.tsx index 4c75faa35e3..ef49c3ed8da 100644 --- a/packages/twenty-front/src/modules/ui/input/components/MultiSelectControl.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/MultiSelectControl.tsx @@ -1,15 +1,27 @@ import { type SelectControlProps, StyledControlContainer, - StyledSelectControlIconChevronDown, } from '@/ui/input/components/SelectControl'; -import { useTheme } from '@emotion/react'; -import React from 'react'; +import { styled } from '@linaria/react'; +import React, { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { + IconChevronDown, type IconComponent, OverflowingTextWithTooltip, } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; + +const StyledIconChevronDownWrapper = styled.div<{ + disabled?: boolean; +}>` + color: ${({ disabled }) => + disabled + ? themeCssVariables.font.color.extraLight + : themeCssVariables.font.color.tertiary}; + display: flex; +`; type MultiSelectOptionType = { label: string; @@ -31,7 +43,7 @@ export const MultiSelectControl = ({ textAccent = 'default', hasRightElement, }: MultiSelectControlProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const firstSelectedOption = selectedOptions?.[0]; return ( @@ -61,10 +73,9 @@ export const MultiSelectControl = ({ )} - + + + ); }; diff --git a/packages/twenty-front/src/modules/ui/input/components/Select.tsx b/packages/twenty-front/src/modules/ui/input/components/Select.tsx index 9c6a86a0fcd..715da8a1b74 100644 --- a/packages/twenty-front/src/modules/ui/input/components/Select.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/Select.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type MouseEvent, useMemo, useRef, useState } from 'react'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; @@ -22,6 +22,7 @@ import { isDefined } from 'twenty-shared/utils'; import { type IconComponent } from 'twenty-ui/display'; import { type SelectOption } from 'twenty-ui/input'; import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type SelectSizeVariant = 'small' | 'default'; @@ -58,16 +59,16 @@ const StyledContainer = styled.div<{ fullWidth?: boolean }>` `; const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: block; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledDescription = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.sm}; `; export const Select = ({ diff --git a/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx b/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx index 2208921676f..3103e66ee6e 100644 --- a/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/SelectControl.tsx @@ -1,9 +1,11 @@ import { type SelectSizeVariant } from '@/ui/input/components/Select'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronDown, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { type SelectOption } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export type SelectControlTextAccent = 'default' | 'placeholder'; @@ -19,45 +21,46 @@ export const StyledControlContainer = styled.div<{ grid-template-columns: ${({ hasIcon }) => hasIcon ? 'auto 1fr auto' : '1fr auto'}; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; box-sizing: border-box; - height: ${({ selectSizeVariant, theme }) => - selectSizeVariant === 'small' ? theme.spacing(6) : theme.spacing(8)}; + height: ${({ selectSizeVariant }) => + selectSizeVariant === 'small' + ? themeCssVariables.spacing[6] + : themeCssVariables.spacing[8]}; max-width: 100%; - padding: 0 ${({ theme }) => theme.spacing(2)}; - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-top-left-radius: ${({ theme }) => theme.border.radius.sm}; - border-bottom-left-radius: ${({ theme }) => theme.border.radius.sm}; + padding: 0 ${themeCssVariables.spacing[2]}; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-top-left-radius: ${themeCssVariables.border.radius.sm}; + border-bottom-left-radius: ${themeCssVariables.border.radius.sm}; - ${({ hasRightElement, theme }) => - !hasRightElement - ? css` - border-right: auto; - border-bottom-right-radius: ${theme.border.radius.sm}; - border-top-right-radius: ${theme.border.radius.sm}; - ` - : css` - border-right: none; - border-bottom-right-radius: none; - border-top-right-radius: none; - `} + border-right: ${({ hasRightElement }) => + hasRightElement + ? 'none' + : `1px solid ${themeCssVariables.border.color.medium}`}; + border-bottom-right-radius: ${({ hasRightElement }) => + hasRightElement ? '0' : themeCssVariables.border.radius.sm}; + border-top-right-radius: ${({ hasRightElement }) => + hasRightElement ? '0' : themeCssVariables.border.radius.sm}; - color: ${({ disabled, theme, textAccent }) => + color: ${({ disabled, textAccent }) => disabled - ? theme.font.color.tertiary + ? themeCssVariables.font.color.tertiary : textAccent === 'default' - ? theme.font.color.primary - : theme.font.color.tertiary}; + ? themeCssVariables.font.color.primary + : themeCssVariables.font.color.tertiary}; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; text-align: left; `; -export const StyledSelectControlIconChevronDown = styled(IconChevronDown)<{ +const StyledIconChevronDownWrapper = styled.div<{ disabled?: boolean; }>` - color: ${({ disabled, theme }) => - disabled ? theme.font.color.extraLight : theme.font.color.tertiary}; + color: ${({ disabled }) => + disabled + ? themeCssVariables.font.color.extraLight + : themeCssVariables.font.color.tertiary}; + display: flex; `; export type SelectControlProps = { @@ -75,7 +78,7 @@ export const SelectControl = ({ textAccent = 'default', hasRightElement, }: SelectControlProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( ) : null} - + + + ); }; diff --git a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx index 83e9e5c2fc5..871a351b108 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type FocusEventHandler, useId } from 'react'; import TextareaAutosize from 'react-textarea-autosize'; @@ -6,6 +6,7 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const MAX_ROWS = 5; @@ -30,43 +31,41 @@ const StyledContainer = styled.div` `; const StyledLabel = styled.label` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: block; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledTextArea = styled(TextareaAutosize)` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; font-family: inherit; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; line-height: 16px; overflow: auto; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; resize: none; width: 100%; &:focus { outline: none; - ${({ theme }) => { - return `box-shadow: 0px 0px 0px 3px ${theme.color.transparent.blue2}; - border-color: ${theme.color.blue};`; - }}; + box-shadow: 0px 0px 0px 3px ${themeCssVariables.color.transparent.blue2}; + border-color: ${themeCssVariables.color.blue}; } &::placeholder { - color: ${({ theme }) => theme.font.color.light}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + color: ${themeCssVariables.font.color.light}; + font-weight: ${themeCssVariables.font.weight.regular}; } &:disabled { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } `; diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx index dbe65ed8277..6f8434865e7 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx @@ -1,12 +1,13 @@ import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper'; import { InputLabel } from '@/ui/input/components/InputLabel'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { +import { css } from '@linaria/core'; +import { styled } from '@linaria/react'; +import React, { + forwardRef, type ChangeEvent, type FocusEventHandler, type InputHTMLAttributes, - forwardRef, + useContext, useId, useRef, useState, @@ -15,6 +16,8 @@ import { type IconComponent, IconEye, IconEyeOff } from 'twenty-ui/display'; import { AutogrowWrapper } from 'twenty-ui/utilities'; import { useCombinedRefs } from '~/hooks/useCombinedRefs'; import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledContainer = styled.div>` box-sizing: border-box; @@ -39,17 +42,17 @@ type StyledAdornmentContainerProps = { const StyledAdornmentContainer = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.transparent.light}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme, position }) => + background-color: ${themeCssVariables.background.transparent.light}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${({ position }) => position === 'left' - ? `${theme.border.radius.sm} 0 0 ${theme.border.radius.sm}` - : `0 ${theme.border.radius.sm} ${theme.border.radius.sm} 0`}; + ? `${themeCssVariables.border.radius.sm} 0 0 ${themeCssVariables.border.radius.sm}` + : `0 ${themeCssVariables.border.radius.sm} ${themeCssVariables.border.radius.sm} 0`}; box-sizing: border-box; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; height: ${({ sizeVariant }) => sizeVariant === 'xs' ? '20px' @@ -60,7 +63,7 @@ const StyledAdornmentContainer = styled.div` : '32px'}; justify-content: center; min-width: fit-content; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; width: auto; line-height: ${({ sizeVariant }) => sizeVariant === 'xs' @@ -71,8 +74,10 @@ const StyledAdornmentContainer = styled.div` ? '28px' : '32px'}; - ${({ position }) => - position === 'left' ? 'border-right: none;' : 'border-left: none;'} + border-right-style: ${({ position }) => + position === 'left' ? 'none' : 'solid'}; + border-left-style: ${({ position }) => + position === 'right' ? 'none' : 'solid'}; `; const StyledInput = styled.input< @@ -89,27 +94,29 @@ const StyledInput = styled.input< | 'leftAdornment' > >` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border-radius: ${({ theme, leftAdornment, rightAdornment }) => + background-color: ${themeCssVariables.background.transparent.lighter}; + border-radius: ${({ leftAdornment, rightAdornment }) => leftAdornment - ? `0 ${theme.border.radius.sm} ${theme.border.radius.sm} 0` + ? `0 ${themeCssVariables.border.radius.sm} ${themeCssVariables.border.radius.sm} 0` : rightAdornment - ? `${theme.border.radius.sm} 0 0 ${theme.border.radius.sm}` - : theme.border.radius.sm}; + ? `${themeCssVariables.border.radius.sm} 0 0 ${themeCssVariables.border.radius.sm}` + : themeCssVariables.border.radius.sm}; border: 1px solid - ${({ theme, error }) => - error ? theme.border.color.danger : theme.border.color.medium}; + ${({ error }) => + error + ? themeCssVariables.border.color.danger + : themeCssVariables.border.color.medium}; box-sizing: border-box; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-grow: 1; - font-family: ${({ theme, inheritFontStyles }) => - inheritFontStyles ? 'inherit' : theme.font.family}; - font-size: ${({ theme, inheritFontStyles }) => - inheritFontStyles ? 'inherit' : theme.font.size.md}; - font-weight: ${({ theme, inheritFontStyles }) => - inheritFontStyles ? 'inherit' : theme.font.weight.regular}; + font-family: ${({ inheritFontStyles }) => + inheritFontStyles ? 'inherit' : themeCssVariables.font.family}; + font-size: ${({ inheritFontStyles }) => + inheritFontStyles ? 'inherit' : themeCssVariables.font.size.md}; + font-weight: ${({ inheritFontStyles }) => + inheritFontStyles ? 'inherit' : themeCssVariables.font.weight.regular}; height: ${({ sizeVariant }) => sizeVariant === 'xs' ? '20px' @@ -119,37 +126,37 @@ const StyledInput = styled.input< ? '28px' : '32px'}; outline: none; - padding: ${({ theme, sizeVariant, autoGrow }) => + padding: ${({ sizeVariant, autoGrow }) => autoGrow ? 0 : sizeVariant === 'xs' - ? `${theme.spacing(2)} 0` - : theme.spacing(2)}; - padding-left: ${({ theme, LeftIcon, autoGrow }) => + ? `${themeCssVariables.spacing[2]} 0` + : themeCssVariables.spacing[2]}; + padding-left: ${({ LeftIcon, autoGrow }) => autoGrow - ? theme.spacing(1) + ? themeCssVariables.spacing[1] : LeftIcon - ? `calc(${theme.spacing(3)} + 16px)` - : theme.spacing(2)}; - padding-right: ${({ theme, RightIcon, autoGrow }) => + ? `calc(${themeCssVariables.spacing[3]} + 16px)` + : themeCssVariables.spacing[2]}; + padding-right: ${({ RightIcon, autoGrow }) => autoGrow - ? theme.spacing(1) + ? themeCssVariables.spacing[1] : RightIcon - ? `calc(${theme.spacing(3)} + 16px)` - : theme.spacing(2)}; - width: ${({ theme, width }) => - width ? `calc(${width}px + ${theme.spacing(0.5)})` : '100%'}; + ? `calc(${themeCssVariables.spacing[3]} + 16px)` + : themeCssVariables.spacing[2]}; + width: ${({ width }) => + width ? `calc(${width}px + ${themeCssVariables.spacing[0.5]})` : '100%'}; max-width: ${({ autoGrow }) => (autoGrow ? '100%' : 'none')}; text-overflow: ellipsis; &::placeholder, &::-webkit-input-placeholder { - color: ${({ theme }) => theme.font.color.light}; - font-family: ${({ theme }) => theme.font.family}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.light}; + font-family: ${themeCssVariables.font.family}; + font-weight: ${themeCssVariables.font.weight.medium}; } &:disabled { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } &[readonly] { @@ -157,9 +164,9 @@ const StyledInput = styled.input< } &:focus { - ${({ theme, error }) => { + ${({ error }) => { return ` - border-color: ${error ? theme.border.color.danger : theme.color.blue}; + border-color: ${error ? themeCssVariables.border.color.danger : themeCssVariables.color.blue}; `; }}; } @@ -169,12 +176,12 @@ const StyledLeftIconContainer = styled.div<{ sizeVariant: TextInputSize }>` align-items: center; display: flex; justify-content: center; - padding-left: ${({ theme, sizeVariant }) => + padding-left: ${({ sizeVariant }) => sizeVariant === 'xs' - ? theme.spacing(0.5) + ? themeCssVariables.spacing[0.5] : sizeVariant === 'md' || sizeVariant === 'sm' - ? theme.spacing(1) - : theme.spacing(2)}; + ? themeCssVariables.spacing[1] + : themeCssVariables.spacing[2]}; position: absolute; top: 0; bottom: 0; @@ -187,7 +194,7 @@ const StyledTrailingIconContainer = styled.div< align-items: center; display: flex; justify-content: center; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; position: absolute; top: 0; bottom: 0; @@ -200,8 +207,10 @@ const StyledTrailingIcon = styled.div<{ onClick?: () => void; }>` align-items: center; - color: ${({ theme, isFocused }) => - isFocused ? theme.font.color.secondary : theme.font.color.light}; + color: ${({ isFocused }) => + isFocused + ? themeCssVariables.font.color.secondary + : themeCssVariables.font.color.light}; cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')}; display: flex; justify-content: center; @@ -276,7 +285,7 @@ const TextInputComponent = forwardRef< }, ref, ) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const inputRef = useRef(null); const combinedRef = useCombinedRefs(ref, inputRef); @@ -397,21 +406,50 @@ const TextInputComponent = forwardRef< }, ); -const StyledAutogrowWrapper = styled(AutogrowWrapper)<{ - sizeVariant?: TextInputSize; -}>` +const autogrowBaseStyle = css` box-sizing: border-box; - height: ${({ sizeVariant }) => - sizeVariant === 'xs' - ? '20px' - : sizeVariant === 'sm' - ? '24px' - : sizeVariant === 'md' - ? '28px' - : '32px'}; padding: 0 5px; `; +const autogrowHeightXs = css` + height: 20px; +`; +const autogrowHeightSm = css` + height: 24px; +`; +const autogrowHeightMd = css` + height: 28px; +`; +const autogrowHeightLg = css` + height: 32px; +`; + +const AUTOGROW_HEIGHT_MAP: Record = { + xs: autogrowHeightXs, + sm: autogrowHeightSm, + md: autogrowHeightMd, + lg: autogrowHeightLg, +}; + +type StyledAutogrowWrapperProps = React.ComponentProps< + typeof AutogrowWrapper +> & { + sizeVariant?: TextInputSize; +}; + +const StyledAutogrowWrapper = ({ + sizeVariant = 'lg', + className, + children, + node, +}: StyledAutogrowWrapperProps) => ( + +); + const TextInputWithAutoGrowWrapper = forwardRef< HTMLInputElement, TextInputWithAutoGrowWrapperProps diff --git a/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx index d802d94a025..e77803fb01e 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx @@ -7,8 +7,9 @@ import { TitleInputAutoOpenEffect } from '@/ui/input/components/TitleInputAutoOp import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type InputProps = { instanceId: string; @@ -35,8 +36,8 @@ const StyledDiv = styled.div<{ }>` background: inherit; border: none; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.primary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.primary}; cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')}; overflow: hidden; height: ${({ sizeVariant }) => @@ -47,13 +48,13 @@ const StyledDiv = styled.div<{ : sizeVariant === 'md' ? '28px' : '32px'}; - padding: ${({ theme }) => theme.spacing(0, 1.25)}; + padding: ${themeCssVariables.spacing[0]} 5px; box-sizing: border-box; display: flex; align-items: center; :hover { - background: ${({ theme, disabled }) => - disabled ? 'inherit' : theme.background.transparent.light}; + background: ${({ disabled }) => + disabled ? 'inherit' : themeCssVariables.background.transparent.light}; } `; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx index dd3f608df12..390e8f981d1 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownButton.tsx @@ -1,5 +1,4 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { CurrencyCode } from 'twenty-shared/constants'; @@ -9,28 +8,31 @@ import { type Currency } from '@/ui/input/components/internal/types/Currency'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { IconChevronDown } from 'twenty-ui/display'; import { CurrencyPickerDropdownSelect } from './CurrencyPickerDropdownSelect'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; const StyledDropdownButtonContainer = styled.div` align-items: center; color: ${({ color }) => color ?? 'none'}; cursor: pointer; display: flex; - border-right: ${({ theme }) => `1px solid ${theme.border.color.medium}`}; + border-right: 1px solid ${themeCssVariables.border.color.medium}; height: 32px; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; user-select: none; &:hover { - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } `; const StyledIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + gap: ${themeCssVariables.spacing[1]}; + font-weight: ${themeCssVariables.font.weight.medium}; justify-content: center; svg { @@ -48,7 +50,7 @@ export const CurrencyPickerDropdownButton = ({ selectedCurrencyCode: string; onChange: (currency: Currency) => void; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const dropdownId = 'currency-picker-dropdown-id'; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePicker.tsx index a92f8171da0..827354024a1 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePicker.tsx @@ -1,5 +1,5 @@ -import styled from '@emotion/styled'; -import { lazy, Suspense, type ComponentType } from 'react'; +import { styled } from '@linaria/react'; +import { Suspense, lazy, type ComponentType, useContext } from 'react'; import type { ReactDatePickerProps as ReactDatePickerLibProps } from 'react-datepicker'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; @@ -12,7 +12,6 @@ import { DatePickerHeader } from '@/ui/input/components/internal/date/components import { RelativeDatePickerHeader } from '@/ui/input/components/internal/date/components/RelativeDatePickerHeader'; import { getHighlightedDates } from '@/ui/input/components/internal/date/utils/getHighlightedDates'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import 'react-datepicker/dist/react-datepicker.css'; @@ -26,10 +25,9 @@ import { type RelativeDateFilter, } from 'twenty-shared/utils'; import { IconCalendarX } from 'twenty-ui/display'; -import { - MenuItemLeftContent, - StyledHoverableMenuItemBase, -} from 'twenty-ui/navigation'; +import { MenuItemLeftContent } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; export const MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID = 'date-picker-month-and-year-dropdown-month-select'; @@ -42,13 +40,13 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` width: ${DATE_PICKER_CONTAINER_WIDTH}px; & .react-datepicker { - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; background: transparent; font-family: 'Inter'; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; border: none; display: block; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-weight: ${themeCssVariables.font.weight.regular}; } & .react-datepicker-popper { @@ -91,20 +89,20 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` & .react-datepicker__header__dropdown { display: flex; - color: ${({ theme }) => theme.font.color.primary}; - margin-left: ${({ theme }) => theme.spacing(1)}; - margin-bottom: ${({ theme }) => theme.spacing(10)}; + color: ${themeCssVariables.font.color.primary}; + margin-left: ${themeCssVariables.spacing[1]}; + margin-bottom: ${themeCssVariables.spacing[10]}; } & .react-datepicker__month-dropdown-container, & .react-datepicker__year-dropdown-container { text-align: left; - border-radius: ${({ theme }) => theme.border.radius.sm}; - margin-left: ${({ theme }) => theme.spacing(1)}; + border-radius: ${themeCssVariables.border.radius.sm}; + margin-left: ${themeCssVariables.spacing[1]}; margin-right: 0; - padding: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(4)}; - background-color: ${({ theme }) => theme.background.tertiary}; + padding: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[4]}; + background-color: ${themeCssVariables.background.tertiary}; } & .react-datepicker__month-read-view--down-arrow, @@ -112,14 +110,14 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` height: 5px; width: 5px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; top: 3px; right: -6px; } & .react-datepicker__year-read-view, & .react-datepicker__month-read-view { - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown-container { @@ -133,15 +131,15 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` & .react-datepicker__month-dropdown, & .react-datepicker__year-dropdown { overflow-y: scroll; - top: ${({ theme }) => theme.spacing(2)}; + top: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown { - left: ${({ theme }) => theme.spacing(2)}; + left: ${themeCssVariables.spacing[2]}; height: 260px; } & .react-datepicker__year-dropdown { - left: calc(${({ theme }) => theme.spacing(9)} + 80px); + left: calc(${themeCssVariables.spacing[9]} + 80px); width: 100px; height: 260px; } @@ -158,16 +156,16 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` & .react-datepicker__year-option, & .react-datepicker__month-option { text-align: left; - padding: ${({ theme }) => theme.spacing(2)} - calc(${({ theme }) => theme.spacing(2)} - 2px); - width: calc(100% - ${({ theme }) => theme.spacing(4)}); - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ theme }) => theme.font.color.secondary}; + padding: ${themeCssVariables.spacing[2]} + calc(${themeCssVariables.spacing[2]} - 2px); + width: calc(100% - ${themeCssVariables.spacing[4]}); + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; margin: 2px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } @@ -183,7 +181,7 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` } & .react-datepicker__day-name { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; width: 34px; height: 40px; line-height: 40px; @@ -212,10 +210,10 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` & .react-datepicker__navigation--previous, & .react-datepicker__navigation--next { height: 34px; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; padding-top: 6px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } & .react-datepicker__navigation--previous { @@ -241,7 +239,7 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` height: 7px; width: 7px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.font.color.tertiary}; + border-color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day--keyboard-selected { @@ -250,54 +248,65 @@ const StyledContainer = styled.div<{ calendarDisabled?: boolean }>` & .react-datepicker__day, .react-datepicker__time-name { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } & .react-datepicker__day--selected { - background-color: ${({ theme }) => theme.color.blue}; - color: ${({ theme }) => theme.background.primary}; + background-color: ${themeCssVariables.color.blue}; + color: ${themeCssVariables.background.primary}; &.react-datepicker__day:hover { - color: ${({ theme }) => theme.background.primary}; + color: ${themeCssVariables.background.primary}; } } & .react-datepicker__day--outside-month { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day:hover { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } & .clearable { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; } `; -const StyledButtonContainer = styled(StyledHoverableMenuItemBase)` +const StyledButtonContainer = styled.div` + align-items: center; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; + cursor: pointer; + display: flex; height: 32px; - margin: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)}; + margin: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]}; width: auto; + + &:hover { + background: ${themeCssVariables.background.transparent.light}; + } `; -const StyledButton = styled(MenuItemLeftContent)` +const StyledButtonContent = styled.div` + align-items: center; + display: flex; + gap: ${themeCssVariables.spacing[2]}; justify-content: start; `; const StyledDatePickerFallback = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - color: ${({ theme }) => theme.font.color.tertiary}; + background: ${themeCssVariables.background.secondary}; + border-radius: ${themeCssVariables.border.radius.md}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 300px; justify-content: center; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; width: 280px; `; @@ -352,7 +361,7 @@ export const DatePicker = ({ const { userTimezone } = useUserTimezone(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown(); const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown(); @@ -513,7 +522,9 @@ export const DatePicker = ({ {clearable && ( - + + + )} diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerHeader.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerHeader.tsx index 36f983fb4f7..59826c58582 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerHeader.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Select } from '@/ui/input/components/Select'; @@ -17,16 +17,17 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState import { Temporal } from 'temporal-polyfill'; import { SOURCE_LOCALE } from 'twenty-shared/translations'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCustomDatePickerHeader = styled.div` align-items: center; display: flex; justify-content: flex-end; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[2]}; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const years = Array.from( diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx index a53709c6767..6e025f566ea 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx @@ -1,5 +1,4 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useState } from 'react'; import { useIMask } from 'react-imask'; @@ -14,31 +13,30 @@ import { getDateMask } from '@/ui/input/components/internal/date/utils/getDateMa import { useParseDateInputStringToPlainDate } from '@/ui/input/components/internal/date/hooks/useParseDateInputStringToPlainDate'; import { useParseJSDateToIMaskDateInputString } from '@/ui/input/components/internal/date/hooks/useParseJSDateToIMaskDateInputString'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInputContainer = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - border-top-left-radius: ${({ theme }) => theme.border.radius.md}; - border-top-right-radius: ${({ theme }) => theme.border.radius.md}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; + border-top-left-radius: ${themeCssVariables.border.radius.md}; + border-top-right-radius: ${themeCssVariables.border.radius.md}; display: flex; - height: ${({ theme }) => theme.spacing(8)}; + height: ${themeCssVariables.spacing[8]}; width: 100%; `; const StyledInput = styled.input<{ hasError?: boolean }>` background: transparent; border: none; - color: ${({ theme }) => theme.font.color.primary}; outline: none; padding: 4px 8px 4px 8px; font-weight: 500; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; width: 100%; - ${({ hasError, theme }) => - hasError && - css` - color: ${theme.color.red}; - `}; + color: ${({ hasError }) => + hasError + ? themeCssVariables.color.red + : themeCssVariables.font.color.primary}; `; type DatePickerInputProps = { diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerWithoutCalendar.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerWithoutCalendar.tsx index de212d43ffa..a5dcffa248b 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerWithoutCalendar.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerWithoutCalendar.tsx @@ -1,5 +1,5 @@ -import styled from '@emotion/styled'; -import { lazy, Suspense, type ComponentType } from 'react'; +import { styled } from '@linaria/react'; +import { Suspense, lazy, type ComponentType, useContext } from 'react'; import type { ReactDatePickerProps as ReactDatePickerLibProps } from 'react-datepicker'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; @@ -10,13 +10,14 @@ import { CalendarStartDay } from 'twenty-shared/constants'; import { detectCalendarStartDay } from '@/localization/utils/detection/detectCalendarStartDay'; import { DatePickerHeader } from '@/ui/input/components/internal/date/components/DatePickerHeader'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useTheme } from '@emotion/react'; import 'react-datepicker/dist/react-datepicker.css'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { Temporal } from 'temporal-polyfill'; import { type Nullable } from 'twenty-shared/types'; import { isDefined, turnJSDateToPlainDate } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; export const MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID = 'date-picker-month-and-year-dropdown-month-select'; @@ -33,13 +34,13 @@ const StyledContainer = styled.div<{ width: ${DATE_PICKER_CONTAINER_WIDTH}px; & .react-datepicker { - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; background: transparent; font-family: 'Inter'; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; border: none; display: block; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-weight: ${themeCssVariables.font.weight.regular}; } & .react-datepicker-popper { @@ -82,20 +83,20 @@ const StyledContainer = styled.div<{ & .react-datepicker__header__dropdown { display: flex; - color: ${({ theme }) => theme.font.color.primary}; - margin-left: ${({ theme }) => theme.spacing(1)}; - margin-bottom: ${({ theme }) => theme.spacing(10)}; + color: ${themeCssVariables.font.color.primary}; + margin-left: ${themeCssVariables.spacing[1]}; + margin-bottom: ${themeCssVariables.spacing[10]}; } & .react-datepicker__month-dropdown-container, & .react-datepicker__year-dropdown-container { text-align: left; - border-radius: ${({ theme }) => theme.border.radius.sm}; - margin-left: ${({ theme }) => theme.spacing(1)}; + border-radius: ${themeCssVariables.border.radius.sm}; + margin-left: ${themeCssVariables.spacing[1]}; margin-right: 0; - padding: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(4)}; - background-color: ${({ theme }) => theme.background.tertiary}; + padding: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[4]}; + background-color: ${themeCssVariables.background.tertiary}; } & .react-datepicker__month-read-view--down-arrow, @@ -103,14 +104,14 @@ const StyledContainer = styled.div<{ height: 5px; width: 5px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; top: 3px; right: -6px; } & .react-datepicker__year-read-view, & .react-datepicker__month-read-view { - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown-container { @@ -124,15 +125,15 @@ const StyledContainer = styled.div<{ & .react-datepicker__month-dropdown, & .react-datepicker__year-dropdown { overflow-y: scroll; - top: ${({ theme }) => theme.spacing(2)}; + top: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown { - left: ${({ theme }) => theme.spacing(2)}; + left: ${themeCssVariables.spacing[2]}; height: 260px; } & .react-datepicker__year-dropdown { - left: calc(${({ theme }) => theme.spacing(9)} + 80px); + left: calc(${themeCssVariables.spacing[9]} + 80px); width: 100px; height: 260px; } @@ -149,16 +150,16 @@ const StyledContainer = styled.div<{ & .react-datepicker__year-option, & .react-datepicker__month-option { text-align: left; - padding: ${({ theme }) => theme.spacing(2)} - calc(${({ theme }) => theme.spacing(2)} - 2px); - width: calc(100% - ${({ theme }) => theme.spacing(4)}); - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ theme }) => theme.font.color.secondary}; + padding: ${themeCssVariables.spacing[2]} + calc(${themeCssVariables.spacing[2]} - 2px); + width: calc(100% - ${themeCssVariables.spacing[4]}); + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; margin: 2px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } @@ -174,7 +175,7 @@ const StyledContainer = styled.div<{ } & .react-datepicker__day-name { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; width: 34px; height: 40px; line-height: 40px; @@ -211,10 +212,10 @@ const StyledContainer = styled.div<{ & .react-datepicker__navigation--previous, & .react-datepicker__navigation--next { height: 34px; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; padding-top: 6px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } & .react-datepicker__navigation--previous { @@ -240,7 +241,7 @@ const StyledContainer = styled.div<{ height: 7px; width: 7px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.font.color.tertiary}; + border-color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day--keyboard-selected { @@ -249,47 +250,47 @@ const StyledContainer = styled.div<{ & .react-datepicker__day, .react-datepicker__time-name { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } & .react-datepicker__day--selected { - background-color: ${({ theme }) => theme.color.blue}; - color: ${({ theme }) => theme.background.primary}; + background-color: ${themeCssVariables.color.blue}; + color: ${themeCssVariables.background.primary}; &.react-datepicker__day:hover { - color: ${({ theme }) => theme.background.primary}; + color: ${themeCssVariables.background.primary}; } } & .react-datepicker__day--outside-month { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day:hover { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } & .clearable { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; } `; const StyledSpacer = styled.div` - height: ${({ theme }) => theme.spacing(2)}; + height: ${themeCssVariables.spacing[2]}; width: auto; `; const StyledDatePickerFallback = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - color: ${({ theme }) => theme.font.color.tertiary}; + background: ${themeCssVariables.background.secondary}; + border-radius: ${themeCssVariables.border.radius.md}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 300px; justify-content: center; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; width: 280px; `; @@ -324,7 +325,7 @@ export const DatePickerWithoutCalendar = ({ }: DatePickerWithoutCalendarProps) => { const plainDate = isDefined(date) ? Temporal.PlainDate.from(date) : null; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown(); const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown(); diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx index df4760b36df..975359160bf 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx @@ -9,25 +9,23 @@ import { DateTimePickerHeader } from '@/ui/input/components/internal/date/compon import { RelativeDatePickerHeader } from '@/ui/input/components/internal/date/components/RelativeDatePickerHeader'; import { getHighlightedDates } from '@/ui/input/components/internal/date/utils/getHighlightedDates'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; -import { lazy, Suspense, type ComponentType } from 'react'; +import { Suspense, lazy, type ComponentType, useContext } from 'react'; import type { ReactDatePickerProps as ReactDatePickerLibProps } from 'react-datepicker'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import 'react-datepicker/dist/react-datepicker.css'; import { IconCalendarX } from 'twenty-ui/display'; -import { - MenuItemLeftContent, - StyledHoverableMenuItemBase, -} from 'twenty-ui/navigation'; +import { MenuItemLeftContent } from 'twenty-ui/navigation'; import { useGetShiftedDateToSystemTimeZone } from '@/ui/input/components/internal/date/hooks/useGetShiftedDateToSystemTimeZone'; import { useUserFirstDayOfTheWeek } from '@/ui/input/components/internal/date/hooks/useUserFirstDayOfTheWeek'; import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; import { Temporal } from 'temporal-polyfill'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; export const MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID = 'date-picker-month-and-year-dropdown-month-select'; @@ -40,13 +38,13 @@ const StyledContainer = styled.div<{ width: 280px; & .react-datepicker { - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; background: transparent; font-family: 'Inter'; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; border: none; display: block; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-weight: ${themeCssVariables.font.weight.regular}; } & .react-datepicker-popper { @@ -89,20 +87,20 @@ const StyledContainer = styled.div<{ & .react-datepicker__header__dropdown { display: flex; - color: ${({ theme }) => theme.font.color.primary}; - margin-left: ${({ theme }) => theme.spacing(1)}; - margin-bottom: ${({ theme }) => theme.spacing(10)}; + color: ${themeCssVariables.font.color.primary}; + margin-left: ${themeCssVariables.spacing[1]}; + margin-bottom: ${themeCssVariables.spacing[10]}; } & .react-datepicker__month-dropdown-container, & .react-datepicker__year-dropdown-container { text-align: left; - border-radius: ${({ theme }) => theme.border.radius.sm}; - margin-left: ${({ theme }) => theme.spacing(1)}; + border-radius: ${themeCssVariables.border.radius.sm}; + margin-left: ${themeCssVariables.spacing[1]}; margin-right: 0; - padding: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(4)}; - background-color: ${({ theme }) => theme.background.tertiary}; + padding: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[4]}; + background-color: ${themeCssVariables.background.tertiary}; } & .react-datepicker__month-read-view--down-arrow, @@ -110,14 +108,14 @@ const StyledContainer = styled.div<{ height: 5px; width: 5px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; top: 3px; right: -6px; } & .react-datepicker__year-read-view, & .react-datepicker__month-read-view { - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown-container { @@ -131,15 +129,15 @@ const StyledContainer = styled.div<{ & .react-datepicker__month-dropdown, & .react-datepicker__year-dropdown { overflow-y: scroll; - top: ${({ theme }) => theme.spacing(2)}; + top: ${themeCssVariables.spacing[2]}; } & .react-datepicker__month-dropdown { - left: ${({ theme }) => theme.spacing(2)}; + left: ${themeCssVariables.spacing[2]}; height: 260px; } & .react-datepicker__year-dropdown { - left: calc(${({ theme }) => theme.spacing(9)} + 80px); + left: calc(${themeCssVariables.spacing[9]} + 80px); width: 100px; height: 260px; } @@ -156,16 +154,16 @@ const StyledContainer = styled.div<{ & .react-datepicker__year-option, & .react-datepicker__month-option { text-align: left; - padding: ${({ theme }) => theme.spacing(2)} - calc(${({ theme }) => theme.spacing(2)} - 2px); - width: calc(100% - ${({ theme }) => theme.spacing(4)}); - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ theme }) => theme.font.color.secondary}; + padding: ${themeCssVariables.spacing[2]} + calc(${themeCssVariables.spacing[2]} - 2px); + width: calc(100% - ${themeCssVariables.spacing[4]}); + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; margin: 2px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } @@ -181,7 +179,7 @@ const StyledContainer = styled.div<{ } & .react-datepicker__day-name { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; width: 34px; height: 40px; line-height: 40px; @@ -210,10 +208,10 @@ const StyledContainer = styled.div<{ & .react-datepicker__navigation--previous, & .react-datepicker__navigation--next { height: 34px; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; padding-top: 6px; &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } } & .react-datepicker__navigation--previous { @@ -239,7 +237,7 @@ const StyledContainer = styled.div<{ height: 7px; width: 7px; border-width: 1px 1px 0 0; - border-color: ${({ theme }) => theme.font.color.tertiary}; + border-color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day--keyboard-selected { @@ -248,55 +246,66 @@ const StyledContainer = styled.div<{ & .react-datepicker__day, .react-datepicker__time-name { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } & .react-datepicker__day--selected { - background-color: ${({ theme }) => theme.color.blue}; - color: ${({ theme }) => theme.background.primary}; + background-color: ${themeCssVariables.color.blue}; + color: ${themeCssVariables.background.primary}; &.react-datepicker__day:hover { - color: ${({ theme }) => theme.background.primary}; + color: ${themeCssVariables.background.primary}; } } & .react-datepicker__day--outside-month { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } & .react-datepicker__day:hover { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; } `; const StyledSeparator = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; width: 100%; `; -const StyledButtonContainer = styled(StyledHoverableMenuItemBase)` +const StyledButtonContainer = styled.div` + align-items: center; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; + cursor: pointer; + display: flex; height: 32px; - margin: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)}; + margin: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]}; width: auto; + + &:hover { + background: ${themeCssVariables.background.transparent.light}; + } `; -const StyledButton = styled(MenuItemLeftContent)` +const StyledButtonContent = styled.div` + align-items: center; + display: flex; + gap: ${themeCssVariables.spacing[2]}; justify-content: start; `; const StyledDatePickerFallback = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - color: ${({ theme }) => theme.font.color.tertiary}; + background: ${themeCssVariables.background.secondary}; + border-radius: ${themeCssVariables.border.radius.md}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 300px; justify-content: center; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; width: 280px; `; @@ -346,7 +355,7 @@ export const DateTimePicker = ({ hideHeaderInput, timeZone, }: DateTimePickerProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { userFirstDayOfTheWeek } = useUserFirstDayOfTheWeek(); @@ -538,7 +547,9 @@ export const DateTimePicker = ({ <> - + + + )} diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerHeader.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerHeader.tsx index 2286832bc93..95cc674ba4a 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerHeader.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; @@ -15,20 +15,21 @@ import { MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID, MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID, } from './DateTimePicker'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCustomDatePickerHeader = styled.div` align-items: center; display: flex; justify-content: flex-end; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[2]}; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledSeparator = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; height: 1px; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerInput.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerInput.tsx index 8ccf350fb86..af9d9564ef1 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePickerInput.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useIMask } from 'react-imask'; import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat'; @@ -18,25 +18,26 @@ import { useEffect, useState } from 'react'; import { Temporal } from 'temporal-polyfill'; import { isDefined } from 'twenty-shared/utils'; import { isDifferentZonedDateTime } from '~/utils/dates/isDifferentZonedDateTime'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInputContainer = styled.div` align-items: center; - border-top-left-radius: ${({ theme }) => theme.border.radius.md}; - border-top-right-radius: ${({ theme }) => theme.border.radius.md}; + border-top-left-radius: ${themeCssVariables.border.radius.md}; + border-top-right-radius: ${themeCssVariables.border.radius.md}; display: flex; - height: ${({ theme }) => theme.spacing(8)}; + height: ${themeCssVariables.spacing[8]}; width: 100%; `; const StyledInput = styled.input<{ hasError?: boolean }>` background: transparent; border: none; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; outline: none; - padding-left: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; font-weight: 500; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; width: 140px; `; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx index 354f6015c8d..2049d9a7679 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/RelativeDatePickerHeader.tsx @@ -5,7 +5,7 @@ import { RELATIVE_DATETIME_UNITS_SELECT_OPTIONS } from '@/ui/input/components/in import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useState } from 'react'; import { type Nullable } from 'twenty-shared/types'; import { @@ -14,12 +14,14 @@ import { type RelativeDateFilterDirection, type RelativeDateFilterUnit, } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ noPadding: boolean }>` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme, noPadding }) => (noPadding ? '0' : theme.spacing(2))}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${({ noPadding }) => + noPadding ? '0' : themeCssVariables.spacing[2]}; padding-bottom: 0; `; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/TimeZoneAbbreviation.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/TimeZoneAbbreviation.tsx index 93f759f42a7..79e9164fbd8 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/TimeZoneAbbreviation.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/TimeZoneAbbreviation.tsx @@ -1,14 +1,15 @@ import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone'; import { getTimezoneAbbreviationForZonedDateTime } from '@/ui/input/components/internal/date/utils/getTimeZoneAbbreviationForZonedDateTime'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isNonEmptyString } from '@sniptt/guards'; import { type Temporal } from 'temporal-polyfill'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledTimezoneAbbreviation = styled.span<{ hasError?: boolean }>` background: transparent; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; width: fit-content; user-select: none; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx index 22fc278932b..0113e501cd0 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton.tsx @@ -1,9 +1,8 @@ import { useCountries } from '@/ui/input/components/internal/hooks/useCountries'; import { type Country } from '@/ui/input/components/internal/types/Country'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useEffect, useState } from 'react'; +import { styled } from '@linaria/react'; +import { useContext, useEffect, useState } from 'react'; import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSelect'; @@ -14,6 +13,8 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import 'react-phone-number-input/style.css'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronDown, IconWorld } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; type StyledDropdownButtonProps = { isUnfolded: boolean; @@ -22,30 +23,30 @@ type StyledDropdownButtonProps = { const StyledDropdownButtonContainer = styled.div` align-items: center; background: none; - border-radius: ${({ theme }) => theme.border.radius.xs} 0 0 - ${({ theme }) => theme.border.radius.xs}; + border-radius: ${themeCssVariables.border.radius.xs} 0 0 + ${themeCssVariables.border.radius.xs}; color: ${({ color }) => color ?? 'none'}; cursor: pointer; display: flex; height: 32px; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(1)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[1]}; user-select: none; - border-right: 1px solid ${({ theme }) => theme.border.color.medium}; + border-right: 1px solid ${themeCssVariables.border.color.medium}; &:hover { - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } `; const StyledIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; justify-content: center; svg { @@ -74,7 +75,7 @@ export const PhoneCountryPickerDropdownButton = ({ value: string; onChange: (countryCode: string) => void; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [selectedCountry, setSelectedCountry] = useState(); diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx index a20fbc880ef..937de4f4b7d 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx @@ -1,5 +1,5 @@ import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useMemo, useState } from 'react'; import { type Country } from '@/ui/input/components/internal/types/Country'; @@ -10,16 +10,17 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import 'react-phone-number-input/style.css'; import { MenuItem, MenuItemSelectAvatar } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - padding-right: ${({ theme }) => theme.spacing(1)}; + padding-right: ${themeCssVariables.spacing[1]}; svg { align-items: center; - border-radius: ${({ theme }) => theme.border.radius.xs}; + border-radius: ${themeCssVariables.border.radius.xs}; display: flex; height: 12px; justify-content: center; diff --git a/packages/twenty-front/src/modules/ui/input/relation-picker/components/CreateNewButton.tsx b/packages/twenty-front/src/modules/ui/input/relation-picker/components/CreateNewButton.tsx index 4fe6b799d75..b53d0413fda 100644 --- a/packages/twenty-front/src/modules/ui/input/relation-picker/components/CreateNewButton.tsx +++ b/packages/twenty-front/src/modules/ui/input/relation-picker/components/CreateNewButton.tsx @@ -1,13 +1,63 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { css } from '@linaria/core'; +import React from 'react'; import { MenuItem } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledCreateNewButton = styled(MenuItem)<{ hovered?: boolean }>` - ${({ hovered, theme }) => - hovered && - css` - background: ${theme.background.transparent.light}; - `} +const hoveredStyle = css` + background: ${themeCssVariables.background.transparent.light}; `; -export const CreateNewButton = StyledCreateNewButton; +type CreateNewButtonProps = React.ComponentProps & { + hovered?: boolean; +}; + +export const CreateNewButton = ({ + hovered, + className, + accent, + withIconContainer, + iconButtons, + isIconDisplayedOnHoverOnly, + isTooltipOpen, + LeftIcon, + LeftComponent, + RightIcon, + RightComponent, + onClick, + onMouseEnter, + onMouseLeave, + testId, + disabled, + text, + contextualTextPosition, + contextualText, + hasSubMenu, + focused, + hotKeys, + isSubMenuOpened, +}: CreateNewButtonProps) => ( + +); diff --git a/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx b/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx index 91d567f71fd..0a20c86462e 100644 --- a/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx +++ b/packages/twenty-front/src/modules/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem.tsx @@ -1,15 +1,17 @@ import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; import { type CSSWidth } from '@/ui/types/CSSWidth'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledDropdownMenuSkeletonContainer = styled.div` - --horizontal-padding: ${({ theme }) => theme.spacing(1)}; - --vertical-padding: ${({ theme }) => theme.spacing(2)}; + --horizontal-padding: ${themeCssVariables.spacing[1]}; + --vertical-padding: ${themeCssVariables.spacing[2]}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - gap: ${({ theme }) => theme.spacing(2)}; + border-radius: ${themeCssVariables.border.radius.sm}; + gap: ${themeCssVariables.spacing[2]}; box-sizing: border-box; flex-shrink: 0; @@ -17,7 +19,7 @@ const StyledDropdownMenuSkeletonContainer = styled.div` padding-left: var(--horizontal-padding); padding-right: var(--horizontal-padding); - height: ${({ theme }) => theme.spacing(8)}; + height: ${themeCssVariables.spacing[8]}; `; export const DropdownMenuSkeletonItem = ({ @@ -25,7 +27,7 @@ export const DropdownMenuSkeletonItem = ({ }: { width?: CSSWidth; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')}; display: flex; - font-size: ${({ theme, onClick }) => - onClick ? theme.font.size.sm : theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - border-top-left-radius: ${({ theme }) => theme.border.radius.sm}; - border-top-right-radius: ${({ theme }) => theme.border.radius.sm}; - padding: ${({ theme }) => theme.spacing(1)}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + font-size: ${({ onClick }) => + onClick ? themeCssVariables.font.size.sm : themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; + border-top-left-radius: ${themeCssVariables.border.radius.sm}; + border-top-right-radius: ${themeCssVariables.border.radius.sm}; + padding: ${themeCssVariables.spacing[1]}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; - height: ${({ theme }) => theme.spacing(6)}; + height: ${themeCssVariables.spacing[6]}; user-select: none; &:hover { - background: ${({ theme, onClick }) => - onClick ? theme.background.transparent.light : 'none'}; + background: ${({ onClick }) => + onClick ? themeCssVariables.background.transparent.light : 'none'}; } flex-shrink: 0; @@ -28,20 +29,20 @@ const StyledHeader = styled.li` const StyledChildrenWrapper = styled.span` overflow: hidden; - padding: 0 ${({ theme }) => theme.spacing(1)}; + padding: 0 ${themeCssVariables.spacing[1]}; white-space: nowrap; text-overflow: ellipsis; `; const StyledEndComponent = styled.div` display: inline-flex; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; margin-left: auto; margin-right: 0; & > svg { - height: ${({ theme }) => theme.icon.size.md}px; - width: ${({ theme }) => theme.icon.size.md}px; + height: ${themeCssVariables.icon.size.md}px; + width: ${themeCssVariables.icon.size.md}px; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent.tsx index 24a825e15f8..cedd940ba43 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent.tsx @@ -1,12 +1,13 @@ -import { type MouseEvent, type ReactElement } from 'react'; -import styled from '@emotion/styled'; -import { useTheme } from '@emotion/react'; +import { type MouseEvent, type ReactElement, useContext } from 'react'; +import { styled } from '@linaria/react'; import { type Avatar, type AvatarProps, type IconComponent, } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledNonClickableStartIcon = styled.div` align-items: center; @@ -16,18 +17,18 @@ const StyledNonClickableStartIcon = styled.div` display: flex; flex-direction: row; - font-family: ${({ theme }) => theme.font.family}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - gap: ${({ theme }) => theme.spacing(1)}; + font-family: ${themeCssVariables.font.family}; + font-weight: ${themeCssVariables.font.weight.regular}; + gap: ${themeCssVariables.spacing[1]}; justify-content: center; white-space: nowrap; - height: ${({ theme }) => theme.spacing(6)}; - width: ${({ theme }) => theme.spacing(6)}; + height: ${themeCssVariables.spacing[6]}; + width: ${themeCssVariables.spacing[6]}; `; const StyledAvatarWrapper = styled.div` - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; `; export const DropdownMenuHeaderLeftComponent = ({ @@ -40,7 +41,7 @@ export const DropdownMenuHeaderLeftComponent = ({ } | Record )) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( <> diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx index a26e477ec96..374ed2805be 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx @@ -2,26 +2,28 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconChevronDown } from 'twenty-ui/display'; import { type SelectOption } from 'twenty-ui/input'; import { MenuItemSelect } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledDropdownMenuInnerSelectDropdownButton = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; display: flex; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - height: ${({ theme }) => theme.spacing(7)}; + font-weight: ${themeCssVariables.font.weight.medium}; + height: ${themeCssVariables.spacing[7]}; justify-content: space-between; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; width: 100%; box-sizing: border-box; @@ -43,7 +45,7 @@ export const DropdownMenuInnerSelect = ({ dropdownId, widthInPixels, }: DropdownMenuInnerSelectProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { closeDropdown } = useCloseDropdown(); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx index 4c97d883384..0303f62e4db 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInput.tsx @@ -1,5 +1,4 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { forwardRef, useRef, @@ -11,6 +10,7 @@ import 'react-phone-number-input/style.css'; import { useRegisterInputEvents } from '@/object-record/record-field/ui/meta-types/input/hooks/useRegisterInputEvents'; import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; import { useCombinedRefs } from '~/hooks/useCombinedRefs'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInput = styled.input<{ withRightComponent?: boolean; @@ -19,16 +19,13 @@ const StyledInput = styled.input<{ ${TEXT_INPUT_STYLE} box-sizing: border-box; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; height: 32px; position: relative; width: 100%; - ${({ withRightComponent }) => - withRightComponent && - css` - padding-right: 32px; - `} + padding-right: ${({ withRightComponent }) => + withRightComponent ? '32px' : '0'}; `; const StyledInputContainer = styled.div` @@ -38,20 +35,20 @@ const StyledInputContainer = styled.div` width: 100%; &:not(:first-of-type) { - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; } `; const StyledRightContainer = styled.div` position: absolute; - right: ${({ theme }) => theme.spacing(2)}; + right: ${themeCssVariables.spacing[2]}; top: 50%; transform: translateY(-50%); `; const StyledErrorDiv = styled.div` - color: ${({ theme }) => theme.color.red}; - padding: 0 ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.color.red}; + padding: 0 ${themeCssVariables.spacing[2]}; `; type HTMLInputProps = InputHTMLAttributes; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx index b53ff596dea..b4ca96132a7 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx @@ -1,10 +1,11 @@ import { DROPDOWN_MENU_ITEMS_CONTAINER_MAX_HEIGHT } from '@/ui/layout/dropdown/constants/DropdownMenuItemsContainerMaxHeight'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledExternalContainer = styled.div<{ maxHeight?: number; }>` - --padding: ${({ theme }) => theme.spacing(1)}; + --padding: ${themeCssVariables.spacing[1]}; align-items: flex-start; display: flex; @@ -28,11 +29,11 @@ const StyledScrollableContainer = styled.div<{ maxHeight?: number }>` width: 100%; overflow-y: auto; - scrollbar-color: ${({ theme }) => theme.border.color.medium} transparent; + scrollbar-color: ${themeCssVariables.border.color.medium} transparent; scrollbar-width: 4px; *::-webkit-scrollbar-thumb { - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSearchInput.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSearchInput.tsx index b6bed451391..ba51cb32ede 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSearchInput.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSearchInput.tsx @@ -1,13 +1,14 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { useInputFocusWithoutScrollOnMount } from '@/ui/input/hooks/useInputFocusWithoutScrollOnMount'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { forwardRef, type InputHTMLAttributes } from 'react'; import { TEXT_INPUT_STYLE } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledDropdownMenuSearchInputContainer = styled.div` align-items: center; - --vertical-padding: ${({ theme }) => theme.spacing(2)}; + --vertical-padding: ${themeCssVariables.spacing[2]}; display: flex; flex-direction: row; min-height: calc(36px - 2 * var(--vertical-padding)); @@ -19,7 +20,7 @@ const StyledDropdownMenuSearchInputContainer = styled.div` const StyledInput = styled.input` ${TEXT_INPUT_STYLE} - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; background-color: transparent; width: 100%; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx index 0075a5403b0..1ad4ccf5dee 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSectionLabel.tsx @@ -1,15 +1,16 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledDropdownMenuSectionLabel = styled.div` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - color: ${({ theme }) => theme.font.color.tertiary}; + background-color: ${themeCssVariables.background.transparent.lighter}; + color: ${themeCssVariables.font.color.tertiary}; min-height: 20px; width: auto; - font-size: ${({ theme }) => theme.font.size.xxs}; + font-size: ${themeCssVariables.font.size.xxs}; display: flex; align-items: center; justify-content: flex-start; - padding-left: ${({ theme }) => theme.spacing(1)}; + padding-left: ${themeCssVariables.spacing[1]}; user-select: none; `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx index 77fe462a93f..472cfd8a3b9 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuSeparator.tsx @@ -1,10 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledDropdownMenuSeparator = styled.div` - background-color: ${({ theme }) => - theme.name === 'dark' - ? theme.background.transparent.light - : theme.border.color.light}; + background-color: ${themeCssVariables.border.color.light}; min-height: 1px; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/OptionsDropdownMenu.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/OptionsDropdownMenu.tsx index 3819c62dafb..28b911bbef7 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/OptionsDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/OptionsDropdownMenu.tsx @@ -6,7 +6,6 @@ import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown' import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { type ReactNode, useId } from 'react'; import { Button } from 'twenty-ui/input'; @@ -30,7 +29,6 @@ export const OptionsDropdownMenu = ({ const generatedDropdownId = useId(); const dropdownId = dropdownIdFromProps ?? generatedDropdownId; const { t } = useLingui(); - const theme = useTheme(); const { toggleDropdown } = useToggleDropdown(); const listId = selectableListId ?? dropdownId; @@ -75,7 +73,7 @@ export const OptionsDropdownMenu = ({ /> } dropdownPlacement="top-end" - dropdownOffset={{ y: parseInt(theme.spacing(2), 10) }} + dropdownOffset={{ y: 8 }} globalHotkeysConfig={{ enableGlobalHotkeysWithModifiers: true, enableGlobalHotkeysConflictingWithKeyboard: false, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownButtonContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownButtonContainer.tsx index 5b4ec6a72d9..5962578ce60 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownButtonContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownButtonContainer.tsx @@ -1,4 +1,5 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; type StyledDropdownButtonProps = { isUnfolded: boolean; @@ -8,30 +9,32 @@ type StyledDropdownButtonProps = { export const StyledDropdownButtonContainer = styled.div` align-items: center; - background: ${({ theme, isUnfolded, transparentBackground }) => + background: ${({ isUnfolded, transparentBackground }) => transparentBackground ? 'none' : isUnfolded - ? theme.background.transparent.light - : theme.background.primary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ isActive, theme }) => - isActive ? theme.color.blue : theme.font.color.secondary}; + ? themeCssVariables.background.transparent.light + : themeCssVariables.background.primary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${({ isActive }) => + isActive + ? themeCssVariables.color.blue + : themeCssVariables.font.color.secondary}; cursor: pointer; display: flex; - padding: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[1]}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; user-select: none; &:hover { - background: ${({ theme, isUnfolded, transparentBackground }) => + background: ${({ isUnfolded, transparentBackground }) => transparentBackground ? 'transparent' : isUnfolded - ? theme.background.transparent.medium - : theme.background.transparent.light}; + ? themeCssVariables.background.transparent.medium + : themeCssVariables.background.transparent.light}; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownMenuSubheader.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownMenuSubheader.tsx index 4fff81c7598..2a43a262b50 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownMenuSubheader.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledDropdownMenuSubheader.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Label } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export const StyledDropdownMenuSubheader = styled(Label)` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - padding: ${({ theme }) => `${theme.spacing(1)} ${theme.spacing(2)}`}; + background-color: ${themeCssVariables.background.transparent.lighter}; + padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledHeaderDropdownButton.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledHeaderDropdownButton.tsx index 7ac30a349ea..71054c73d90 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledHeaderDropdownButton.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/StyledHeaderDropdownButton.tsx @@ -1,4 +1,5 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; type StyledDropdownButtonProps = { isUnfolded?: boolean; @@ -9,25 +10,29 @@ export const StyledHeaderDropdownButton = styled.button theme.border.radius.sm}; - color: ${({ isActive, theme }) => - isActive ? theme.color.blue : theme.font.color.secondary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${({ isActive }) => + isActive + ? themeCssVariables.color.blue + : themeCssVariables.font.color.secondary}; cursor: pointer; display: flex; - padding: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[2]}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; user-select: none; - background: ${({ theme, isUnfolded }) => - isUnfolded ? theme.background.transparent.light : theme.background.primary}; + background: ${({ isUnfolded }) => + isUnfolded + ? themeCssVariables.background.transparent.light + : themeCssVariables.background.primary}; &:hover { - background: ${({ theme, isUnfolded }) => + background: ${({ isUnfolded }) => isUnfolded - ? theme.background.transparent.medium - : theme.background.transparent.light}; + ? themeCssVariables.background.transparent.medium + : themeCssVariables.background.transparent.light}; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/Dropdown.stories.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/Dropdown.stories.tsx index cf6c23d693c..66fe9bb39bf 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/Dropdown.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/__stories__/Dropdown.stories.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type Decorator, type Meta, diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx index e1063f6b0fa..f5103c2c21b 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/internal/DropdownInternalContainer.tsx @@ -14,7 +14,7 @@ import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useLis import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { FloatingPortal, type Placement, diff --git a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx index 6939ac6f7da..dc4588d93ad 100644 --- a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandableList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactElement, useCallback, @@ -13,11 +13,12 @@ import { isDefined } from 'twenty-shared/utils'; import { ChipSize } from 'twenty-ui/components'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; import { AnimatedContainer } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: space-between; min-width: 100%; width: 100%; @@ -25,7 +26,7 @@ const StyledContainer = styled.div` const StyledChildrenContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow: hidden; max-width: 100%; flex: 0 1 fit-content; @@ -43,7 +44,7 @@ const StyledChildContainer = styled.div` `; const StyledUnShrinkableContainer = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; flex-shrink: 0; width: 24px; diff --git a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedFieldDisplay.tsx b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedFieldDisplay.tsx index d3f864c512d..d31a05d02c5 100644 --- a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedFieldDisplay.tsx @@ -1,9 +1,10 @@ import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices'; import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { flip, FloatingPortal, offset, useFloating } from '@floating-ui/react'; import { type ReactNode } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type ExpandedFieldDisplayProps = { anchorElement?: HTMLElement; @@ -14,8 +15,8 @@ type ExpandedFieldDisplayProps = { const StyledExpandedFieldContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[2]}; overflow: auto; box-sizing: border-box; height: 300px; diff --git a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedListDropdown.tsx b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedListDropdown.tsx index 495de7d9e0a..bc4c2e1beaa 100644 --- a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedListDropdown.tsx +++ b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/ExpandedListDropdown.tsx @@ -2,9 +2,10 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { StyledDropdownContentContainer } from '@/ui/layout/dropdown/components/internal/DropdownInternalContainer'; import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { FloatingPortal, offset, shift, useFloating } from '@floating-ui/react'; import { type ReactNode } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type ExpandedListDropdownProps = { anchorElement?: HTMLElement; @@ -15,8 +16,8 @@ type ExpandedListDropdownProps = { const StyledExpandedListContainer = styled.div` display: flex; flex-wrap: wrap; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[2]}; `; // TODO: unify this and use Dropdown component instead diff --git a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/__stories__/ExpandableList.stories.tsx b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/__stories__/ExpandableList.stories.tsx index e64298bc853..9d66b8765db 100644 --- a/packages/twenty-front/src/modules/ui/layout/expandable-list/components/__stories__/ExpandableList.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/expandable-list/components/__stories__/ExpandableList.stories.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { expect, userEvent, within } from 'storybook/test'; @@ -7,9 +7,10 @@ import { isDefined } from 'twenty-shared/utils'; import { Tag } from 'twenty-ui/components'; import { ComponentDecorator } from 'twenty-ui/testing'; import { MAIN_COLOR_NAMES } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; width: 300px; `; diff --git a/packages/twenty-front/src/modules/ui/layout/fullscreen/components/FullScreenContainer.tsx b/packages/twenty-front/src/modules/ui/layout/fullscreen/components/FullScreenContainer.tsx index 768f4254d29..e21c5aedd89 100644 --- a/packages/twenty-front/src/modules/ui/layout/fullscreen/components/FullScreenContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/fullscreen/components/FullScreenContainer.tsx @@ -4,8 +4,9 @@ import { Breadcrumb, type BreadcrumbProps, } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useIsMobile } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type FullScreenContainerProps = { children: JSX.Element | JSX.Element[]; @@ -14,7 +15,7 @@ type FullScreenContainerProps = { }; const StyledFullScreen = styled.div` - background: ${({ theme }) => theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; display: flex; flex-direction: column; width: 100%; @@ -22,14 +23,14 @@ const StyledFullScreen = styled.div` const StyledMainContainer = styled.div` height: calc( - 100% - ${PAGE_BAR_MIN_HEIGHT}px - ${({ theme }) => theme.spacing(2 * 2 + 5)} + 100% - ${PAGE_BAR_MIN_HEIGHT}px - ${themeCssVariables.spacing[9]} ); - padding: ${({ theme }) => - `0 ${theme.spacing(3)} ${theme.spacing(3)} ${theme.spacing(3)}`}; + padding: 0 ${themeCssVariables.spacing[3]} ${themeCssVariables.spacing[3]} + ${themeCssVariables.spacing[3]}; `; const StyledPageHeader = styled(PageHeader)` - padding-left: ${({ theme }) => theme.spacing(3)}; + padding-left: ${themeCssVariables.spacing[3]}; `; export const FullScreenContainer = ({ diff --git a/packages/twenty-front/src/modules/ui/layout/fullscreen/components/__stories__/FullScreenContainer.stories.tsx b/packages/twenty-front/src/modules/ui/layout/fullscreen/components/__stories__/FullScreenContainer.stories.tsx index 6d0292809cf..544890c93e8 100644 --- a/packages/twenty-front/src/modules/ui/layout/fullscreen/components/__stories__/FullScreenContainer.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/fullscreen/components/__stories__/FullScreenContainer.stories.tsx @@ -1,5 +1,5 @@ import { FullScreenContainer } from '@/ui/layout/fullscreen/components/FullScreenContainer'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import { ComponentDecorator, diff --git a/packages/twenty-front/src/modules/ui/layout/fullscreen/hooks/useFullScreenModal.tsx b/packages/twenty-front/src/modules/ui/layout/fullscreen/hooks/useFullScreenModal.tsx index f4cbf45e9a7..df6338a0f4c 100644 --- a/packages/twenty-front/src/modules/ui/layout/fullscreen/hooks/useFullScreenModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/fullscreen/hooks/useFullScreenModal.tsx @@ -4,9 +4,10 @@ import { Breadcrumb, type BreadcrumbProps, } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useRef } from 'react'; import { createPortal } from 'react-dom'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledFullScreenOverlay = styled.div` position: fixed; @@ -14,7 +15,7 @@ const StyledFullScreenOverlay = styled.div` left: 0; right: 0; bottom: 0; - background: ${({ theme }) => theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; display: flex; flex-direction: column; width: 100%; @@ -23,17 +24,17 @@ const StyledFullScreenOverlay = styled.div` `; const StyledFullScreenHeader = styled(PageHeader)` - padding-left: ${({ theme }) => theme.spacing(3)}; + padding-left: ${themeCssVariables.spacing[3]}; `; const StyledFullScreenContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; flex: 1; min-height: 0; - padding: ${({ theme }) => - `0 ${theme.spacing(3)} ${theme.spacing(3)} ${theme.spacing(3)}`}; + padding: 0 ${themeCssVariables.spacing[3]} ${themeCssVariables.spacing[3]} + ${themeCssVariables.spacing[3]}; // Make the immediate child a flex column that grows, so nested components // with height="100%" (e.g., editors) can size correctly. @@ -42,7 +43,7 @@ const StyledFullScreenContent = styled.div` flex-direction: column; flex: 1; min-height: 0; - row-gap: ${({ theme }) => theme.spacing(5)}; + row-gap: ${themeCssVariables.spacing[5]}; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index 80d1fc19c15..d68cb6abeab 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; @@ -11,6 +11,7 @@ import { useLingui } from '@lingui/react/macro'; import { H1Title, H1TitleFontColor } from 'twenty-ui/display'; import { Button, type ButtonAccent } from 'twenty-ui/input'; import { Section, SectionAlignment, SectionFontColor } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type ConfirmationModalProps = { modalId: string; @@ -28,15 +29,15 @@ export type ConfirmationModalProps = { }; const StyledConfirmationModal = styled(Modal)` - border-radius: ${({ theme }) => theme.spacing(1)}; - width: calc(400px - ${({ theme }) => theme.spacing(32)}); + border-radius: ${themeCssVariables.spacing[1]}; + width: calc(400px - ${themeCssVariables.spacing[32]}); height: auto; `; export const StyledCenteredButton = styled(Button)` box-sizing: border-box; justify-content: center; - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; const StyledCenteredTitle = styled.div` @@ -44,17 +45,17 @@ const StyledCenteredTitle = styled.div` `; const StyledSection = styled(Section)` - margin-bottom: ${({ theme }) => theme.spacing(6)}; + margin-bottom: ${themeCssVariables.spacing[6]}; `; export const StyledConfirmationButton = styled(StyledCenteredButton)` - border-color: ${({ theme }) => theme.border.color.danger}; + border-color: ${themeCssVariables.border.color.danger}; box-shadow: none; - color: ${({ theme }) => theme.color.red}; - font-size: ${({ theme }) => theme.font.size.md}; - line-height: ${({ theme }) => theme.text.lineHeight.lg}; + color: ${themeCssVariables.color.red}; + font-size: ${themeCssVariables.font.size.md}; + line-height: ${themeCssVariables.text.lineHeight.lg}; :hover { - background-color: ${({ theme }) => theme.color.red3}; + background-color: ${themeCssVariables.color.red3}; } `; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx index 4882a94db04..fd72d1e2539 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx @@ -10,13 +10,14 @@ import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AnimatePresence, motion } from 'framer-motion'; -import React, { useRef } from 'react'; +import React, { useContext, useRef } from 'react'; import { createPortal } from 'react-dom'; import { isDefined } from 'twenty-shared/utils'; -const StyledModalDiv = styled(motion.div)<{ +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; +const StyledModalDivBase = styled.div<{ size?: ModalSize; padding?: ModalPadding; isMobile: boolean; @@ -24,65 +25,70 @@ const StyledModalDiv = styled(motion.div)<{ }>` display: flex; flex-direction: column; - box-shadow: ${({ theme, modalVariant }) => + box-shadow: ${({ modalVariant }) => modalVariant === 'primary' - ? theme.boxShadow.superHeavy + ? themeCssVariables.boxShadow.superHeavy : modalVariant === 'transparent' ? 'none' - : theme.boxShadow.strong}; - background: ${({ theme, modalVariant }) => - modalVariant === 'transparent' ? 'transparent' : theme.background.primary}; - color: ${({ theme }) => theme.font.color.primary}; - border-radius: ${({ theme, isMobile, modalVariant }) => { + : themeCssVariables.boxShadow.strong}; + background: ${({ modalVariant }) => + modalVariant === 'transparent' + ? 'transparent' + : themeCssVariables.background.primary}; + color: ${themeCssVariables.font.color.primary}; + border-radius: ${({ isMobile, modalVariant }) => { if (isMobile || modalVariant === 'transparent') return `0`; - return theme.border.radius.md; + return themeCssVariables.border.radius.md; }}; overflow-x: hidden; overflow-y: auto; z-index: ${RootStackingContextZIndices.RootModal}; // should be higher than Backdrop's z-index - width: ${({ isMobile, size, theme }) => { - if (isMobile) return theme.modal.size.fullscreen.width; + width: ${({ isMobile, size }) => { + if (isMobile) + return themeCssVariables.modal.size.fullscreen.width ?? 'auto'; switch (size) { case 'small': - return theme.modal.size.sm.width; + return themeCssVariables.modal.size.sm.width ?? 'auto'; case 'medium': - return theme.modal.size.md.width; + return themeCssVariables.modal.size.md.width ?? 'auto'; case 'large': - return theme.modal.size.lg.width; + return themeCssVariables.modal.size.lg.width ?? 'auto'; case 'extraLarge': - return theme.modal.size.xl.width; + return themeCssVariables.modal.size.xl.width ?? 'auto'; default: return 'auto'; } }}; - padding: ${({ padding, theme }) => { + padding: ${({ padding }) => { switch (padding) { case 'none': - return theme.spacing(0); + return themeCssVariables.spacing[0]; case 'small': - return theme.spacing(2); + return themeCssVariables.spacing[2]; case 'medium': - return theme.spacing(4); + return themeCssVariables.spacing[4]; case 'large': - return theme.spacing(6); + return themeCssVariables.spacing[6]; default: return 'auto'; } }}; - height: ${({ isMobile, theme, size }) => { - if (isMobile) return theme.modal.size.fullscreen.height; + height: ${({ isMobile, size }) => { + if (isMobile) + return themeCssVariables.modal.size.fullscreen.height ?? 'auto'; switch (size) { case 'extraLarge': - return theme.modal.size.xl.height; + return themeCssVariables.modal.size.xl.height ?? 'auto'; default: return 'auto'; } }}; max-height: ${({ isMobile }) => (isMobile ? 'none' : '90dvh')}; `; +const StyledModalDiv = motion.create(StyledModalDivBase); const StyledHeader = styled.div` align-items: center; @@ -90,7 +96,7 @@ const StyledHeader = styled.div` flex-direction: row; height: 60px; overflow: hidden; - padding: ${({ theme }) => theme.spacing(5)}; + padding: ${themeCssVariables.spacing[5]}; `; const StyledContent = styled.div<{ @@ -101,17 +107,11 @@ const StyledContent = styled.div<{ flex: 1; flex: 1 1 0%; flex-direction: column; - padding: ${({ theme }) => theme.spacing(10)}; - ${({ isVerticalCentered }) => - isVerticalCentered && - css` - align-items: center; - `} - ${({ isHorizontalCentered }) => - isHorizontalCentered && - css` - justify-content: center; - `} + padding: ${themeCssVariables.spacing[10]}; + align-items: ${({ isVerticalCentered }) => + isVerticalCentered ? 'center' : 'stretch'}; + justify-content: ${({ isHorizontalCentered }) => + isHorizontalCentered ? 'center' : 'flex-start'}; `; const StyledFooter = styled.div` @@ -120,22 +120,22 @@ const StyledFooter = styled.div` flex-direction: row; height: 60px; overflow: hidden; - padding: ${({ theme }) => theme.spacing(5)}; + padding: ${themeCssVariables.spacing[5]}; `; -const StyledBackDrop = styled(motion.div)<{ +const StyledBackDropBase = styled.div<{ modalVariant: ModalVariants; isInContainer?: boolean; }>` align-items: center; - background: ${({ theme, modalVariant, isInContainer }) => + background: ${({ modalVariant, isInContainer }) => isInContainer - ? theme.background.overlayTertiary + ? themeCssVariables.background.overlayTertiary : modalVariant === 'primary' || modalVariant === 'transparent' - ? theme.background.overlayPrimary + ? themeCssVariables.background.overlayPrimary : modalVariant === 'secondary' - ? theme.background.overlaySecondary - : theme.background.overlayTertiary}; + ? themeCssVariables.background.overlaySecondary + : themeCssVariables.background.overlayTertiary}; display: flex; height: 100%; justify-content: center; @@ -147,6 +147,7 @@ const StyledBackDrop = styled(motion.div)<{ z-index: ${RootStackingContextZIndices.RootModalBackDrop}; user-select: none; `; +const StyledBackDrop = motion.create(StyledBackDropBase); type ModalHeaderProps = React.PropsWithChildren & { className?: string; @@ -237,7 +238,7 @@ export const Modal = ({ : container; const isInContainer = isDefined(container) && !ignoreContainer; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const stopEventPropagation = (e: React.MouseEvent) => { e.stopPropagation(); diff --git a/packages/twenty-front/src/modules/ui/layout/overlay/components/OverlayContainer.tsx b/packages/twenty-front/src/modules/ui/layout/overlay/components/OverlayContainer.tsx index 330669e0ca9..bf888541740 100644 --- a/packages/twenty-front/src/modules/ui/layout/overlay/components/OverlayContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/overlay/components/OverlayContainer.tsx @@ -1,4 +1,5 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; // eslint-disable-next-line twenty/styled-components-prefixed-with-styled export const OverlayContainer = styled.div<{ @@ -8,16 +9,16 @@ export const OverlayContainer = styled.div<{ align-items: center; display: flex; - backdrop-filter: ${({ theme }) => theme.blur.medium}; + backdrop-filter: ${themeCssVariables.blur.medium}; - border-radius: ${({ theme, borderRadius }) => - theme.border.radius[borderRadius ?? 'md']}; + border-radius: ${({ borderRadius }) => + themeCssVariables.border.radius[borderRadius ?? 'md']}; - background: ${({ theme }) => theme.background.transparent.primary}; + background: ${themeCssVariables.background.transparent.primary}; border: 1px solid - ${({ theme, hasDangerBorder }) => - theme.border.color[hasDangerBorder ? 'danger' : 'medium']}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; + ${({ hasDangerBorder }) => + themeCssVariables.border.color[hasDangerBorder ? 'danger' : 'medium']}; + box-shadow: ${themeCssVariables.boxShadow.strong}; overflow: hidden; diff --git a/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton.tsx b/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton.tsx index 03b059fd79c..d1d00b2a13e 100644 --- a/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton.tsx @@ -5,33 +5,31 @@ import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/i import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices'; import { PAGE_HEADER_COMMAND_MENU_BUTTON_CLICK_OUTSIDE_ID } from '@/ui/layout/page-header/constants/PageHeaderCommandMenuButtonClickOutsideId'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { i18n } from '@lingui/core'; import { t } from '@lingui/core/macro'; import { motion } from 'framer-motion'; import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/display'; import { AnimatedButton } from 'twenty-ui/input'; import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; -const StyledButtonWrapper = styled.div<{ - alignWithCommandMenuTopBar: boolean; -}>` +const StyledButtonWrapper = styled.div<{ alignToTop: boolean }>` + align-items: ${({ alignToTop }) => (alignToTop ? 'center' : 'initial')}; + display: ${({ alignToTop }) => (alignToTop ? 'flex' : 'block')}; + height: ${({ alignToTop }) => + alignToTop ? `${COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE}px` : 'auto'}; + position: ${({ alignToTop }) => (alignToTop ? 'fixed' : 'static')}; + right: ${({ alignToTop }) => + alignToTop ? themeCssVariables.spacing[3] : 'auto'}; + top: ${({ alignToTop }) => (alignToTop ? '0' : 'auto')}; z-index: ${RootStackingContextZIndices.CommandMenuButton}; - ${({ alignWithCommandMenuTopBar, theme }) => - alignWithCommandMenuTopBar && - css` - align-items: center; - display: flex; - height: ${COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE}px; - position: fixed; - right: ${theme.spacing(3)}; - top: 0; - `} `; const StyledTooltipWrapper = styled.div` - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; `; const xPaths = { @@ -46,7 +44,7 @@ const AnimatedIcon = ({ }: { isCommandMenuOpened: boolean; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { ? t`Close command menu` : t`Open command menu`; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( - +
theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; display: flex; flex-direction: column; height: 100dvh; @@ -13,19 +13,9 @@ const StyledLayout = styled.div` `; export const BlankLayout = () => { - const theme = useTheme(); return ( - <> - - - - - + + + ); }; diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx index d22283cc6ee..8a3132ebc18 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx @@ -12,7 +12,7 @@ import { PageDragDropProvider } from '@/navigation/components/PageDragDropProvid import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage'; import { OBJECT_SETTINGS_WIDTH } from '@/settings/data-model/constants/ObjectSettings'; import { SignInAppNavigationDrawerMock } from '@/sign-in-background-mock/components/SignInAppNavigationDrawerMock'; -import { lazy, Suspense } from 'react'; +import { Suspense, lazy, useContext } from 'react'; const SignInBackgroundMockPage = lazy(() => import('@/sign-in-background-mock/components/SignInBackgroundMockPage').then( @@ -23,39 +23,37 @@ import { useShowFullscreen } from '@/ui/layout/fullscreen/hooks/useShowFullscree import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { Global, css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'; import { Outlet } from 'react-router-dom'; import { useScreenSize } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledLayout = styled.div` - background: ${({ theme }) => theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; display: flex; flex-direction: column; height: 100dvh; position: relative; - scrollbar-color: ${({ theme }) => theme.border.color.medium} transparent; + scrollbar-color: ${themeCssVariables.border.color.medium} transparent; scrollbar-width: 4px; width: 100%; *::-webkit-scrollbar-thumb { - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; } `; -const StyledPageContainer = styled(motion.div)` +const StyledPageContainerBase = styled.div` display: flex; flex: 1 1 auto; flex-direction: row; min-height: 0; `; +const StyledPageContainer = motion.create(StyledPageContainerBase); -const StyledAppNavigationDrawer = styled(AppNavigationDrawer)` - flex-shrink: 0; -`; - -const StyledAppNavigationDrawerMock = styled(SignInAppNavigationDrawerMock)` +const StyledNavigationDrawerWrapper = styled.div` flex-shrink: 0; `; @@ -68,20 +66,13 @@ const StyledMainContainer = styled.div` export const DefaultLayout = () => { const isMobile = useIsMobile(); const isSettingsPage = useIsSettingsPage(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const windowsWidth = useScreenSize().width; const showAuthModal = useShowAuthModal(); const useShowFullScreen = useShowFullscreen(); return ( <> - @@ -105,9 +96,13 @@ export const DefaultLayout = () => { {!showAuthModal && } {showAuthModal ? ( - + + + ) : useShowFullScreen ? null : ( - + + + )} {showAuthModal ? ( <> diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx index eaee8fcaab5..49770fa9b48 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/PageBody.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; import { PagePanel } from './PagePanel'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type PageBodyProps = { children: ReactNode; @@ -9,15 +10,15 @@ type PageBodyProps = { }; const StyledMainContainer = styled.div` - background: ${({ theme }) => theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; box-sizing: border-box; display: flex; flex: 1 1 auto; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; min-height: 0; - padding-bottom: ${({ theme }) => theme.spacing(3)}; - padding-right: ${({ theme }) => theme.spacing(3)}; + padding-bottom: ${themeCssVariables.spacing[3]}; + padding-right: ${themeCssVariables.spacing[3]}; padding-left: 0; width: 100%; `; diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx index 9f1717ec544..365936afa65 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/PageContainer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div` display: flex; diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx index 2a59339ab0e..7524c557835 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/PageHeader.tsx @@ -1,6 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { type ReactNode } from 'react'; +import { styled } from '@linaria/react'; +import { type ReactNode, useContext } from 'react'; import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton'; @@ -16,41 +15,43 @@ import { OverflowingTextWithTooltip, } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; -import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledTopBarContainer = styled.div<{ isMobile: boolean }>` align-items: center; - background: ${({ theme }) => theme.background.noisy}; - color: ${({ theme }) => theme.font.color.primary}; + background: ${themeCssVariables.background.noisy}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - font-size: ${({ theme }) => theme.font.size.lg}; + font-size: ${themeCssVariables.font.size.lg}; justify-content: space-between; min-height: ${PAGE_BAR_MIN_HEIGHT}px; - padding-top: ${({ theme }) => theme.spacing(3)}; - padding-bottom: ${({ theme }) => theme.spacing(3)}; - padding-left: ${({ isMobile, theme }) => (isMobile ? theme.spacing(3) : 0)}; - padding-right: ${({ theme }) => theme.spacing(3)}; - gap: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[3]}; + padding-bottom: ${themeCssVariables.spacing[3]}; + padding-left: ${({ isMobile }) => + isMobile ? themeCssVariables.spacing[3] : 0}; + padding-right: ${themeCssVariables.spacing[3]}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledLeftContainer = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow-x: hidden; width: 100%; @media (max-width: ${MOBILE_VIEWPORT}px) { - padding-left: ${({ theme }) => theme.spacing(1)}; + padding-left: ${themeCssVariables.spacing[1]}; } `; const StyledTitleContainer = styled.div` display: flex; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-right: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-right: ${themeCssVariables.spacing[1]}; width: 100%; overflow: hidden; align-items: center; @@ -59,7 +60,7 @@ const StyledTitleContainer = styled.div` const StyledTopBarIconStyledTitleContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; flex-direction: row; width: 100%; overflow: hidden; @@ -67,7 +68,7 @@ const StyledTopBarIconStyledTitleContainer = styled.div` const StyledPageActionContainer = styled.div` display: inline-flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; flex: 1 0 auto; `; @@ -95,7 +96,7 @@ export const PageHeader = ({ className, }: PageHeaderProps) => { const isMobile = useIsMobile(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const isNavigationDrawerExpanded = useAtomStateValue( isNavigationDrawerExpandedState, ); diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx index a7d1950789c..70535860745 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/PagePanel.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import React from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledPanel = styled.div` - background: ${({ theme }) => theme.background.primary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.primary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; height: 100%; overflow-x: auto; overflow-y: hidden; diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx index 32421b521be..7523eaac8b5 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx @@ -1,26 +1,27 @@ -import styled from '@emotion/styled'; -import { type ReactNode } from 'react'; +import { styled } from '@linaria/react'; +import { type CSSProperties, type ReactNode } from 'react'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledOuterContainer = styled.div` display: flex; - gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')}; + gap: var(--show-page-gap, 0); height: 100%; width: 100%; `; const StyledInnerContainer = styled.div` display: flex; - flex-direction: ${() => (useIsMobile() ? 'column' : 'row')}; + flex-direction: var(--show-page-direction, row); width: 100%; height: 100%; `; const StyledScrollWrapper = styled(ScrollWrapper)` - background-color: ${({ theme }) => theme.background.secondary}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border-radius: ${themeCssVariables.border.radius.md}; `; export type ShowPageContainerProps = { @@ -29,10 +30,20 @@ export type ShowPageContainerProps = { export const ShowPageContainer = ({ children }: ShowPageContainerProps) => { const isMobile = useIsMobile(); + + const mobileStyle = isMobile + ? ({ + '--show-page-gap': themeCssVariables.spacing[3], + '--show-page-direction': 'column', + } as CSSProperties) + : undefined; + return isMobile ? ( - + - {children} + + {children} + ) : ( diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx index 2c4a6b4fb3b..9dcb0563221 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/components/SubMenuTopBarContainer.tsx @@ -3,10 +3,11 @@ import { Breadcrumb, type BreadcrumbProps, } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type JSX, type ReactNode } from 'react'; import { PageBody } from './PageBody'; import { PageHeader } from './PageHeader'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type SubMenuTopBarContainerProps = { children: JSX.Element | JSX.Element[]; @@ -24,13 +25,14 @@ const StyledContainer = styled.div` `; const StyledTitle = styled.h3<{ reserveTitleSpace?: boolean }>` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.semiBold}; line-height: 1.2; - margin: ${({ theme }) => theme.spacing(8, 8, 2)}; - min-height: ${({ theme, reserveTitleSpace }) => - reserveTitleSpace ? theme.spacing(5) : 'none'}; + margin: ${themeCssVariables.spacing[8]} ${themeCssVariables.spacing[8]} + ${themeCssVariables.spacing[2]}; + min-height: ${({ reserveTitleSpace }) => + reserveTitleSpace ? themeCssVariables.spacing[5] : 'none'}; `; export const SubMenuTopBarContainer = ({ diff --git a/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelEdge.tsx b/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelEdge.tsx index 7c75379d585..a9a8938d8da 100644 --- a/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelEdge.tsx +++ b/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelEdge.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { RESIZE_EDGE_WIDTH_PX } from '@/ui/layout/resizable-panel/constants/ResizeEdgeWidthPx'; import { useResizablePanel } from '@/ui/layout/resizable-panel/hooks/useResizablePanel'; import { type ResizablePanelConstraints } from '@/ui/layout/resizable-panel/types/ResizablePanelConstraints'; import { type ResizablePanelSide } from '@/ui/layout/resizable-panel/types/ResizablePanelSide'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type StyledEdgeProps = { isActive: boolean; @@ -12,32 +13,34 @@ type StyledEdgeProps = { }; const StyledEdge = styled.div` - position: absolute; - top: 0; - bottom: 0; - ${({ side }) => - side === 'right' ? 'right' : 'left'}: -${RESIZE_EDGE_WIDTH_PX / 2}px; - width: ${RESIZE_EDGE_WIDTH_PX}px; - cursor: col-resize; - - display: flex; align-items: center; + bottom: 0; + cursor: col-resize; + display: flex; justify-content: center; + left: ${({ side }) => + side === 'left' ? `-${RESIZE_EDGE_WIDTH_PX / 2}px` : 'auto'}; + position: absolute; + + right: ${({ side }) => + side === 'right' ? `-${RESIZE_EDGE_WIDTH_PX / 2}px` : 'auto'}; + top: 0; + width: ${RESIZE_EDGE_WIDTH_PX}px; `; const StyledHandle = styled.div<{ isActive: boolean; isHovered: boolean }>` width: 4px; height: 48px; - border-radius: ${({ theme }) => theme.border.radius.pill}; - background-color: ${({ theme, isActive, isHovered }) => + border-radius: ${themeCssVariables.border.radius.pill}; + background-color: ${({ isActive, isHovered }) => isActive - ? theme.color.blue + ? themeCssVariables.color.blue : isHovered - ? theme.font.color.tertiary - : theme.background.quaternary}; + ? themeCssVariables.font.color.tertiary + : themeCssVariables.background.quaternary}; transition: - background-color ${({ theme }) => theme.animation.duration.fast}s, - transform ${({ theme }) => theme.animation.duration.fast}s; + background-color ${themeCssVariables.animation.duration.fast}s, + transform ${themeCssVariables.animation.duration.fast}s; transform: ${({ isHovered, isActive }) => isHovered || isActive ? 'scaleY(1.2)' : 'scaleY(1)'}; `; diff --git a/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelGap.tsx b/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelGap.tsx index db08935dab9..904c3f20c0f 100644 --- a/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelGap.tsx +++ b/packages/twenty-front/src/modules/ui/layout/resizable-panel/components/ResizablePanelGap.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useResizablePanel } from '@/ui/layout/resizable-panel/hooks/useResizablePanel'; import { type ResizablePanelConstraints } from '@/ui/layout/resizable-panel/types/ResizablePanelConstraints'; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerFooter.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerFooter.tsx index ab8a43dcf31..662fac7ce4f 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerFooter.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerFooter.tsx @@ -1,16 +1,17 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Fragment } from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.background.secondary}; + border-top: 1px solid ${themeCssVariables.border.color.light}; bottom: 0; box-sizing: border-box; display: flex; justify-content: flex-end; - padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)}; - gap: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; + gap: ${themeCssVariables.spacing[2]}; width: 100%; `; diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowStepExecutionResult.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowStepExecutionResult.tsx index 5b106812482..c2963106d18 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowStepExecutionResult.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowStepExecutionResult.tsx @@ -1,6 +1,5 @@ import { LightCopyIconButton } from '@/object-record/record-field/ui/components/LightCopyIconButton'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconLoader, @@ -9,6 +8,9 @@ import { } from 'twenty-ui/display'; import { CodeEditor, CoreEditorHeader } from 'twenty-ui/input'; import { AnimatedCircleLoading } from 'twenty-ui/utilities'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledContainer = styled.div` display: flex; @@ -28,26 +30,26 @@ type OutputAccent = 'default' | 'success' | 'error'; const StyledInfoContainer = styled.div` display: flex; - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; `; const StyledOutput = styled.div<{ accent?: OutputAccent }>` align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; - color: ${({ theme, accent }) => + gap: ${themeCssVariables.spacing[1]}; + color: ${({ accent }) => accent === 'success' - ? theme.color.turquoise + ? themeCssVariables.color.turquoise : accent === 'error' - ? theme.color.red - : theme.font.color.secondary}; + ? themeCssVariables.color.red + : themeCssVariables.font.color.secondary}; display: flex; `; const StyledStatusInfo = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - font-size: ${({ theme }) => theme.font.size.sm}; - color: ${({ theme }) => theme.font.color.tertiary}; + gap: ${themeCssVariables.spacing[2]}; + font-size: ${themeCssVariables.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; `; export type ExecutionStatus = { @@ -77,7 +79,7 @@ export const WorkflowStepExecutionResult = ({ loadingMessage = t`Processing...`, idleMessage = t`Output`, }: WorkflowStepExecutionResultProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const SuccessLeftNode = ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx index 041477e9049..91547549458 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx @@ -32,8 +32,7 @@ import { getConnectionOptionsForSourceHandle } from '@/workflow/workflow-diagram import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId'; import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId'; import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Background, ReactFlow, @@ -64,6 +63,8 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState import { isDefined } from 'twenty-shared/utils'; import { Tag, type TagColor } from 'twenty-ui/components'; import { useStore } from 'jotai'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledResetReactflowStyles = styled.div` height: 100%; @@ -92,7 +93,7 @@ const StyledStatusTagContainer = styled.div` left: 0; top: 0; position: absolute; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; `; const defaultFitViewOptions = { @@ -166,7 +167,7 @@ export const WorkflowDiagramCanvasBase = ({ }) => void; }) => { const store = useStore(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const reactflow = useReactFlow(); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramConnector.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramConnector.tsx index 03fa2128a6e..dd418456dd3 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramConnector.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramConnector.tsx @@ -1,7 +1,8 @@ -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramConnector = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( ` - background: ${({ theme }) => theme.background.primary}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; - border-radius: ${({ theme }) => theme.spacing(2)}; + background: ${themeCssVariables.background.primary}; + box-shadow: ${themeCssVariables.boxShadow.strong}; + border-radius: ${themeCssVariables.spacing[2]}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing[0.5]}; left: ${({ x }) => `${x}px`}; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; position: absolute; top: ${({ y }) => `${y}px`}; width: 200px; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunCard.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunCard.tsx index f05f79d09bc..cb4e25107d3 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunCard.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunCard.tsx @@ -6,22 +6,23 @@ import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/Wo import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect'; import { WorkflowRunVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { Suspense, useId } from 'react'; +import { styled } from '@linaria/react'; +import { Suspense, useContext, useId } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledLoadingSkeletonContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 100%; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; width: 100%; `; const LoadingSkeleton = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionCard.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionCard.tsx index 523321be3e4..f0ea3072fd4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionCard.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionCard.tsx @@ -4,22 +4,23 @@ import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWo import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer'; import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { Suspense } from 'react'; +import { styled } from '@linaria/react'; +import { Suspense, useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledLoadingSkeletonContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: 100%; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; width: 100%; `; const LoadingSkeleton = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/getWorkflowDiagramColors.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/getWorkflowDiagramColors.ts index 338b1fabbdc..6c05db05f11 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/getWorkflowDiagramColors.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/getWorkflowDiagramColors.ts @@ -1,5 +1,5 @@ import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow'; -import { type Theme } from '@emotion/react'; +import type { ThemeType } from 'twenty-ui/theme'; type WorkflowDiagramColors = { background: string; @@ -18,7 +18,7 @@ export const getWorkflowDiagramColors = ({ theme, runStatus, }: { - theme: Theme; + theme: ThemeType; runStatus?: WorkflowRunStepStatus; }): WorkflowDiagramNodeColors => { switch (runStatus) { diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge.tsx index c1d357322ee..3e32b587666 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge.tsx @@ -1,7 +1,8 @@ import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState'; import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps'; -import { useTheme } from '@emotion/react'; import { BaseEdge } from '@xyflow/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowDiagramBaseEdgeProps = Pick< WorkflowDiagramEdgeComponentProps, @@ -24,7 +25,7 @@ export const WorkflowDiagramBaseEdge = ({ markerEnd, path, }: WorkflowDiagramBaseEdgeProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { isEdgeSelected, isEdgeHovered } = useEdgeState(); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBlankEdge.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBlankEdge.tsx index 041c60725be..fe832db5ca2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBlankEdge.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBlankEdge.tsx @@ -1,7 +1,8 @@ import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { getEdgePath } from '@/workflow/workflow-diagram/workflow-edges/utils/getEdgePath'; -import { useTheme } from '@emotion/react'; import { BaseEdge, type EdgeProps } from '@xyflow/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowDiagramBlankEdgeProps = EdgeProps; @@ -15,7 +16,7 @@ export const WorkflowDiagramBlankEdge = ({ targetX, targetPosition, }: WorkflowDiagramBlankEdgeProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { segments } = getEdgePath({ sourceX, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramConnection.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramConnection.tsx index 9bca932bb62..b90ceac9612 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramConnection.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramConnection.tsx @@ -2,8 +2,9 @@ import { type ConnectionLineComponentProps, getBezierPath, } from '@xyflow/react'; -import { useTheme } from '@emotion/react'; import { EDGE_BRANCH_ARROW_MARKER } from '@/workflow/workflow-diagram/workflow-edges/constants/EdgeBranchArrowMarker'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowDiagramConnectionProps = ConnectionLineComponentProps; @@ -13,7 +14,7 @@ export const WorkflowDiagramConnection = ({ toX, toY, }: WorkflowDiagramConnectionProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [path] = getBezierPath({ sourceX: fromX, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers.tsx index 31df069cafa..f6a8f6c22a0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers.tsx @@ -1,8 +1,9 @@ +import { useContext } from 'react'; import { EDGE_BRANCH_ARROW_MARKER } from '@/workflow/workflow-diagram/workflow-edges/constants/EdgeBranchArrowMarker'; -import { useTheme } from '@emotion/react'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramCustomMarkers = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramDefaultEdgeReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramDefaultEdgeReadonly.tsx index 10bf046e9fe..7267c54cf98 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramDefaultEdgeReadonly.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramDefaultEdgeReadonly.tsx @@ -2,10 +2,11 @@ import { WorkflowDiagramEdgeLabel } from '@/workflow/workflow-diagram/workflow-e import { WorkflowDiagramEdgeLabelContainer } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabelContainer'; import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps'; import { getEdgePath } from '@/workflow/workflow-diagram/workflow-edges/utils/getEdgePath'; -import { useTheme } from '@emotion/react'; import { i18n } from '@lingui/core'; import { BaseEdge, EdgeLabelRenderer } from '@xyflow/react'; import { isDefined } from 'twenty-shared/utils'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowDiagramDefaultEdgeReadonlyProps = WorkflowDiagramEdgeComponentProps; @@ -21,7 +22,7 @@ export const WorkflowDiagramDefaultEdgeReadonly = ({ markerEnd, data, }: WorkflowDiagramDefaultEdgeReadonlyProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { segments, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup.tsx index 19736242d85..13e67bbf861 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup.tsx @@ -1,19 +1,18 @@ -import styled from '@emotion/styled'; -import { IconButtonGroup, type IconButtonGroupProps } from 'twenty-ui/input'; import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors'; -import { css } from '@emotion/react'; +import { css } from '@linaria/core'; +import { styled } from '@linaria/react'; +import { useContext, useMemo, type CSSProperties } from 'react'; +import { IconButtonGroup, type IconButtonGroupProps } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; -const StyledIconButtonGroup = styled(IconButtonGroup)<{ selected?: boolean }>` +const iconButtonGroupStyle = css` + background-color: var(--edge-btn-bg, transparent); + border: var(--edge-btn-border, none); pointer-events: all; +`; - ${({ selected, theme }) => { - if (!selected) return ''; - const colors = getWorkflowDiagramColors({ theme }); - return css` - background-color: ${colors.selected.background}; - border: 1px solid ${colors.selected.borderColor}; - `; - }} +const StyledWrapper = styled.div` + display: contents; `; type WorkflowDiagramEdgeButtonGroupProps = IconButtonGroupProps & { @@ -24,11 +23,24 @@ export const WorkflowDiagramEdgeButtonGroup = ({ selected = false, iconButtons, }: WorkflowDiagramEdgeButtonGroupProps) => { + const { theme } = useContext(ThemeContext); + + const dynamicStyles = useMemo(() => { + if (!selected) return {}; + const colors = getWorkflowDiagramColors({ theme }); + return { + '--edge-btn-bg': colors.selected.background, + // eslint-disable-next-line lingui/no-unlocalized-strings + '--edge-btn-border': `1px solid ${colors.selected.borderColor}`, + } as CSSProperties; + }, [selected, theme]); + return ( - + + + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabel.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabel.tsx index 323373e0950..051e951a46e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabel.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabel.tsx @@ -1,23 +1,24 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { Label } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.strong}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.strong}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: center; - padding-block: ${({ theme }) => theme.spacing(0.5)}; - padding-inline: ${({ theme }) => theme.spacing(1)}; + padding-block: ${themeCssVariables.spacing[0.5]}; + padding-inline: ${themeCssVariables.spacing[1]}; `; const StyledNumber = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; `; type WorkflowDiagramEdgeLabelProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabelContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabelContainer.tsx index efb9590a18f..58a36e10733 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabelContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabelContainer.tsx @@ -1,5 +1,4 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Position } from '@xyflow/react'; import { isDefined } from 'twenty-shared/utils'; @@ -13,28 +12,19 @@ const StyledWorkflowDiagramEdgeLabelContainer = styled.div<{ position: absolute; width: fit-content; - ${({ position, sourceX, sourceY, centerX, centerY }) => { + transform: ${({ position, sourceX, sourceY, centerX, centerY }) => { if (isDefined(centerX) && isDefined(centerY)) { - return css` - transform: translate(-50%, -50%) translate(${centerX}px, ${centerY}px); - `; + return `translate(-50%, -50%) translate(${centerX}px, ${centerY}px)`; } - switch (position) { - case Position.Right: { - return css` - transform: translate(0%, -50%) - translate(${Math.floor(sourceX)}px, ${sourceY}px) translateX(10px); - `; - } - case Position.Bottom: { - return css` - transform: translate(-50%, 0%) - translate(${sourceX}px, ${Math.floor(sourceY)}px) translateY(10px); - `; - } + case Position.Right: + return `translate(0%, -50%) translate(${Math.floor(sourceX)}px, ${sourceY}px) translateX(10px)`; + case Position.Bottom: + return `translate(-50%, 0%) translate(${sourceX}px, ${Math.floor(sourceY)}px) translateY(10px)`; + default: + return 'none'; } - }} + }}; `; export { StyledWorkflowDiagramEdgeLabelContainer as WorkflowDiagramEdgeLabelContainer }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container.tsx index 348b8125506..ec220df3189 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container.tsx @@ -1,12 +1,11 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div<{ labelX: number; labelY: number }>` - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; pointer-events: all; - ${({ labelX, labelY }) => css` - transform: translate(-50%, -50%) translate(${labelX}px, ${labelY}px); - `} + transform: ${({ labelX, labelY }) => + `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`}; position: absolute; `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer.tsx index 63e6cf1a342..a018ccfd646 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledContainer = styled.div<{ shouldDisplay: boolean }>` opacity: ${({ shouldDisplay }) => (shouldDisplay ? 1 : 0)}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx index cf2a7dd081d..4c7a69ed4e8 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable.tsx @@ -17,9 +17,11 @@ import { useLingui } from '@lingui/react/macro'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => { const { t } = useLingui(); + const { theme } = useContext(ThemeContext); const { openWorkflowTriggerTypeInCommandMenu } = useWorkflowCommandMenu(); @@ -60,6 +62,7 @@ export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => { return ( @@ -72,7 +75,7 @@ export const WorkflowDiagramEmptyTriggerEditable = ({ id }: { id: string }) => { - + {t`Add a Trigger`} diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx index 9939279b79b..bb7c3739d9c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerReadonly.tsx @@ -19,10 +19,12 @@ import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramEmptyTriggerReadonly = ({ id }: { id: string }) => { const { getIcon } = useIcons(); const { t } = useLingui(); + const { theme } = useContext(ThemeContext); const workflowVisualizerWorkflowId = useAtomComponentStateValue( workflowVisualizerWorkflowIdComponentState, @@ -73,6 +75,7 @@ export const WorkflowDiagramEmptyTriggerReadonly = ({ id }: { id: string }) => { return ( @@ -85,7 +88,7 @@ export const WorkflowDiagramEmptyTriggerReadonly = ({ id }: { id: string }) => { - + {t`Add a Trigger`} diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleSource.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleSource.tsx index 0edeba75f11..fdf152f1046 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleSource.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleSource.tsx @@ -2,47 +2,23 @@ import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow'; import { NODE_HANDLE_HEIGHT_PX } from '@/workflow/workflow-diagram/constants/NodeHandleHeightPx'; import { NODE_HANDLE_WIDTH_PX } from '@/workflow/workflow-diagram/constants/NodeHandleWidthPx'; import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Handle, Position, type HandleProps } from '@xyflow/react'; +import { useContext, useMemo, type CSSProperties } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const HANDLE_SCALE_ON_HOVER = 1.5; -const StyledHandle = styled(Handle, { - shouldForwardProp: (prop) => - prop !== 'disableHoverEffect' && - prop !== 'selected' && - prop !== 'hovered' && - prop !== 'runStatus', -})<{ - type: HandleProps['type']; - disableHoverEffect?: boolean; - selected: boolean; - hovered?: boolean; - runStatus?: WorkflowRunStepStatus; -}>` +const StyledHandle = styled(Handle)` &.react-flow__handle { - opacity: ${({ type }) => (type === 'target' ? 0 : 1)}; height: ${NODE_HANDLE_HEIGHT_PX}px; width: ${NODE_HANDLE_WIDTH_PX}px; - - ${({ theme, selected, hovered, disableHoverEffect, runStatus }) => { - if (!selected) { - return css` - background: ${theme.background.primary}; - border-color: ${hovered && disableHoverEffect !== true - ? theme.font.color.light - : theme.border.color.strong}; - `; - } - - const colors = getWorkflowDiagramColors({ theme, runStatus }); - - return css` - background: ${colors.selected.background}; - border-color: ${colors.selected.borderColor}; - `; - }} + opacity: var(--handle-opacity, 1); + background: var(--handle-bg); + border-color: var(--handle-border-color); + transform: var(--handle-transform); + transform-origin: var(--handle-transform-origin); &::after { content: ''; @@ -50,8 +26,8 @@ const StyledHandle = styled(Handle, { top: 50%; left: 50%; transform: translate(-50%, -50%); - width: calc(100% + ${({ theme }) => theme.spacing(4)}); - height: calc(100% + ${({ theme }) => theme.spacing(4)}); + width: calc(100% + ${themeCssVariables.spacing[4]}); + height: calc(100% + ${themeCssVariables.spacing[4]}); } transition: @@ -60,55 +36,88 @@ const StyledHandle = styled(Handle, { border-color 0.1s; z-index: 1; - ${({ position }) => { - if (position === Position.Right) { - return css` - transform: translate(50%, -50%); - transform-origin: top right; - `; - } - - return css` - transform: translate(-50%, 50%); - transform-origin: bottom left; - `; - }} - &.connectionindicator { cursor: pointer; } &:hover { - ${({ disableHoverEffect, theme }) => { - if (disableHoverEffect === true) { - return undefined; - } - - const colors = getWorkflowDiagramColors({ theme }); - - return css` - background: ${colors.selected.background} !important; - border-color: ${colors.selected.borderColor} !important; - `; - }} - - ${({ disableHoverEffect, position }) => { - if (disableHoverEffect === true) { - return undefined; - } - - if (position === Position.Right) { - return css` - transform: scale(${HANDLE_SCALE_ON_HOVER}) translate(50%, -50%); - `; - } - - return css` - transform: scale(${HANDLE_SCALE_ON_HOVER}) translate(-50%, 50%); - `; - }} + background: var(--handle-hover-bg, var(--handle-bg)) !important; + border-color: var( + --handle-hover-border-color, + var(--handle-border-color) + ) !important; + transform: var(--handle-hover-transform, var(--handle-transform)); } } `; -export { StyledHandle as WorkflowDiagramHandleSource }; +type WorkflowDiagramHandleSourceProps = { + id: string; + type: HandleProps['type']; + position: Position; + selected: boolean; + hovered?: boolean; + disableHoverEffect?: boolean; + runStatus?: WorkflowRunStepStatus; +}; + +export const WorkflowDiagramHandleSource = ({ + id, + type, + position, + selected, + hovered, + disableHoverEffect, + runStatus, +}: WorkflowDiagramHandleSourceProps) => { + const { theme } = useContext(ThemeContext); + + const dynamicStyles = useMemo(() => { + const isRight = position === Position.Right; + const transform = isRight ? 'translate(50%, -50%)' : 'translate(-50%, 50%)'; + // eslint-disable-next-line lingui/no-unlocalized-strings + const transformOrigin = isRight ? 'top right' : 'bottom left'; + + let bg: string; + let borderColor: string; + + if (selected) { + const colors = getWorkflowDiagramColors({ theme, runStatus }); + bg = colors.selected.background; + borderColor = colors.selected.borderColor; + } else { + bg = theme.background.primary; + borderColor = + hovered && disableHoverEffect !== true + ? theme.font.color.light + : theme.border.color.strong; + } + + const styles: Record = { + '--handle-opacity': type === 'target' ? '0' : '1', + '--handle-bg': bg, + '--handle-border-color': borderColor, + '--handle-transform': transform, + '--handle-transform-origin': transformOrigin, + }; + + if (disableHoverEffect !== true) { + const hoverColors = getWorkflowDiagramColors({ theme }); + styles['--handle-hover-bg'] = hoverColors.selected.background; + styles['--handle-hover-border-color'] = hoverColors.selected.borderColor; + styles['--handle-hover-transform'] = + `scale(${HANDLE_SCALE_ON_HOVER}) ${transform}`; + } + + return styles as CSSProperties; + }, [position, selected, hovered, disableHoverEffect, runStatus, type, theme]); + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleTarget.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleTarget.tsx index 8e6b64c2190..d939f08dfff 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleTarget.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramHandleTarget.tsx @@ -1,6 +1,7 @@ import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Handle, Position } from '@xyflow/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowDiagramHandleTargetProps = { isConnectable?: boolean; @@ -10,7 +11,7 @@ const StyledHandle = styled(Handle)` &.react-flow__handle { opacity: 0; z-index: 1; - border-radius: ${({ theme }) => theme.border.radius.md}; + border-radius: ${themeCssVariables.border.radius.md}; width: 100%; height: 100%; left: 0; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx index 1f7f4f0a2fa..a01b4de4bf9 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx @@ -19,11 +19,12 @@ import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workf import { useConnectionState } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useConnectionState'; import { isNodeTitleHighlighted } from '@/workflow/workflow-diagram/workflow-nodes/utils/isNodeTitleHighlighted'; import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { Position } from '@xyflow/react'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { capitalize, isDefined } from 'twenty-shared/utils'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledAddStepButtonContainer = styled.div<{ shouldDisplay: boolean; @@ -51,6 +52,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({ onClick?: () => void; }) => { const { i18n } = useLingui(); + const { theme } = useContext(ThemeContext); const [isHovered, setIsHovered] = useState(false); @@ -95,6 +97,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({ <> diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx index b6b7317df18..6e332b25742 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx @@ -1,15 +1,16 @@ import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey'; -import { useTheme } from '@emotion/react'; import { assertUnreachable } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramStepNodeIcon = ({ data, }: { data: WorkflowDiagramStepNodeData; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const Icon = getIcon(getWorkflowNodeIconKey(data)); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx index 5a493d521f7..75716e31901 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx @@ -25,6 +25,7 @@ import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomStat import { useContext } from 'react'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; export const WorkflowDiagramStepNodeReadonly = ({ id, @@ -34,6 +35,7 @@ export const WorkflowDiagramStepNodeReadonly = ({ data: WorkflowDiagramStepNodeData; }) => { const { getIcon } = useIcons(); + const { theme } = useContext(ThemeContext); const workflowVisualizerWorkflowId = useAtomComponentStateValue( workflowVisualizerWorkflowIdComponentState, @@ -88,6 +90,7 @@ export const WorkflowDiagramStepNodeReadonly = ({ <> @@ -104,6 +107,7 @@ export const WorkflowDiagramStepNodeReadonly = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeContainer.tsx index 02b9298b264..2e552fbefe6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeContainer.tsx @@ -1,20 +1,22 @@ import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow'; import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import type { ThemeType } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledNodeContainer = styled.div<{ + theme: ThemeType; runStatus?: WorkflowRunStepStatus; isConnectable?: boolean; selected: boolean; }>` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; max-width: 240px; min-width: 44px; - padding: ${({ theme }) => theme.spacing(2)}; - border-radius: ${({ theme }) => theme.border.radius.md}; + padding: ${themeCssVariables.spacing[2]}; + border-radius: ${themeCssVariables.border.radius.md}; border-width: 1px; border-style: solid; box-sizing: border-box; @@ -22,34 +24,35 @@ const StyledNodeContainer = styled.div<{ position: relative; transition: border-color 0.1s; - ${({ theme, runStatus, selected, isConnectable }) => { + background: ${({ theme, runStatus, selected }) => { const colors = getWorkflowDiagramColors({ theme, runStatus }); + return selected ? colors.selected.background : colors.unselected.background; + }}; - const background = selected - ? colors.selected.background - : colors.unselected.background; + border-color: ${({ theme, runStatus, selected }) => { + const colors = getWorkflowDiagramColors({ theme, runStatus }); + return selected + ? colors.selected.borderColor + : colors.unselected.borderColor; + }}; - return css` - background: ${background}; - border-color: ${selected + &:hover { + background: ${({ theme, runStatus, selected }) => { + const colors = getWorkflowDiagramColors({ theme, runStatus }); + const bg = selected + ? colors.selected.background + : colors.unselected.background; + return `linear-gradient(0deg, ${themeCssVariables.background.transparent.lighter} 0%, ${themeCssVariables.background.transparent.lighter} 100%), ${bg}`; + }}; + + border-color: ${({ theme, runStatus, selected, isConnectable }) => { + if (isConnectable === true) return themeCssVariables.color.blue; + const colors = getWorkflowDiagramColors({ theme, runStatus }); + return selected ? colors.selected.borderColor - : colors.unselected.borderColor}; - - &:hover { - background: linear-gradient( - 0deg, - ${theme.background.transparent.lighter} 0%, - ${theme.background.transparent.lighter} 100% - ), - ${background}; - - ${isConnectable && - css` - border-color: ${theme.color.blue} !important; - `}; - } - `; - }} + : colors.unselected.borderColor; + }}; + } `; export { StyledNodeContainer as WorkflowNodeContainer }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeIconContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeIconContainer.tsx index 35232724fbf..f34b3babefd 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeIconContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeIconContainer.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledNodeIconContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; border-radius: 4px; box-sizing: border-box; display: flex; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabel.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabel.tsx index 907e4562e47..4706a86f017 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabel.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabel.tsx @@ -1,23 +1,40 @@ +import { useContext } from 'react'; + import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow'; import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Label } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; -const StyledNodeLabel = styled(Label)<{ +type WorkflowNodeLabelProps = { runStatus?: WorkflowRunStepStatus; selected: boolean; -}>` + children?: React.ReactNode; + className?: string; +}; + +const StyledNodeLabelWrapper = styled.div<{ labelColor: string }>` box-sizing: border-box; flex: 1 0 0; - ${({ theme, runStatus, selected }) => { - const colors = getWorkflowDiagramColors({ theme, runStatus }); - - return css` - color: ${selected ? colors.selected.color : colors.unselected.color}; - `; - }} + > div { + color: ${({ labelColor }) => labelColor}; + } `; -export { StyledNodeLabel as WorkflowNodeLabel }; +export const WorkflowNodeLabel = ({ + runStatus, + selected, + children, + className, +}: WorkflowNodeLabelProps) => { + const { theme } = useContext(ThemeContext); + const colors = getWorkflowDiagramColors({ theme, runStatus }); + const labelColor = selected ? colors.selected.color : colors.unselected.color; + + return ( + + + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart.tsx index 844abc38df9..1013a8c598d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledNodeLabelWithCounterPart = styled.div` align-items: center; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart.tsx index aa67680d606..155713fdde1 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledNodeRightPart = styled.div` align-items: flex-start; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle.tsx index be0a9e47e8b..2d7fffcc6f0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle.tsx @@ -1,38 +1,29 @@ import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow'; import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; - +import { styled } from '@linaria/react'; +import type { ThemeType } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledNodeTitle = styled.div<{ + theme: ThemeType; highlight?: boolean; runStatus?: WorkflowRunStepStatus; selected: boolean; }>` - box-sizing: border-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; align-self: stretch; - display: -webkit-box; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - overflow: hidden; - text-overflow: ellipsis; - - ${({ theme, highlight, runStatus, selected }) => { + box-sizing: border-box; + color: ${({ theme, highlight, runStatus, selected }) => { const colors = getWorkflowDiagramColors({ theme, runStatus }); + if (highlight === true) return colors.selected.titleColor; + return selected ? colors.selected.titleColor : colors.unselected.titleColor; + }}; + display: -webkit-box; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; + overflow: hidden; - if (true === highlight) { - return css` - color: ${colors.selected.titleColor}; - `; - } - - return css` - color: ${selected - ? colors.selected.titleColor - : colors.unselected.titleColor}; - `; - }} + text-overflow: ellipsis; `; export { StyledNodeTitle as WorkflowNodeTitle }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx index d0b2429b27c..f9a20b683d3 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx @@ -23,8 +23,7 @@ import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-node import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle'; import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId'; import { getNodeIterationCount } from '@/workflow/workflow-diagram/workflow-nodes/utils/getNodeIterationCount'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Position } from '@xyflow/react'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useContext } from 'react'; @@ -32,15 +31,17 @@ import { capitalize, isDefined } from 'twenty-shared/utils'; import { StepStatus } from 'twenty-shared/workflow'; import { IconCheck, IconX, useIcons } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext, type ThemeType } from 'twenty-ui/theme'; const StyledNodeLabelWithCounterPart = styled(WorkflowNodeLabelWithCounterPart)` - column-gap: ${({ theme }) => theme.spacing(2)}; + column-gap: ${themeCssVariables.spacing[2]}; `; const StyledStatusIconsContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: flex-end; box-sizing: border-box; `; @@ -49,7 +50,7 @@ const StyledColorIcon = styled.div<{ color: string; }>` align-items: center; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; display: flex; height: 14px; @@ -59,22 +60,18 @@ const StyledColorIcon = styled.div<{ `; const StyledIterationCounter = styled.div<{ + theme: ThemeType; runStatus?: WorkflowRunStepStatus; }>` - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - - ${({ theme, runStatus }) => { - const colors = getWorkflowDiagramColors({ theme, runStatus }); - return css` - color: ${colors.unselected.color}; - `; - }} + color: ${({ theme, runStatus }) => + getWorkflowDiagramColors({ theme, runStatus }).unselected.color}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledRightPartContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const WorkflowRunDiagramStepNode = ({ @@ -85,7 +82,7 @@ export const WorkflowRunDiagramStepNode = ({ data: WorkflowRunDiagramStepNodeData; }) => { const { getIcon } = useIcons(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const workflowVisualizerWorkflowId = useAtomComponentStateValue( workflowVisualizerWorkflowIdComponentState, @@ -140,6 +137,7 @@ export const WorkflowRunDiagramStepNode = ({ <> {iterationCount > 0 && ( - + {iterationCount} )} @@ -189,7 +190,11 @@ export const WorkflowRunDiagramStepNode = ({ - + {data.name} diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer.tsx index 88c97ea0e86..52f3ff9ae20 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer.tsx @@ -1,4 +1,5 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledStepListContainer = styled.div` display: flex; @@ -6,8 +7,8 @@ const StyledStepListContainer = styled.div` height: 100%; overflow-y: auto; - padding-block: ${({ theme }) => theme.spacing(1)}; - padding-inline: ${({ theme }) => theme.spacing(2)}; + padding-block: ${themeCssVariables.spacing[1]}; + padding-inline: ${themeCssVariables.spacing[2]}; `; export { StyledStepListContainer as RightDrawerStepListContainer }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle.tsx index 43280c813af..5e8079d52c0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle.tsx @@ -1,13 +1,14 @@ -import styled from '@emotion/styled'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { styled } from '@linaria/react'; const StyledSelectStepTitle = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - padding-top: ${({ theme }) => theme.spacing(2)}; - padding-bottom: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(1)}; - padding-right: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + padding-top: ${themeCssVariables.spacing[2]}; + padding-bottom: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[1]}; + padding-right: ${themeCssVariables.spacing[1]}; `; export { StyledSelectStepTitle as RightDrawerWorkflowSelectStepTitle }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx index bd61776e481..91069ae4437 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx @@ -1,5 +1,5 @@ import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledWorkflowRunStepJsonContainer = styled(WorkflowStepBody)` grid-template-rows: max-content; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx index 18365953dea..04093415b57 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx @@ -1,18 +1,19 @@ import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; import { AppErrorDisplay } from '@/error-handler/components/internal/AppErrorDisplay'; import { type AppErrorDisplayProps } from '@/error-handler/types/AppErrorDisplayProps'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledWorkflowStepBody = styled.div` - background: ${({ theme }) => theme.background.primary}; + background: ${themeCssVariables.background.primary}; display: flex; flex: 1 1 auto; flex-direction: column; height: 100%; overflow-y: scroll; - padding-block: ${({ theme }) => theme.spacing(4)}; - padding-inline: ${({ theme }) => theme.spacing(3)}; - row-gap: ${({ theme }) => theme.spacing(4)}; + padding-block: ${themeCssVariables.spacing[4]}; + padding-inline: ${themeCssVariables.spacing[3]}; + row-gap: ${themeCssVariables.spacing[4]}; `; export const WorkflowStepBody = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton.tsx index 5b5b7163539..84f56b9e1fd 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterAddRootStepFilterButton.tsx @@ -1,13 +1,14 @@ import { useAddRootStepFilter } from '@/workflow/workflow-steps/filters/hooks/useAddRootStepFilter'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useContext } from 'react'; import { IconFilter } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledButton = styled(Button)` - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; export const WorkflowStepFilterAddRootStepFilterButton = () => { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn.tsx index 431ada294ee..e9f46d26de5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn.tsx @@ -5,9 +5,10 @@ import { WorkflowStepFilterOperandSelect } from '@/workflow/workflow-steps/filte import { WorkflowStepFilterOptionsDropdown } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterOptionsDropdown'; import { WorkflowStepFilterValueInput } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterValueInput'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useContext } from 'react'; import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowStepFilterColumnProps = { stepFilterGroup: StepFilterGroup; @@ -22,7 +23,7 @@ const StyledContainer = styled.div` display: flex; flex-direction: row; justify-content: space-between; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const WorkflowStepFilterColumn = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect.tsx index 4a83956f1fa..cfb975aa004 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterFieldSelect.tsx @@ -9,7 +9,6 @@ import { useAvailableVariablesInWorkflowStep } from '@/workflow/workflow-variabl import { useSearchVariable } from '@/workflow/workflow-variables/hooks/useSearchVariable'; import { type StepOutputSchemaV2 } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { useContext, useState } from 'react'; import { type StepFilter } from 'twenty-shared/types'; @@ -32,7 +31,6 @@ export const WorkflowStepFilterFieldSelect = ({ }: WorkflowStepFilterFieldSelectProps) => { const { readonly } = useContext(WorkflowStepFilterContext); const { t } = useLingui(); - const theme = useTheme(); const { closeDropdown } = useCloseDropdown(); const { getIcon } = useIcons(); @@ -153,8 +151,8 @@ export const WorkflowStepFilterFieldSelect = ({ } dropdownPlacement="bottom-end" dropdownOffset={{ - x: parseInt(theme.spacing(0.5), 10), - y: parseInt(theme.spacing(1), 10), + x: 2, + y: 4, }} /> ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupChildren.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupChildren.tsx index 3ed2dbd832b..3872d07d997 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupChildren.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupChildren.tsx @@ -2,21 +2,24 @@ import { WorkflowStepFilterAddFilterRuleSelect } from '@/workflow/workflow-steps import { WorkflowStepFilterColumn } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterColumn'; import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow-steps/filters/hooks/useChildStepFiltersAndChildStepFilterGroups'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ isGrayBackground?: boolean }>` align-items: start; - background-color: ${({ theme, isGrayBackground }) => - isGrayBackground ? theme.background.transparent.lighter : 'transparent'}; - border: ${({ theme }) => `1px solid ${theme.border.color.medium}`}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${({ isGrayBackground }) => + isGrayBackground + ? themeCssVariables.background.transparent.lighter + : 'transparent'}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[6]}; + padding: ${themeCssVariables.spacing[2]}; `; type WorkflowStepFilterGroupChildrenProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn.tsx index 3ed98a276fa..cd8cef76ae0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupColumn.tsx @@ -3,9 +3,10 @@ import { WorkflowStepFilterGroupChildren } from '@/workflow/workflow-steps/filte import { WorkflowStepFilterGroupOptionsDropdown } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterGroupOptionsDropdown'; import { WorkflowStepFilterLogicalOperatorCell } from '@/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useContext } from 'react'; import { type StepFilterGroup } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowStepFilterGroupColumnProps = { parentStepFilterGroup: StepFilterGroup; @@ -17,7 +18,7 @@ const StyledContainer = styled.div` display: flex; flex-direction: row; justify-content: space-between; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const WorkflowStepFilterGroupColumn = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell.tsx index 4c836220d49..1a5758498a3 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/filters/components/WorkflowStepFilterLogicalOperatorCell.tsx @@ -4,29 +4,30 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/filters/hooks/useUpsertStepFilterSettings'; import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useContext, useMemo } from 'react'; import { StepLogicalOperator, type StepFilterGroup } from 'twenty-shared/types'; import { capitalize, isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledText = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - height: ${({ theme }) => theme.spacing(8)}; + height: ${themeCssVariables.spacing[8]}; `; const StyledNumber = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; - margin-right: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.tertiary}; + margin-right: ${themeCssVariables.spacing[1]}; `; const StyledContainer = styled.div` align-items: start; display: flex; - min-width: ${({ theme }) => theme.spacing(20)}; - color: ${({ theme }) => theme.font.color.tertiary}; + min-width: ${themeCssVariables.spacing[20]}; + color: ${themeCssVariables.font.color.tertiary}; `; type WorkflowStepFilterLogicalOperatorCellProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsFlagRow.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsFlagRow.tsx index 0adba3a114e..2fa3678321a 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsFlagRow.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsFlagRow.tsx @@ -1,5 +1,4 @@ import { type SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/permission-flags/types/SettingsRolePermissionsSettingPermission'; -import { useTheme } from '@emotion/react'; import { IconTrash } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; import { @@ -9,6 +8,8 @@ import { StyledRowLeftContent, StyledText, } from './WorkflowAiAgentPermissionsStyles'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowAiAgentPermissionsFlagRowProps = { permission: SettingsRolePermissionsSettingPermission; @@ -27,7 +28,7 @@ export const WorkflowAiAgentPermissionsFlagRow = ({ onAdd, onDelete, }: WorkflowAiAgentPermissionsFlagRowProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const isClickable = !readonly && !isEnabled && Boolean(onAdd); const isDisabled = isEnabled && !showDeleteButton; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsObjectRow.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsObjectRow.tsx index e831156e272..9d9e14cca8f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsObjectRow.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsObjectRow.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@emotion/react'; import { useIcons } from 'twenty-ui/display'; import { StyledIconChevronRight, @@ -7,6 +6,8 @@ import { StyledRowLeftContent, StyledText, } from './WorkflowAiAgentPermissionsStyles'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowAiAgentPermissionsObjectRowProps = { objectMetadata: { @@ -23,7 +24,7 @@ export const WorkflowAiAgentPermissionsObjectRow = ({ onClick, readonly, }: WorkflowAiAgentPermissionsObjectRowProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const IconComponent = getIcon(objectMetadata.icon); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsStyles.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsStyles.ts index 3c65ce73b12..8653bb73cd2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsStyles.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsStyles.ts @@ -1,12 +1,14 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconChevronRight, Label } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export const StyledText = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; export const StyledLabel = styled(Label)` - margin: ${({ theme }) => theme.spacing(3, 3, 0)}; + margin: ${themeCssVariables.spacing[3]} ${themeCssVariables.spacing[3]} + ${themeCssVariables.spacing[0]}; `; export const StyledRow = styled.div<{ isDisabled?: boolean }>` @@ -14,16 +16,16 @@ export const StyledRow = styled.div<{ isDisabled?: boolean }>` display: flex; justify-content: space-between; width: 100%; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; box-sizing: border-box; - border-radius: ${({ theme }) => theme.spacing(1)}; + border-radius: ${themeCssVariables.spacing[1]}; cursor: ${({ isDisabled }) => (isDisabled ? 'not-allowed' : 'pointer')}; opacity: ${({ isDisabled }) => (isDisabled ? 0.5 : 1)}; pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')}; :hover { - background-color: ${({ theme, isDisabled }) => - isDisabled ? 'inherit' : theme.background.transparent.light}; + background-color: ${({ isDisabled }) => + isDisabled ? 'inherit' : themeCssVariables.background.transparent.light}; } :hover [data-delete-button] { @@ -33,32 +35,32 @@ export const StyledRow = styled.div<{ isDisabled?: boolean }>` export const StyledDeleteButton = styled.div` opacity: 0; - transition: opacity ${({ theme }) => theme.animation.duration.fast}ms; + transition: opacity ${themeCssVariables.animation.duration.fast}ms; `; export const StyledRowLeftContent = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const StyledList = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[0.5]}; + padding: ${themeCssVariables.spacing[2]}; `; export const StyledIconContainer = styled.div` - background-color: ${({ theme }) => theme.background.tertiary}; - padding: ${({ theme }) => theme.spacing(1)}; - border-radius: ${({ theme }) => theme.spacing(1)}; + background-color: ${themeCssVariables.background.tertiary}; + padding: ${themeCssVariables.spacing[1]}; + border-radius: ${themeCssVariables.spacing[1]}; display: flex; justify-content: center; align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export const StyledIconChevronRight = styled(IconChevronRight)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsTab.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsTab.tsx index 148c70e3e15..31e67a5d12e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsTab.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowAiAgentPermissionsTab.tsx @@ -8,7 +8,7 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState import { workflowAiAgentActionAgentState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/workflowAiAgentActionAgentState'; import { workflowAiAgentPermissionsIsAddingPermissionState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/workflowAiAgentPermissionsIsAddingPermissionState'; import { workflowAiAgentPermissionsSelectedObjectIdState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/workflowAiAgentPermissionsSelectedObjectIdState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -25,10 +25,11 @@ import { WorkflowAiAgentPermissionsCrudList } from './WorkflowAiAgentPermissions import { WorkflowAiAgentPermissionsFlagList } from './WorkflowAiAgentPermissionsFlagList'; import { WorkflowAiAgentPermissionsObjectsList } from './WorkflowAiAgentPermissionsObjectsList'; import { getFilteredPermissions } from './workflowAiAgentPermissions.utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSearchInput = styled(TextInput)` width: 100%; height: 40px; - border-block: 1px solid ${({ theme }) => theme.border.color.medium}; + border-block: 1px solid ${themeCssVariables.border.color.medium}; input { height: 40px; line-height: 40px; @@ -39,7 +40,7 @@ const StyledSearchInput = styled(TextInput)` `; const StyledBackButtonText = styled.span` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; const StyledBackButton = styled.button` @@ -47,15 +48,15 @@ const StyledBackButton = styled.button` align-items: center; background: none; border: none; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[3]}; text-align: left; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx index 5b5874d4523..2785cad9e64 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx @@ -16,7 +16,7 @@ import { WORKFLOW_AI_AGENT_TABS } from '@/workflow/workflow-steps/workflow-actio import { useResetWorkflowAiAgentPermissionsStateOnCommandMenuClose } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/hooks/useResetWorkflowAiAgentPermissionsStateOnCommandMenuClose'; import { workflowAiAgentActionAgentState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/workflowAiAgentActionAgentState'; import { workflowAiAgentPermissionsIsAddingPermissionState } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/states/workflowAiAgentPermissionsIsAddingPermissionState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { @@ -35,6 +35,7 @@ import { import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { RightDrawerSkeletonLoader } from '~/loading/components/RightDrawerSkeletonLoader'; import { WorkflowAiAgentPromptTab } from './WorkflowAiAgentPromptTab'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type WorkflowAiAgentTabId = (typeof WORKFLOW_AI_AGENT_TABS)[keyof typeof WORKFLOW_AI_AGENT_TABS]; @@ -50,8 +51,8 @@ type WorkflowEditActionAiAgentProps = { }; const StyledTabList = styled(TabList)` - background-color: ${({ theme }) => theme.background.secondary}; - padding-left: ${({ theme }) => theme.spacing(2)}; + background-color: ${themeCssVariables.background.secondary}; + padding-left: ${themeCssVariables.spacing[2]}; `; const StyledPermissionsStepBody = styled(WorkflowStepBody)` diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowOutputSchemaBuilder.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowOutputSchemaBuilder.tsx index 12865657530..a2b170fd34e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowOutputSchemaBuilder.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowOutputSchemaBuilder.tsx @@ -3,13 +3,15 @@ import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/c import { type OutputSchemaField } from '@/ai/constants/OutputFieldTypeOptions'; import { InputLabel } from '@/ui/input/components/InputLabel'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconPlus, IconTrash } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; import { v4 } from 'uuid'; import { WorkflowOutputFieldTypeSelector } from './WorkflowOutputFieldTypeSelector'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowOutputSchemaBuilderProps = { fields: OutputSchemaField[]; @@ -25,80 +27,80 @@ const StyledOutputSchemaContainer = styled.div` const StyledFieldsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledOutputSchemaFieldContainer = styled.div` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledSettingsContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledSettingsHeader = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: grid; - gap: ${({ theme }) => theme.spacing(1)}; - padding-right: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + padding-right: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[3]}; grid-template-columns: 1fr 24px; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledTitleContainer = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + padding-top: ${themeCssVariables.spacing[3]}; `; const StyledCloseButtonContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; `; const StyledAddFieldButton = styled.button` align-items: center; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.secondary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; display: flex; font-family: inherit; - font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(1)}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[1]}; justify-content: center; - margin-top: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[2]}; width: 100%; - background-color: ${({ theme }) => theme.background.transparent.lighter}; + background-color: ${themeCssVariables.background.transparent.lighter}; &:hover { - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } `; const StyledMessageContentContainer = styled.div` flex-direction: column; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; - padding: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; + padding: ${themeCssVariables.spacing[4]}; line-height: normal; `; const StyledMessageDescription = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + color: ${themeCssVariables.font.color.secondary}; + font-weight: ${themeCssVariables.font.weight.regular}; `; export const WorkflowOutputSchemaBuilder = ({ @@ -106,7 +108,7 @@ export const WorkflowOutputSchemaBuilder = ({ onChange, readonly, }: WorkflowOutputSchemaBuilderProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const addField = () => { const newField: OutputSchemaField = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor.tsx index c01167c26a0..e61c0b37fc3 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor.tsx @@ -1,10 +1,11 @@ import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { type Monaco } from '@monaco-editor/react'; import { type editor } from 'monaco-editor'; import { IconMaximize } from 'twenty-ui/display'; import { CodeEditor, LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const CODE_EDITOR_MIN_HEIGHT = 343; @@ -19,8 +20,8 @@ const StyledCodeEditorContainer = styled.div` const StyledFullScreenButtonContainer = styled.div` position: absolute; - top: ${({ theme }) => theme.spacing(2)}; - right: ${({ theme }) => theme.spacing(2)}; + top: ${themeCssVariables.spacing[2]}; + right: ${themeCssVariables.spacing[2]}; z-index: 1; `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx index 31be6a11552..8e5e6b42934 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCode.tsx @@ -28,7 +28,7 @@ import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/work import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId'; import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; @@ -48,6 +48,7 @@ import { CodeEditor } from 'twenty-ui/input'; import { useIsMobile } from 'twenty-ui/utilities'; import { useDebouncedCallback } from 'use-debounce'; import { getFunctionInputFromInputSchema } from 'twenty-shared/workflow'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const CODE_EDITOR_MIN_HEIGHT = 343; @@ -61,8 +62,8 @@ const StyledCodeEditorContainer = styled.div` `; const StyledTabList = styled(TabList)` - background-color: ${({ theme }) => theme.background.secondary}; - padding-left: ${({ theme }) => theme.spacing(2)}; + background-color: ${themeCssVariables.background.secondary}; + padding-left: ${themeCssVariables.spacing[2]}; `; const StyledFullScreenCodeEditorContainer = styled.div` diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields.tsx index b4e45ad04e4..ee6cee406bb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields.tsx @@ -3,13 +3,14 @@ import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/c import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { type FunctionInput } from 'twenty-shared/workflow'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isObject } from '@sniptt/guards'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div<{ fullWidth?: boolean }>` display: flex; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; flex-wrap: wrap; > * { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionCode.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionCode.tsx index 492fafc1ec4..3b240a6b683 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionCode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionCode.tsx @@ -5,7 +5,7 @@ import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLog import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields'; import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type Monaco } from '@monaco-editor/react'; import { type editor } from 'monaco-editor'; import { AutoTypings } from 'monaco-editor-auto-typings'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx index 603793db258..96a053266cd 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx @@ -12,7 +12,6 @@ import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowS import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; import { useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow'; @@ -66,8 +65,6 @@ export const WorkflowEditActionCreateRecord = ({ action, actionOptions, }: WorkflowEditActionCreateRecordProps) => { - const theme = useTheme(); - const { getIcon } = useIcons(); const { activeNonSystemObjectMetadataItems } = @@ -218,7 +215,7 @@ export const WorkflowEditActionCreateRecord = ({ saveAction(newFormData); }} withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord.tsx index 122c1b903c1..8cc097afac8 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord.tsx @@ -9,7 +9,6 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; import { isDefined } from 'twenty-shared/utils'; import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow'; import { HorizontalSeparator, useIcons } from 'twenty-ui/display'; @@ -38,8 +37,6 @@ export const WorkflowEditActionDeleteRecord = ({ action, actionOptions, }: WorkflowEditActionDeleteRecordProps) => { - const theme = useTheme(); - const { getIcon } = useIcons(); const { activeNonSystemObjectMetadataItems } = @@ -136,7 +133,7 @@ export const WorkflowEditActionDeleteRecord = ({ saveAction(newFormData); }} withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx index 79038208dbd..388b39b4ee0 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmailBase.tsx @@ -24,7 +24,6 @@ import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowS import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; import { useEmailForm } from '@/workflow/workflow-steps/workflow-actions/hooks/useEmailForm'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useEffect, useState } from 'react'; @@ -56,7 +55,6 @@ export const WorkflowEditActionEmailBase = ({ action, actionOptions, }: WorkflowEditActionEmailBaseProps) => { - const theme = useTheme(); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); const { triggerApisOAuth } = useTriggerApisOAuth(); const { enqueueErrorSnackBar } = useSnackBar(); @@ -242,7 +240,7 @@ export const WorkflowEditActionEmailBase = ({ handleConnectedAccountChange(connectedAccountId); }} disabled={actionOptions.readonly} - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> {isDefined(missingScopes) && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx index 19590d607e2..1dce72e0a0c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord.tsx @@ -12,7 +12,6 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { type UpdateRecordFormData } from '@/workflow/workflow-steps/workflow-actions/types/update-record-form-data.type'; import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -39,8 +38,6 @@ export const WorkflowEditActionUpdateRecord = ({ action, actionOptions, }: WorkflowEditActionUpdateRecordProps) => { - const theme = useTheme(); - const { getIcon } = useIcons(); const { activeNonSystemObjectMetadataItems } = @@ -169,7 +166,7 @@ export const WorkflowEditActionUpdateRecord = ({ saveAction(newFormData); }} withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpsertRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpsertRecord.tsx index 7b1d749aa94..7d10b523c3b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpsertRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpsertRecord.tsx @@ -13,7 +13,6 @@ import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowS import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -76,8 +75,6 @@ export const WorkflowEditActionUpsertRecord = ({ action, actionOptions, }: WorkflowEditActionUpsertRecordProps) => { - const theme = useTheme(); - const { getIcon } = useIcons(); const { activeNonSystemObjectMetadataItems } = @@ -235,7 +232,7 @@ export const WorkflowEditActionUpsertRecord = ({ saveAction(newFormData); }} withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx index e1b06ba5577..ee8d8454b15 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBody.tsx @@ -11,26 +11,27 @@ import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/sta import { rootLevelStepFilterGroupComponentSelector } from '@/workflow/workflow-steps/filters/states/rootLevelStepFilterGroupComponentSelector'; import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings'; import { isStepFilterGroupChildAStepFilterGroup } from '@/workflow/workflow-steps/filters/utils/isStepFilterGroupChildAStepFilterGroup'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: start; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledChildContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[6]}; width: 100%; `; const StyledFilterBodyContainer = styled(WorkflowStepBody)` - gap: ${({ theme }) => theme.spacing(0)}; + gap: ${themeCssVariables.spacing[0]}; `; type WorkflowEditActionFilterBodyProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx index cc24f029809..fcb5facd435 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx @@ -1,5 +1,4 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { msg } from '@lingui/core/macro'; import { i18n } from '@lingui/core'; import { useLingui } from '@lingui/react/macro'; @@ -33,13 +32,14 @@ import { WorkflowFindRecordsFilters } from '@/workflow/workflow-steps/workflow-a import { WorkflowFindRecordsFiltersEffect } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect'; import { WorkflowFindRecordsSorts } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts'; import { WorkflowObjectDropdownContent } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowObjectDropdownContent'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: block; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledRecordTypeSelectContainer = styled.div<{ fullWidth?: boolean }>` @@ -81,7 +81,6 @@ export const WorkflowEditActionFindRecords = ({ action, actionOptions, }: WorkflowEditActionFindRecordsProps) => { - const theme = useTheme(); const { t } = useLingui(); const maxRecordsFormatted = QUERY_MAX_RECORDS.toLocaleString(); @@ -202,7 +201,7 @@ export const WorkflowEditActionFindRecords = ({ /> ) } - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx index b47df036e0b..1d4609f39a8 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsSorts.tsx @@ -2,27 +2,28 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { filterSortableFieldMetadataItems } from '@/object-metadata/utils/filterSortableFieldMetadataItems'; import { type RecordSort } from '@/object-record/record-sort/types/RecordSort'; import { Select } from '@/ui/input/components/Select'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { IconArrowsSort, IconTrash, useIcons } from 'twenty-ui/display'; import { Button, type SelectOption } from 'twenty-ui/input'; import { v4 as uuidv4 } from 'uuid'; import { ViewSortDirection } from '~/generated-metadata/graphql'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledSortItemContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledAddButtonContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(1)}; + margin-top: ${themeCssVariables.spacing[1]}; `; type WorkflowFindRecordsSortsProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx index f6907854568..20be88f7d14 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx @@ -14,12 +14,11 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { WorkflowEditActionFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type OnDragEndResponder } from '@hello-pangea/dnd'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { @@ -33,6 +32,8 @@ import { import { LightIconButton } from 'twenty-ui/input'; import { useDebouncedCallback } from 'use-debounce'; import { v4 } from 'uuid'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export type WorkflowEditActionFormBuilderProps = { triggerType: WorkflowTriggerType | undefined; @@ -51,13 +52,13 @@ type FormData = WorkflowFormActionField[]; const StyledWorkflowStepBody = styled(WorkflowStepBody)` display: block; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; `; const StyledFormFieldContainer = styled.div` align-items: flex-end; - column-gap: ${({ theme }) => theme.spacing(1)}; + column-gap: ${themeCssVariables.spacing[1]}; display: grid; grid-template-areas: 'grip input delete' @@ -68,19 +69,19 @@ const StyledFormFieldContainer = styled.div` const StyledDraggingIndicator = styled.div` position: absolute; - inset: ${({ theme }) => theme.spacing(-2)}; - top: ${({ theme }) => theme.spacing(-1)}; - background-color: ${({ theme }) => theme.background.transparent.light}; + inset: -8px; + top: -4px; + background-color: ${themeCssVariables.background.transparent.light}; `; const StyledLightGripIconButton = styled(LightIconButton)` grid-area: grip; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledLightTrashIconButton = styled(LightIconButton)` grid-area: delete; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledFormFieldInputContainer = styled(FormFieldInputContainer)` @@ -99,20 +100,19 @@ const StyledFieldContainer = styled.div<{ border: none; display: flex; font-family: inherit; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; width: 100%; cursor: ${({ readonly }) => (readonly ? 'default' : 'pointer')}; - ${({ readonly, theme }) => - !readonly && - css` - &:hover, - &[data-open='true'] { - background-color: ${theme.background.transparent.lighter}; - } - `} + &:hover, + &[data-open='true'] { + background-color: ${({ readonly }) => + readonly + ? 'transparent' + : themeCssVariables.background.transparent.lighter}; + } `; const StyledPlaceholder = styled(FormFieldPlaceholder)` @@ -120,30 +120,30 @@ const StyledPlaceholder = styled(FormFieldPlaceholder)` `; const StyledAddFieldButtonContainer = styled.div` - padding-left: ${({ theme }) => theme.spacing(7)}; - padding-right: ${({ theme }) => theme.spacing(7)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-left: ${themeCssVariables.spacing[7]}; + padding-right: ${themeCssVariables.spacing[7]}; + padding-top: ${themeCssVariables.spacing[2]}; `; const StyledAddFieldButtonContentContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; display: flex; - font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(0.5)}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[0.5]}; justify-content: center; width: 100%; `; const StyledCalloutContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(7)}; - padding-right: ${({ theme }) => theme.spacing(7)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[7]}; + padding-right: ${themeCssVariables.spacing[7]}; + padding-top: ${themeCssVariables.spacing[2]}; `; const StyledNotClosableCalloutContainer = styled(StyledCalloutContainer)` - padding-bottom: ${({ theme }) => theme.spacing(4)}; + padding-bottom: ${themeCssVariables.spacing[4]}; `; export const WorkflowEditActionFormBuilder = ({ @@ -151,7 +151,7 @@ export const WorkflowEditActionFormBuilder = ({ action, actionOptions, }: WorkflowEditActionFormBuilderProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); const [formData, setFormData] = useState(action.settings.input); @@ -278,7 +278,7 @@ export const WorkflowEditActionFormBuilder = ({ isInsideScrollableContainer disableDraggingBackground draggableComponentStyles={{ - marginBottom: theme.spacing(4), + marginBottom: themeCssVariables.spacing[4], }} itemComponent={({ isDragging }) => { const showButtons = diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings.tsx index 24311ac2cbf..32e7af8a3ec 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFieldSettings.tsx @@ -6,11 +6,13 @@ import { FORM_SELECT_FIELD_TYPE_OPTIONS } from '@/workflow/workflow-steps/workfl import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { type WorkflowFormFieldType } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormFieldType'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconSettingsAutomation, IconX } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowEditActionFormFieldSettingsProps = { field: WorkflowFormActionField; @@ -19,42 +21,42 @@ type WorkflowEditActionFormFieldSettingsProps = { }; const StyledFormFieldSettingsContainer = styled.div` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; - margin-top: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + margin-top: ${themeCssVariables.spacing[3]}; `; const StyledSettingsContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledSettingsHeader = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: grid; - gap: ${({ theme }) => theme.spacing(1)}; - padding-right: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + padding-right: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[3]}; grid-template-columns: 1fr 24px; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledTitleContainer = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[1]}; + padding-top: ${themeCssVariables.spacing[3]}; `; const StyledCloseButtonContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; `; export const WorkflowEditActionFormFieldSettings = ({ @@ -62,7 +64,7 @@ export const WorkflowEditActionFormFieldSettings = ({ onChange, onClose, }: WorkflowEditActionFormFieldSettingsProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsNumber.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsNumber.tsx index 3226e8912dd..ca91d644afd 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsNumber.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsNumber.tsx @@ -4,9 +4,10 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import camelCase from 'lodash.camelcase'; import { FieldMetadataType } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowFormFieldSettingsNumberProps = { field: WorkflowFormActionField; @@ -16,7 +17,7 @@ type WorkflowFormFieldSettingsNumberProps = { const StyledContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const WorkflowFormFieldSettingsNumber = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsRecordPicker.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsRecordPicker.tsx index e9d1663839a..3c7f89786fe 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsRecordPicker.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsRecordPicker.tsx @@ -6,12 +6,12 @@ import { Select } from '@/ui/input/components/Select'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import camelCase from 'lodash.camelcase'; import { useIcons } from 'twenty-ui/display'; import { type SelectOption } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowFormFieldSettingsRecordPickerProps = { field: WorkflowFormActionField; @@ -21,15 +21,13 @@ type WorkflowFormFieldSettingsRecordPickerProps = { const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const WorkflowFormFieldSettingsRecordPicker = ({ field, onChange, }: WorkflowFormFieldSettingsRecordPickerProps) => { - const theme = useTheme(); - const { getIcon } = useIcons(); const { activeNonSystemObjectMetadataItems } = @@ -67,7 +65,7 @@ export const WorkflowFormFieldSettingsRecordPicker = ({ }); }} withSearchInput - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsSelect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsSelect.tsx index c5b1fd1e75b..0f662fddf8b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsSelect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsSelect.tsx @@ -7,9 +7,10 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import camelCase from 'lodash.camelcase'; import { FieldMetadataType } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowFormFieldSettingsSelectProps = { field: WorkflowFormActionField; @@ -19,13 +20,13 @@ type WorkflowFormFieldSettingsSelectProps = { const StyledFormFieldSettingsSelect = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledRowContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const WorkflowFormFieldSettingsSelect = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsText.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsText.tsx index 9ce09e2515a..2b6125ee237 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsText.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowFormFieldSettingsText.tsx @@ -4,9 +4,10 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import camelCase from 'lodash.camelcase'; import { FieldMetadataType } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowFormFieldSettingsTextProps = { field: WorkflowFormActionField; @@ -16,7 +17,7 @@ type WorkflowFormFieldSettingsTextProps = { const StyledContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const WorkflowFormFieldSettingsText = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow.ts index 7e3e44100f7..6b37c884ceb 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow.ts @@ -1,9 +1,10 @@ import { type WorkflowActionType } from '@/workflow/types/Workflow'; import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow'; -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const useActionIconColorOrThrow = (actionType: WorkflowActionType) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return getActionIconColorOrThrow({ theme, actionType }); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/BodyInput.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/BodyInput.tsx index d0c247ad51f..437037fec53 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/BodyInput.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/BodyInput.tsx @@ -13,7 +13,7 @@ import { import { getBodyTypeFromHeaders } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getBodyTypeFromHeaders'; import { parseHttpJsonBodyWithoutVariablesOrThrow } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/parseHttpJsonBodyWithoutVariablesOrThrow'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isString } from '@sniptt/guards'; import { useState } from 'react'; import { isDefined, parseJson } from 'twenty-shared/utils'; @@ -24,20 +24,21 @@ import { import { IconFileText, IconKey } from 'twenty-ui/display'; import { type JsonValue } from 'type-fest'; import { KeyValuePairInput } from './KeyValuePairInput'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledSelectDropdown = styled(Select)` - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledNoBodyMessage = styled.div` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.md}; - padding: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.md}; + padding: ${themeCssVariables.spacing[2]}; text-align: left; `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/HttpRequestTestVariableInput.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/HttpRequestTestVariableInput.tsx index 7323c383907..4731e634cf7 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/HttpRequestTestVariableInput.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/HttpRequestTestVariableInput.tsx @@ -7,12 +7,13 @@ import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAto import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState'; import { httpRequestTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/http-request-action/states/httpRequestTestDataFamilyState'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledVariableInputsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; type HttpRequestTestVariableInputProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/KeyValuePairInput.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/KeyValuePairInput.tsx index d534dbca62a..b7f8ac01968 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/KeyValuePairInput.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/KeyValuePairInput.tsx @@ -4,32 +4,28 @@ import { InputLabel } from '@/ui/input/components/InputLabel'; import { AUTO_SET_HEADER_KEYS } from '@/workflow/workflow-steps/workflow-actions/http-request-action/constants/AutoSetHeaderKeys'; import { isAutoSetHeaderKey } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/isReadOnlyHeaderKey'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { css } from '@emotion/react'; import { t } from '@lingui/core/macro'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useState } from 'react'; import { IconTrash } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { v4 } from 'uuid'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledKeyValueContainer = styled.div<{ readonly: boolean | undefined }>` display: grid; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; - ${({ readonly, theme }) => + grid-template-columns: ${({ readonly }) => readonly - ? css` - grid-template-columns: repeat(2, minmax(0, 1fr)); - ` - : css` - grid-template-columns: repeat(2, minmax(0, 1fr)) ${theme.spacing(8)}; - `}; + ? 'repeat(2, minmax(0, 1fr))' + : `repeat(2, minmax(0, 1fr)) ${themeCssVariables.spacing[8]}`}; `; export type KeyValuePair = { id: string; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx index 3b6c72b8ca2..514121b5880 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx @@ -13,10 +13,9 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { getBodyTypeFromHeaders } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/getBodyTypeFromHeaders'; import { isMethodWithBody } from '@/workflow/workflow-steps/workflow-actions/http-request-action/utils/isMethodWithBody'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useEffect } from 'react'; +import { useContext, useEffect } from 'react'; import { IconPlayerPlay, IconSettings } from 'twenty-ui/display'; import { HTTP_METHODS, @@ -31,6 +30,8 @@ import { BodyInput } from './BodyInput'; import { HttpRequestExecutionResult } from './HttpRequestExecutionResult'; import { HttpRequestTestVariableInput } from './HttpRequestTestVariableInput'; import { KeyValuePairInput } from './KeyValuePairInput'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowEditActionHttpRequestProps = { action: WorkflowHttpRequestAction; @@ -41,15 +42,15 @@ type WorkflowEditActionHttpRequestProps = { }; const StyledTabList = styled(TabList)` - background-color: ${({ theme }) => theme.background.secondary}; - padding-left: ${({ theme }) => theme.spacing(2)}; + background-color: ${themeCssVariables.background.secondary}; + padding-left: ${themeCssVariables.spacing[2]}; `; const StyledTestTabContent = styled.div` display: flex; flex-direction: column; flex: 1; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; height: 100%; min-height: 400px; `; @@ -57,7 +58,7 @@ const StyledTestTabContent = styled.div` const StyledConfigurationTabContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; height: 100%; flex: 1; `; @@ -89,7 +90,7 @@ export const WorkflowEditActionHttpRequest = ({ actionOptions, }: WorkflowEditActionHttpRequestProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const activeTabId = useAtomComponentStateValue( activeTabIdComponentState, WORKFLOW_HTTP_REQUEST_TAB_LIST_COMPONENT_ID, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/__stories__/WorkflowEditActionHttpRequest.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/__stories__/WorkflowEditActionHttpRequest.stories.tsx index c2a35727836..b822788aa97 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/__stories__/WorkflowEditActionHttpRequest.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/__stories__/WorkflowEditActionHttpRequest.stories.tsx @@ -117,8 +117,7 @@ export const Configured: Story = { const canvas = within(canvasElement); const urlLabel = await canvas.findByText('URL'); - const urlInputContainer = urlLabel.closest('div')?.nextElementSibling; - const urlEditor = urlInputContainer?.querySelector('.ProseMirror'); + const urlEditor = urlLabel.parentElement?.querySelector('.ProseMirror'); expect(urlEditor).toBeVisible(); expect(urlEditor).toHaveTextContent('https://api.example.com/data'); @@ -138,8 +137,7 @@ export const ReadOnly: Story = { const canvas = within(canvasElement); const urlLabel = await canvas.findByText('URL'); - const urlInputContainer = urlLabel.closest('div')?.nextElementSibling; - const urlEditor = urlInputContainer?.querySelector('.ProseMirror'); + const urlEditor = urlLabel.parentElement?.querySelector('.ProseMirror'); expect(urlEditor).toBeVisible(); expect(urlEditor).toHaveTextContent('https://api.example.com/data'); expect(urlEditor).toHaveAttribute('contenteditable', 'false'); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx index 10b5ab20c9d..5758c39faf4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx @@ -22,23 +22,24 @@ import { getBranchesToDelete } from '@/workflow/workflow-steps/workflow-actions/ import { getBranchLabel } from '@/workflow/workflow-steps/workflow-actions/if-else-action/utils/getBranchLabel'; import { useStepsOutputSchema } from '@/workflow/workflow-variables/hooks/useStepsOutputSchema'; import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { Fragment } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type StepIfElseBranch } from 'twenty-shared/workflow'; import { HorizontalSeparator, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: start; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; const StyledBodyContainer = styled(WorkflowStepBody)` - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; type WorkflowEditActionIfElseBodyProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowIfElseBranchEditor.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowIfElseBranchEditor.tsx index 658088badd2..3f6d4257735 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowIfElseBranchEditor.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowIfElseBranchEditor.tsx @@ -6,23 +6,24 @@ import { useChildStepFiltersAndChildStepFilterGroups } from '@/workflow/workflow import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/filters/states/context/WorkflowStepFilterContext'; import { type FilterSettings } from '@/workflow/workflow-steps/filters/types/FilterSettings'; import { isStepFilterGroupChildAStepFilterGroup } from '@/workflow/workflow-steps/filters/utils/isStepFilterGroupChildAStepFilterGroup'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { i18n, type MessageDescriptor } from '@lingui/core'; import { type StepFilter, type StepFilterGroup } from 'twenty-shared/types'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { type StepIfElseBranch } from 'twenty-shared/workflow'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledBranchContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; width: 100%; `; const StyledFiltersContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; width: 100%; `; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx index e78777a6af7..6c652863b67 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowIteratorSubStepSwitcher.tsx @@ -6,23 +6,24 @@ import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThro import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow'; import { getIsDescendantOfIterator } from '@/workflow/workflow-steps/utils/getIsDescendantOfIterator'; import { getWorkflowRunAllStepInfoHistory } from '@/workflow/workflow-steps/utils/getWorkflowRunAllStepInfoHistory'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { plural } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronLeft, IconChevronRight } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; align-items: center; justify-content: space-between; - padding-block: ${({ theme }) => theme.spacing(2)}; - padding-inline: ${({ theme }) => theme.spacing(3)}; + padding-block: ${themeCssVariables.spacing[2]}; + padding-inline: ${themeCssVariables.spacing[3]}; `; const StyledCounter = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.tertiary}; + font-weight: ${themeCssVariables.font.weight.medium}; `; export const WorkflowIteratorSubStepSwitcher = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/logic-function-action/components/WorkflowEditActionLogicFunction.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/logic-function-action/components/WorkflowEditActionLogicFunction.tsx index 5a2a2689035..c33752df832 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/logic-function-action/components/WorkflowEditActionLogicFunction.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/logic-function-action/components/WorkflowEditActionLogicFunction.tsx @@ -7,18 +7,19 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields'; import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/setNestedValue'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { isObject } from '@sniptt/guards'; import { useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { Callout } from 'twenty-ui/display'; import { useDebouncedCallback } from 'use-debounce'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; type WorkflowEditActionLogicFunctionProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts index 617b0349401..76f2b634057 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts @@ -1,9 +1,8 @@ import { type WorkflowActionType } from '@/workflow/types/Workflow'; -import { type Theme } from '@emotion/react'; -import { COLOR_LIGHT, GRAY_SCALE_LIGHT } from 'twenty-ui/theme'; +import { COLOR_LIGHT, GRAY_SCALE_LIGHT, type ThemeType } from 'twenty-ui/theme'; import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow'; -const mockTheme: Theme = { +const mockTheme: ThemeType = { color: { orange: COLOR_LIGHT.orange, pink: COLOR_LIGHT.pink, @@ -14,7 +13,7 @@ const mockTheme: Theme = { tertiary: GRAY_SCALE_LIGHT.gray9, }, }, -} as Theme; +} as ThemeType; describe('getActionIconColorOrThrow', () => { describe('action types that return red color', () => { @@ -91,7 +90,7 @@ describe('getActionIconColorOrThrow', () => { describe('theme object handling', () => { it('should use the provided theme colors correctly', () => { - const customTheme: Theme = { + const customTheme: ThemeType = { color: { red: COLOR_LIGHT.red, orange: COLOR_LIGHT.orange, @@ -102,7 +101,7 @@ describe('getActionIconColorOrThrow', () => { tertiary: GRAY_SCALE_LIGHT.gray11, }, }, - } as Theme; + } as ThemeType; expect( getActionIconColorOrThrow({ @@ -229,7 +228,7 @@ describe('getActionIconColorOrThrow', () => { }); it('should use the provided theme colors correctly', () => { - const customTheme: Theme = { + const customTheme: ThemeType = { color: { red: COLOR_LIGHT.red, orange: COLOR_LIGHT.orange, @@ -240,7 +239,7 @@ describe('getActionIconColorOrThrow', () => { tertiary: GRAY_SCALE_LIGHT.gray11, }, }, - } as Theme; + } as ThemeType; expect( getActionIconColorOrThrow({ theme: customTheme, actionType: 'CODE' }), @@ -266,7 +265,7 @@ describe('getActionIconColorOrThrow', () => { }); it('should return undefined when red color is missing for SEND_EMAIL action', () => { - const themeWithoutBlue: Theme = { + const themeWithoutBlue: ThemeType = { color: { orange: COLOR_LIGHT.orange, pink: COLOR_LIGHT.pink, @@ -276,7 +275,7 @@ describe('getActionIconColorOrThrow', () => { tertiary: GRAY_SCALE_LIGHT.gray9, }, }, - } as Theme; + } as ThemeType; expect( getActionIconColorOrThrow({ @@ -289,7 +288,7 @@ describe('getActionIconColorOrThrow', () => { it('should handle null theme gracefully', () => { expect(() => { getActionIconColorOrThrow({ - theme: null as unknown as Theme, + theme: null as unknown as ThemeType, actionType: 'CODE', }); }).toThrow(); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts index 1bd5bd1d008..3561bb50156 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts @@ -1,12 +1,12 @@ import { type WorkflowActionType } from '@/workflow/types/Workflow'; -import { type Theme } from '@emotion/react'; import { assertUnreachable } from 'twenty-shared/utils'; +import { type ThemeType } from 'twenty-ui/theme'; export const getActionIconColorOrThrow = ({ theme, actionType, }: { - theme: Theme; + theme: ThemeType; actionType: WorkflowActionType; }) => { switch (actionType) { diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx index 652f6751cf3..f79a8bd0170 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/CronExpressionHelper.tsx @@ -6,11 +6,12 @@ import { convertScheduleToCronExpression } from '@/workflow/workflow-trigger/uti import { normalizeCronExpression } from '@/workflow/workflow-trigger/utils/cron-to-human/utils/normalizeCronExpression'; import { getTriggerScheduleDescription } from '@/workflow/workflow-trigger/utils/getTriggerScheduleDescription'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { CronExpressionParser } from 'cron-parser'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { formatDateTimeString } from '~/utils/string/formatDateTimeString'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const getNextExecutions = ( cronExpression: string, @@ -44,39 +45,39 @@ const getNextExecutions = ( const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; - margin-top: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[3]}; + margin-top: ${themeCssVariables.spacing[2]}; `; const StyledSection = styled.div` - background-color: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.sm}; box-sizing: border-box; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[3]} ${themeCssVariables.spacing[4]}; `; const StyledScheduleDescription = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledScheduleTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledExecutionItem = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-top: ${({ theme }) => theme.spacing(0.5)}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-top: ${themeCssVariables.spacing[0.5]}; `; type CronExpressionHelperProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx index c59b7dfd5c8..1da98da953e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx @@ -15,21 +15,21 @@ import { type WorkflowDatabaseEventTrigger } from '@/workflow/types/Workflow'; import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { useCallback, useMemo, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { IconChevronLeft, IconSettings, useIcons } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: block; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledRecordTypeSelectContainer = styled.div<{ fullWidth?: boolean }>` @@ -63,7 +63,6 @@ export const WorkflowEditTriggerDatabaseEventForm = ({ trigger, triggerOptions, }: WorkflowEditTriggerDatabaseEventFormProps) => { - const theme = useTheme(); const { getIcon } = useIcons(); const { t } = useLingui(); const [searchInputValue, setSearchInputValue] = useState(''); @@ -250,7 +249,7 @@ export const WorkflowEditTriggerDatabaseEventForm = ({ ))} } - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} /> {isDefined(selectedObjectMetadataItem) && isFieldFilteringSupported && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx index 645fcc92eff..a5d5baf0f5d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManual.tsx @@ -9,13 +9,13 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { MANUAL_TRIGGER_AVAILABILITY_TYPE_OPTIONS } from '@/workflow/workflow-trigger/constants/ManualTriggerAvailabilityTypeOptions'; import { MANUAL_TRIGGER_IS_PINNED_OPTIONS } from '@/workflow/workflow-trigger/constants/ManualTriggerIsPinnedOptions'; import { getManualTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getManualTriggerDefaultSettings'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { QUERY_MAX_RECORDS } from 'twenty-shared/constants'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; import { type SelectOption } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type WorkflowEditTriggerManualProps = { trigger: WorkflowManualTrigger; @@ -31,15 +31,15 @@ type WorkflowEditTriggerManualProps = { }; const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledDescription = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.sm}; margin-top: 1px; `; @@ -52,8 +52,6 @@ export const WorkflowEditTriggerManual = ({ trigger, triggerOptions, }: WorkflowEditTriggerManualProps) => { - const theme = useTheme(); - const { t } = useLingui(); const { getIcon } = useIcons(); @@ -107,7 +105,7 @@ export const WorkflowEditTriggerManual = ({ }), }); }} - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> @@ -139,7 +137,7 @@ export const WorkflowEditTriggerManual = ({ }, }); }} - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> ) : null} @@ -147,7 +145,7 @@ export const WorkflowEditTriggerManual = ({ diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx index 7d455a360ce..873355f85f5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx @@ -12,10 +12,9 @@ import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/Workflo import { WEBHOOK_TRIGGER_AUTHENTICATION_OPTIONS } from '@/workflow/workflow-trigger/constants/WebhookTriggerAuthenticationOptions'; import { WEBHOOK_TRIGGER_HTTP_METHOD_OPTIONS } from '@/workflow/workflow-trigger/constants/WebhookTriggerHttpMethodOptions'; import { getWebhookTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getWebhookTriggerDefaultSettings'; -import { useTheme } from '@emotion/react'; import { isNonEmptyString } from '@sniptt/guards'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { getOutputSchemaFromValue } from 'twenty-shared/logic-function'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; @@ -25,6 +24,7 @@ import { IconCopy } from 'twenty-ui/display'; import { useDebouncedCallback } from 'use-debounce'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; +import { ThemeContext } from 'twenty-ui/theme'; type WorkflowEditTriggerWebhookFormProps = { trigger: WorkflowWebhookTrigger; @@ -50,7 +50,7 @@ export const WorkflowEditTriggerWebhookForm = ({ trigger, triggerOptions, }: WorkflowEditTriggerWebhookFormProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { copyToClipboard } = useCopyToClipboard(); const [errorMessages, setErrorMessages] = useState({}); const [errorMessagesVisible, setErrorMessagesVisible] = useState(false); @@ -110,7 +110,7 @@ export const WorkflowEditTriggerWebhookForm = ({ { computeOutputSchema: false }, ); }} - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} + dropdownOffset={{ y: 4 }} dropdownWidth={GenericDropdownContentWidth.ExtraLarge} /> {trigger.settings.httpMethod === 'POST' && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts index 48f95da8948..70475040f7e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts @@ -1,14 +1,13 @@ -import { type Theme } from '@emotion/react'; -import { COLOR_LIGHT } from 'twenty-ui/theme'; +import { COLOR_LIGHT, type ThemeType } from 'twenty-ui/theme'; import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor'; describe('getTriggerIconColor', () => { - const mockTheme: Theme = { + const mockTheme: ThemeType = { color: { blue: COLOR_LIGHT.blue, purple: COLOR_LIGHT.purple, }, - } as unknown as Theme; + } as unknown as ThemeType; it('returns the blue color for database event from theme', () => { const result = getTriggerIconColor({ @@ -29,12 +28,12 @@ describe('getTriggerIconColor', () => { }); it('works with different theme configurations', () => { - const differentTheme: Theme = { + const differentTheme: ThemeType = { color: { blue: COLOR_LIGHT.blue, purple: COLOR_LIGHT.purple, }, - } as unknown as Theme; + } as unknown as ThemeType; const result = getTriggerIconColor({ theme: differentTheme, @@ -45,12 +44,12 @@ describe('getTriggerIconColor', () => { }); it('maintains reference to theme.color.blue', () => { - const customTheme: Theme = { + const customTheme: ThemeType = { color: { blue: COLOR_LIGHT.blue, purple: COLOR_LIGHT.purple, }, - } as unknown as Theme; + } as unknown as ThemeType; const result = getTriggerIconColor({ theme: customTheme, diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts index eebbdf8f8a2..d339f187f6e 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts @@ -1,11 +1,11 @@ -import { type Theme } from '@emotion/react'; import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { type ThemeType } from 'twenty-ui/theme'; export const getTriggerIconColor = ({ theme, triggerType, }: { - theme: Theme; + theme: ThemeType; triggerType: WorkflowTriggerType; }) => { switch (triggerType) { diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorTextChip.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorTextChip.tsx index 2f5d91c0fe1..644a4d5908a 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorTextChip.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorTextChip.tsx @@ -1,10 +1,11 @@ import { BaseChip } from '@/object-record/record-field/ui/form-types/components/BaseChip'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { NodeViewWrapper, type NodeViewProps } from '@tiptap/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledWrapper = styled.span` display: inline-block; - padding-inline: ${({ theme }) => theme.spacing(0.5)}; + padding-inline: ${themeCssVariables.spacing[0.5]}; `; type WorkflowTextEditorTextChipProps = NodeViewProps; diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorVariableChip.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorVariableChip.tsx index 753c42a330c..bee8d533f25 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorVariableChip.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowTextEditorVariableChip.tsx @@ -1,10 +1,11 @@ import { VariableChip } from '@/object-record/record-field/ui/form-types/components/VariableChip'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { NodeViewWrapper, type NodeViewProps } from '@tiptap/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledWrapper = styled.span` display: inline-block; - padding-inline: ${({ theme }) => theme.spacing(0.5)}; + padding-inline: ${themeCssVariables.spacing[0.5]}; `; type WorkflowTextEditorVariableChipProps = NodeViewProps; diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablePicker.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablePicker.tsx index d1d2d46be0e..755504346c6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablePicker.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablePicker.tsx @@ -1,39 +1,50 @@ import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent'; import { WorkflowVariablesDropdown } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdown'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; -export const StyledSearchVariablesDropdownContainer = styled.div<{ +const StyledSearchVariablesDropdownContainer = styled.div<{ multiline?: boolean; - readonly?: boolean; + isReadonly?: boolean; }>` align-items: center; display: flex; justify-content: center; - ${({ theme, readonly }) => - !readonly && - css` - :hover { - background-color: ${theme.background.transparent.light}; - } - `} - - ${({ theme, multiline }) => + background-color: ${({ multiline }) => multiline - ? css` - border-radius: ${theme.border.radius.sm}; - padding: ${theme.spacing(0.5)} ${theme.spacing(0)}; - position: absolute; - right: ${theme.spacing(0)}; - top: ${theme.spacing(0)}; - ` - : css` - background-color: ${theme.background.transparent.lighter}; - border-top-right-radius: ${theme.border.radius.sm}; - border-bottom-right-radius: ${theme.border.radius.sm}; - border: 1px solid ${theme.border.color.medium}; - `} + ? 'transparent' + : themeCssVariables.background.transparent.lighter}; + + border-radius: ${({ multiline }) => + multiline + ? themeCssVariables.border.radius.sm + : `0 ${themeCssVariables.border.radius.sm} ${themeCssVariables.border.radius.sm} 0`}; + + border: ${({ multiline }) => + multiline ? 'none' : `1px solid ${themeCssVariables.border.color.medium}`}; + + padding: ${({ multiline }) => + multiline + ? `${themeCssVariables.spacing[0.5]} ${themeCssVariables.spacing[0]}` + : '0'}; + + position: ${({ multiline }) => (multiline ? 'absolute' : 'static')}; + right: ${({ multiline }) => + multiline ? themeCssVariables.spacing[0] : 'auto'}; + top: ${({ multiline }) => + multiline ? themeCssVariables.spacing[0] : 'auto'}; + + &:hover { + background-color: ${({ isReadonly, multiline }) => { + if (isReadonly === true) { + return multiline + ? 'transparent' + : themeCssVariables.background.transparent.lighter; + } + return themeCssVariables.background.transparent.light; + }}; + } `; export const WorkflowVariablePicker: VariablePickerComponent = ({ @@ -47,7 +58,7 @@ export const WorkflowVariablePicker: VariablePickerComponent = ({ return ( ` - background-color: ${({ theme, transparentBackground }) => + background-color: ${({ transparentBackground }) => transparentBackground ? 'transparent' - : theme.background.transparent.lighter}; + : themeCssVariables.background.transparent.lighter}; - color: ${({ theme }) => theme.font.color.tertiary}; - padding: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: ${themeCssVariables.spacing[2]}; :hover { cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; } @@ -50,7 +51,7 @@ export const WorkflowVariablesDropdown = ({ multiline?: boolean; clickableComponent?: React.ReactNode; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const dropdownId = `${SEARCH_VARIABLES_DROPDOWN_ID}-${instanceId}`; const isDropdownOpen = useAtomComponentStateValue( @@ -138,7 +139,7 @@ export const WorkflowVariablesDropdown = ({ } dropdownPlacement="bottom-end" dropdownOffset={{ - x: parseInt(theme.spacing(0.5), 10), + x: 2, y: parseInt(theme.spacing(multiline ? 11 : 1), 10), }} /> diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index b117eb57ccd..81f4c9dc22a 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -113,6 +113,11 @@ export default defineConfig(({ command, mode }) => { include: [ '**/twenty-ui/src/**/*.{ts,tsx}', '**/AdvancedTextEditor.tsx', + '**/FileUploadProvider.tsx', + '**/MultiSelectControl.tsx', + '**/FormNumberFieldInput.tsx', + '**/FormUuidFieldInput.tsx', + '**/KeyboardShortcutMenuStyles.tsx', '**/BubbleMenuIconButton.tsx', '**/TextBubbleMenu.tsx', '**/TurnIntoBlockDropdown.tsx', @@ -416,6 +421,259 @@ export default defineConfig(({ command, mode }) => { '**/WorkflowStepActionDrawerDecorator.tsx', '**/WorkspaceInviteLink.tsx', '**/WorkspaceInviteTeam.tsx', + '**/AddressInput.tsx', + '**/AxisLayer.tsx', + '**/BarChart.tsx', + '**/BarChartBaseLayer.tsx', + '**/BarChartHoverLayer.tsx', + '**/BarChartLayers.tsx', + '**/BarChartTotalsLayer.tsx', + '**/BlankLayout.tsx', + '**/BodyInput.tsx', + '**/BooleanInput.tsx', + '**/CalendarWidget.tsx', + '**/ChartColorGradientOption.tsx', + '**/ChartColorPaletteOption.tsx', + '**/ChartFiltersSettings.tsx', + '**/ChartSettings.tsx', + '**/ChartTypeSelectionSection.tsx', + '**/CommandGroup.tsx', + '**/CommandMenuAIChatThreadsPage.tsx', + '**/CommandMenuAskAIInfo.tsx', + '**/CommandMenuAskAIPage.tsx', + '**/CommandMenuBackButton.tsx', + '**/CommandMenuContainer.tsx', + '**/CommandMenuContextChip.tsx', + '**/CommandMenuContextRecordChipAvatars.tsx', + '**/CommandMenuEditColorOption.tsx', + '**/CommandMenuEditRichTextPage.tsx', + '**/CommandMenuFolderInfo.tsx', + '**/CommandMenuForMobile.tsx', + '**/CommandMenuItemNumberInput.tsx', + '**/CommandMenuItemTextInput.tsx', + '**/CommandMenuItemWithAddToNavigationDrag.tsx', + '**/CommandMenuList.tsx', + '**/CommandMenuMergeRecordPage.tsx', + '**/CommandMenuMessageThreadIntermediaryMessages.tsx', + '**/CommandMenuMessageThreadPage.tsx', + '**/CommandMenuNavigationMenuItemEditPage.tsx', + '**/CommandMenuOpenContainer.tsx', + '**/CommandMenuPageInfo.tsx', + '**/CommandMenuPageInfoLayout.tsx', + '**/CommandMenuPageLayoutChartSettings.tsx', + '**/CommandMenuPageLayoutFieldsLayout.tsx', + '**/CommandMenuPageLayoutFieldsSettings.tsx', + '**/CommandMenuPageLayoutIframeSettings.tsx', + '**/CommandMenuRecordPage.tsx', + '**/CommandMenuRouter.tsx', + '**/CommandMenuSidePanelForDesktop.tsx', + '**/CommandMenuSubViewWithSearch.tsx', + '**/CommandMenuTopBar.tsx', + '**/CommandMenuTopBarRightCornerIcon.tsx', + '**/CommandMenuUpdateMultipleRecords.tsx', + '**/CommandMenuWorkflowEditStepContent.tsx', + '**/CommandMenuWorkflowRunViewStepContent.tsx', + '**/CommandMenuWorkflowViewStepContent.tsx', + '**/ConfirmationModal.tsx', + '**/CreateNewButton.tsx', + '**/CronExpressionHelper.tsx', + '**/CurrencyInput.tsx', + '**/CurrencyPickerDropdownButton.tsx', + '**/DashboardColorIcon.tsx', + '**/DashboardColorSelectionMenu.tsx', + '**/DashboardEditorSideMenu.tsx', + '**/DashboardFormattingToolbar.tsx', + '**/DashboardFormattingToolbarColorButton.tsx', + '**/DashboardsBlockEditor.tsx', + '**/DatePicker.tsx', + '**/DatePickerHeader.tsx', + '**/DatePickerInput.tsx', + '**/DatePickerWithoutCalendar.tsx', + '**/DateTimeDisplay.tsx', + '**/DateTimePicker.tsx', + '**/DateTimePickerHeader.tsx', + '**/DateTimePickerInput.tsx', + '**/DefaultLayout.tsx', + '**/Dialog.tsx', + '**/DoubleTextInput.tsx', + '**/DraggableList.tsx', + '**/Dropdown.stories.tsx', + '**/Dropdown.tsx', + '**/DropdownContent.tsx', + '**/DropdownInternalContainer.tsx', + '**/DropdownMenuHeader.tsx', + '**/DropdownMenuHeaderLeftComponent.tsx', + '**/DropdownMenuInnerSelect.tsx', + '**/DropdownMenuInput.tsx', + '**/DropdownMenuItemsContainer.tsx', + '**/DropdownMenuSearchInput.tsx', + '**/DropdownMenuSectionLabel.tsx', + '**/DropdownMenuSeparator.tsx', + '**/DropdownMenuSkeletonItem.tsx', + '**/EmailWidget.tsx', + '**/ExpandableList.stories.tsx', + '**/ExpandableList.tsx', + '**/ExpandedFieldDisplay.tsx', + '**/ExpandedListDropdown.tsx', + '**/FieldInputContainer.tsx', + '**/FieldRichTextWidget.tsx', + '**/FieldWidget.tsx', + '**/FieldWidgetDisplay.tsx', + '**/FieldWidgetEditAction.tsx', + '**/FieldWidgetInlineCellContainer.tsx', + '**/FieldWidgetMorphRelationCard.tsx', + '**/FieldWidgetMorphRelationField.tsx', + '**/FieldWidgetRelationCard.tsx', + '**/FieldWidgetRelationEditAction.tsx', + '**/FieldWidgetRelationField.tsx', + '**/FieldWidgetShowMoreButton.tsx', + '**/FieldsConfigurationEditor.tsx', + '**/FieldsConfigurationGroupEditor.tsx', + '**/FieldsConfigurationGroupRenameInput.tsx', + '**/FieldsWidget.tsx', + '**/FieldsWidgetGroupContainer.tsx', + '**/FileChip.tsx', + '**/FileWidget.tsx', + '**/FrontComponentWidgetRenderer.tsx', + '**/FullScreenContainer.stories.tsx', + '**/FullScreenContainer.tsx', + '**/GlobalFilePreviewModal.tsx', + '**/GraphWidgetAggregateChart.tsx', + '**/GraphWidgetBarChart.tsx', + '**/GraphWidgetChartContainer.tsx', + '**/GraphWidgetGaugeChart.tsx', + '**/GraphWidgetLegend.tsx', + '**/GraphWidgetLegendDot.tsx', + '**/GraphWidgetLineChart.tsx', + '**/GraphWidgetPieChart.tsx', + '**/GraphWidgetTooltip.tsx', + '**/HttpRequestTestVariableInput.tsx', + '**/IconPicker.tsx', + '**/IframeWidget.tsx', + '**/ImageInput.tsx', + '**/InputErrorHelper.tsx', + '**/InputHint.tsx', + '**/InputLabel.tsx', + '**/KeyValuePairInput.tsx', + '**/Modal.tsx', + '**/NoteWidget.tsx', + '**/OverlayContainer.tsx', + '**/PageBody.tsx', + '**/PageContainer.tsx', + '**/PageHeader.tsx', + '**/PageHeaderToggleCommandMenuButton.tsx', + '**/PageLayoutCanvasViewer.tsx', + '**/PageLayoutGridLayout.tsx', + '**/PageLayoutGridOverlay.tsx', + '**/PageLayoutGridResizeHandle.tsx', + '**/PageLayoutLeftPanel.tsx', + '**/PageLayoutRendererContent.tsx', + '**/PageLayoutTabList.stories.tsx', + '**/PageLayoutTabList.tsx', + '**/PageLayoutTabListDroppableMoreButton.tsx', + '**/PageLayoutTabListReorderableOverflowDropdown.tsx', + '**/PageLayoutTabListReorderableTab.tsx', + '**/PageLayoutTabListVisibleTabs.tsx', + '**/PageLayoutTabMenuItemSelectAvatar.tsx', + '**/PageLayoutTabRenderClone.tsx', + '**/PageLayoutVerticalListEditor.tsx', + '**/PageLayoutVerticalListViewer.tsx', + '**/PageLayoutWidgetInvalidConfigDisplay.tsx', + '**/PageLayoutWidgetNoDataDisplay.tsx', + '**/PagePanel.tsx', + '**/PhoneCountryPickerDropdownButton.tsx', + '**/PhoneCountryPickerDropdownSelect.tsx', + '**/PieChartCenterMetricLayer.tsx', + '**/RelativeDatePickerHeader.tsx', + '**/ResizablePanelEdge.tsx', + '**/ResizablePanelGap.tsx', + '**/RightDrawerFooter.tsx', + '**/RightDrawerWorkflowSelectStepContainer.tsx', + '**/RightDrawerWorkflowSelectStepTitle.tsx', + '**/Select.tsx', + '**/SelectControl.tsx', + '**/ShowPageContainer.tsx', + '**/SidePanelSubPageNavigationHeader.tsx', + '**/SnackBar.tsx', + '**/SnackBarProvider.tsx', + '**/StandaloneRichTextWidget.tsx', + '**/StyledDropdownButtonContainer.tsx', + '**/StyledDropdownMenuSubheader.tsx', + '**/StyledHeaderDropdownButton.tsx', + '**/SubMenuTopBarContainer.tsx', + '**/TaskWidget.tsx', + '**/TextArea.tsx', + '**/TextAreaInput.tsx', + '**/TextInput.tsx', + '**/TimeZoneAbbreviation.tsx', + '**/TimelineWidget.tsx', + '**/TitleInput.tsx', + '**/UploadFileChip.tsx', + '**/WidgetActionFieldSeeAll.tsx', + '**/WidgetCard.tsx', + '**/WidgetCardContent.tsx', + '**/WidgetCardHeader.tsx', + '**/WidgetGrip.tsx', + '**/WidgetRenderer.tsx', + '**/WidgetSkeletonLoader.tsx', + '**/WorkflowAiAgentPermissionsStyles.ts', + '**/WorkflowAiAgentPermissionsTab.tsx', + '**/WorkflowCodeEditor.tsx', + '**/WorkflowDiagramCanvasBase.tsx', + '**/WorkflowDiagramCreateStepElement.tsx', + '**/WorkflowDiagramEdgeButtonGroup.tsx', + '**/WorkflowDiagramEdgeLabel.tsx', + '**/WorkflowDiagramEdgeLabelContainer.tsx', + '**/WorkflowDiagramEdgeV2Container.tsx', + '**/WorkflowDiagramEdgeV2VisibilityContainer.tsx', + '**/WorkflowDiagramHandleSource.tsx', + '**/WorkflowDiagramHandleTarget.tsx', + '**/WorkflowDiagramRightClickCommandMenu.tsx', + '**/WorkflowDiagramStepNodeEditableContent.tsx', + '**/WorkflowEditActionAiAgent.tsx', + '**/WorkflowEditActionCode.tsx', + '**/WorkflowEditActionCodeFields.tsx', + '**/WorkflowEditActionFilterBody.tsx', + '**/WorkflowEditActionFindRecords.tsx', + '**/WorkflowEditActionFormBuilder.tsx', + '**/WorkflowEditActionFormFieldSettings.tsx', + '**/WorkflowEditActionHttpRequest.tsx', + '**/WorkflowEditActionIfElseBody.tsx', + '**/WorkflowEditActionLogicFunction.tsx', + '**/WorkflowEditTriggerDatabaseEventForm.tsx', + '**/WorkflowEditTriggerManual.tsx', + '**/WorkflowFindRecordsSorts.tsx', + '**/WorkflowFormFieldSettingsNumber.tsx', + '**/WorkflowFormFieldSettingsRecordPicker.tsx', + '**/WorkflowFormFieldSettingsSelect.tsx', + '**/WorkflowFormFieldSettingsText.tsx', + '**/WorkflowIfElseBranchEditor.tsx', + '**/WorkflowIteratorSubStepSwitcher.tsx', + '**/WorkflowNodeContainer.tsx', + '**/WorkflowNodeIconContainer.tsx', + '**/WorkflowNodeLabel.tsx', + '**/WorkflowNodeLabelWithCounterPart.tsx', + '**/WorkflowNodeRightPart.tsx', + '**/WorkflowNodeTitle.tsx', + '**/WorkflowOutputSchemaBuilder.tsx', + '**/WorkflowReadonlyActionCode.tsx', + '**/WorkflowRunCard.tsx', + '**/WorkflowRunDiagramStepNode.tsx', + '**/WorkflowRunStepJsonContainer.tsx', + '**/WorkflowStepBody.tsx', + '**/WorkflowStepExecutionResult.tsx', + '**/WorkflowStepFilterAddRootStepFilterButton.tsx', + '**/WorkflowStepFilterColumn.tsx', + '**/WorkflowStepFilterGroupChildren.tsx', + '**/WorkflowStepFilterGroupColumn.tsx', + '**/WorkflowStepFilterLogicalOperatorCell.tsx', + '**/WorkflowTextEditorTextChip.tsx', + '**/WorkflowTextEditorVariableChip.tsx', + '**/WorkflowVariablePicker.tsx', + '**/WorkflowVariablesDropdown.tsx', + '**/WorkflowVersionCard.tsx', + '**/useCommandMenuContextChips.tsx', + '**/useFullScreenModal.tsx', ], babelOptions: { presets: ['@babel/preset-typescript', '@babel/preset-react'], @@ -444,13 +702,12 @@ export default defineConfig(({ command, mode }) => { minify: 'esbuild', outDir: 'build', sourcemap: VITE_BUILD_SOURCEMAP === 'true', + chunkSizeWarningLimit: CHUNK_SIZE_WARNING_LIMIT, rollupOptions: { // Don't use manual chunks as it causes many issue // including this one we wasted a lot of time on: // https://github.com/rollup/rollup/issues/2793 output: { - // Set chunk size warning limit (in bytes) - warns at 1MB - chunkSizeWarningLimit: CHUNK_SIZE_WARNING_LIMIT, // Custom plugin to fail build if chunks exceed max size plugins: [ { diff --git a/packages/twenty-ui/.storybook/main.ts b/packages/twenty-ui/.storybook/main.ts index 4fbcaec0ab3..a4b9db14e98 100644 --- a/packages/twenty-ui/.storybook/main.ts +++ b/packages/twenty-ui/.storybook/main.ts @@ -39,6 +39,14 @@ const config: StorybookConfig = { return { ...viteConfig, plugins, + resolve: { + ...viteConfig.resolve, + alias: { + ...(viteConfig.resolve?.alias ?? {}), + '@tabler/icons-react': + '@tabler/icons-react/dist/esm/icons/index.mjs', + }, + }, }; }, }; diff --git a/packages/twenty-ui/src/input/button/components/ColorPickerButton.tsx b/packages/twenty-ui/src/input/button/components/ColorPickerButton.tsx index fb45afb77f6..6435af6cd91 100644 --- a/packages/twenty-ui/src/input/button/components/ColorPickerButton.tsx +++ b/packages/twenty-ui/src/input/button/components/ColorPickerButton.tsx @@ -15,17 +15,17 @@ const StyledButtonWrapper = styled.div<{ isSelected?: boolean; }>` button { - ${({ isSelected }) => + background-color: ${({ isSelected }) => isSelected - ? `background-color: ${themeCssVariables.background.transparent.medium};` - : ''} + ? themeCssVariables.background.transparent.medium + : 'transparent'}; } button:hover { - ${({ isSelected }) => + background-color: ${({ isSelected }) => isSelected - ? `background-color: ${themeCssVariables.background.transparent.medium};` - : ''} + ? themeCssVariables.background.transparent.medium + : 'transparent'}; } `; diff --git a/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx b/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx index 738e2fe92b3..a29ff568061 100644 --- a/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx +++ b/packages/twenty-ui/src/json-visualizer/components/JsonNestedNode.tsx @@ -41,13 +41,11 @@ const StyledJsonListBase = styled.ul<{ padding: 0; display: grid; row-gap: ${themeCssVariables.spacing[2]}; - ${({ depth }) => - depth > 0 - ? `padding-left: ${themeCssVariables.spacing[8]}; - > :first-of-type { - margin-top: ${themeCssVariables.spacing[2]}; - }` - : ''} + padding-left: ${({ depth }) => (depth > 0 ? themeCssVariables.spacing[8] : '0')}; + + > :first-of-type { + margin-top: ${({ depth }) => (depth > 0 ? themeCssVariables.spacing[2] : '0')}; + } `; const StyledJsonList = motion.create(StyledJsonListBase); diff --git a/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx b/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx index ffc32ea836c..34b045411c2 100644 --- a/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx +++ b/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx @@ -61,7 +61,7 @@ const StyledRowContainer = styled.div<{ theme: ThemeType }>` const StyledElementContainer = styled.div<{ width: number }>` display: flex; - ${({ width }) => width && `min-width: ${width}px;`} + min-width: ${({ width }) => (width ? `${width}px` : 'auto')}; `; const StyledCellContainer = styled.div<{ theme: ThemeType }>` @@ -120,28 +120,28 @@ export const CatalogDecorator: Decorator = (Story, context) => { return ( - {dimension4.values.map((value4: any) => ( - + {dimension4.values.map((value4: any, index4: number) => ( + {dimension4.labels?.(value4) ?? (isStringOrNumber(value4) ? value4 : '')} - {dimension3.values.map((value3: any) => ( - + {dimension3.values.map((value3: any, index3: number) => ( + {dimension3.labels?.(value3) ?? (isStringOrNumber(value3) ? value3 : '')} - {dimension2.values.map((value2: any) => ( - + {dimension2.values.map((value2: any, index2: number) => ( + {dimension2.labels?.(value2) ?? (isStringOrNumber(value2) ? value2 : '')} - {dimension1.values.map((value1: any) => { + {dimension1.values.map((value1: any, index1: number) => { return ( diff --git a/packages/twenty-ui/src/theme/constants/TextInputStyle.ts b/packages/twenty-ui/src/theme/constants/TextInputStyle.ts index 58ee707b2c9..b3ea7081f3c 100644 --- a/packages/twenty-ui/src/theme/constants/TextInputStyle.ts +++ b/packages/twenty-ui/src/theme/constants/TextInputStyle.ts @@ -1,19 +1,19 @@ -import { type ThemeType } from '..'; +import { themeCssVariables } from '../../theme-constants'; -export const TEXT_INPUT_STYLE = (props: { theme: ThemeType }) => ` +export const TEXT_INPUT_STYLE = ` background-color: transparent; border: none; - color: ${props.theme.font.color.primary}; - font-family: ${props.theme.font.family}; + color: ${themeCssVariables.font.color.primary}; + font-family: ${themeCssVariables.font.family}; font-size: inherit; font-weight: inherit; outline: none; - padding: ${props.theme.spacing(0)} ${props.theme.spacing(2)}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[2]}; &::placeholder, &::-webkit-input-placeholder { - color: ${props.theme.font.color.light}; - font-family: ${props.theme.font.family}; - font-weight: ${props.theme.font.weight.medium}; + color: ${themeCssVariables.font.color.light}; + font-family: ${themeCssVariables.font.family}; + font-weight: ${themeCssVariables.font.weight.medium}; } `; diff --git a/packages/twenty-ui/vite.config.ts b/packages/twenty-ui/vite.config.ts index 480b9a53e33..a17a1ecb6b4 100644 --- a/packages/twenty-ui/vite.config.ts +++ b/packages/twenty-ui/vite.config.ts @@ -83,6 +83,7 @@ export default defineConfig(({ command }) => { checker(checkersConfig), { ...wyw({ + include: [path.resolve(__dirname, 'src') + '/**/*.{ts,tsx}'], babelOptions: { presets: ['@babel/preset-typescript', '@babel/preset-react'], }, diff --git a/yarn.lock b/yarn.lock index e46213da1da..d7fb575f4eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26705,16 +26705,6 @@ __metadata: languageName: node linkType: hard -"@wyw-in-js/processor-utils@npm:0.6.0": - version: 0.6.0 - resolution: "@wyw-in-js/processor-utils@npm:0.6.0" - dependencies: - "@babel/generator": "npm:^7.23.5" - "@wyw-in-js/shared": "npm:0.6.0" - checksum: 10c0/e7338afb71aa1eccf7646447df9d20c2ac895dc1d5a5ad8c26931997fa31595ece5890e8ada39b3c1fda28439c7598de950980dded714dbe003b232f95d22d9e - languageName: node - linkType: hard - "@wyw-in-js/processor-utils@npm:0.7.0": version: 0.7.0 resolution: "@wyw-in-js/processor-utils@npm:0.7.0" @@ -26746,17 +26736,6 @@ __metadata: languageName: node linkType: hard -"@wyw-in-js/shared@npm:0.6.0": - version: 0.6.0 - resolution: "@wyw-in-js/shared@npm:0.6.0" - dependencies: - debug: "npm:^4.3.4" - find-up: "npm:^5.0.0" - minimatch: "npm:^9.0.3" - checksum: 10c0/a7bab831ebdf9172c8b7a117525550b57c6b338bb6579f186b0f54a3cae5cde75dd245e375b93766fe1f1fc1d42f804353622594115727a2a8c4eb4de84aaaab - languageName: node - linkType: hard - "@wyw-in-js/shared@npm:0.7.0": version: 0.7.0 resolution: "@wyw-in-js/shared@npm:0.7.0" @@ -26768,29 +26747,6 @@ __metadata: languageName: node linkType: hard -"@wyw-in-js/transform@npm:0.6.0": - version: 0.6.0 - resolution: "@wyw-in-js/transform@npm:0.6.0" - dependencies: - "@babel/core": "npm:^7.23.5" - "@babel/generator": "npm:^7.23.5" - "@babel/helper-module-imports": "npm:^7.22.15" - "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" - "@babel/template": "npm:^7.22.15" - "@babel/traverse": "npm:^7.23.5" - "@babel/types": "npm:^7.23.5" - "@wyw-in-js/processor-utils": "npm:0.6.0" - "@wyw-in-js/shared": "npm:0.6.0" - babel-merge: "npm:^3.0.0" - cosmiconfig: "npm:^8.0.0" - happy-dom: "npm:^15.11.0" - source-map: "npm:^0.7.4" - stylis: "npm:^4.3.0" - ts-invariant: "npm:^0.10.3" - checksum: 10c0/f94c1477effefee8116530f415e1442317144131d9032eb91e2d3ee7e765594e657aaf65defb71bcc249341147c253cf72190063a9d22a38b13cb80ab6d6eabd - languageName: node - linkType: hard - "@wyw-in-js/transform@npm:0.7.0": version: 0.7.0 resolution: "@wyw-in-js/transform@npm:0.7.0" @@ -26814,6 +26770,29 @@ __metadata: languageName: node linkType: hard +"@wyw-in-js/transform@patch:@wyw-in-js/transform@npm%3A0.7.0#~/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch": + version: 0.7.0 + resolution: "@wyw-in-js/transform@patch:@wyw-in-js/transform@npm%3A0.7.0#~/.yarn/patches/@wyw-in-js-transform-npm-0.7.0-ba641dc99f.patch::version=0.7.0&hash=95ca78" + dependencies: + "@babel/core": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.5" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" + "@babel/template": "npm:^7.22.15" + "@babel/traverse": "npm:^7.23.5" + "@babel/types": "npm:^7.23.5" + "@wyw-in-js/processor-utils": "npm:0.7.0" + "@wyw-in-js/shared": "npm:0.7.0" + babel-merge: "npm:^3.0.0" + cosmiconfig: "npm:^8.0.0" + happy-dom: "npm:^15.11.0" + source-map: "npm:^0.7.4" + stylis: "npm:^4.3.0" + ts-invariant: "npm:^0.10.3" + checksum: 10c0/94a4753b5a6f0c859af6adf20c9668f13d8cc5422f44f1b568ed2d1fd787ff65d25447919498382174ff61985bc28ecb7cbe881481510d23bb65fd0a51b00993 + languageName: node + linkType: hard + "@wyw-in-js/vite@npm:^0.7.0": version: 0.7.0 resolution: "@wyw-in-js/vite@npm:0.7.0"