diff --git a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx index 44869ca6f7..526733a951 100644 --- a/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx +++ b/packages/twenty-front/src/loading/components/LeftPanelSkeletonLoader.tsx @@ -1,12 +1,12 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { useTheme } from '@emotion/react'; -import { ANIMATION } from 'twenty-ui/theme'; +import { useContext } from 'react'; +import { ANIMATION, ThemeContext } from 'twenty-ui/theme'; import { MainNavigationDrawerItemsSkeletonLoader } from '~/loading/components/MainNavigationDrawerItemsSkeletonLoader'; const StyledAnimatedContainer = styled(motion.div)` @@ -48,7 +48,7 @@ const StyledSkeletonTitleContainer = styled.div` export const LeftPanelSkeletonLoader = () => { const isMobile = useIsMobile(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/loading/components/RightDrawerSkeletonLoader.tsx b/packages/twenty-front/src/loading/components/RightDrawerSkeletonLoader.tsx index 7e592415b6..d382ecd2f5 100644 --- a/packages/twenty-front/src/loading/components/RightDrawerSkeletonLoader.tsx +++ b/packages/twenty-front/src/loading/components/RightDrawerSkeletonLoader.tsx @@ -1,17 +1,19 @@ 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 { useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledRightDrawerContainer = styled.div` display: flex; flex-direction: column; width: 100%; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; `; const StyledSkeletonLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; box-sizing: border-box; display: flex; flex: 1 1 auto; @@ -22,8 +23,8 @@ const StyledMainContainer = styled.div` `; const StyledPanel = styled.div` - background: ${({ theme }) => theme.background.primary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; + background: ${themeCssVariables.background.primary}; + border: 1px solid ${themeCssVariables.border.color.medium}; border-radius: ${BORDER_COMMON.radius.md}; height: 100%; overflow: auto; @@ -49,7 +50,7 @@ const StyledRightPanelFlexContainer = styled.div` `; const StyledSkeletonHeaderLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( @@ -68,7 +69,7 @@ const StyledSkeletonHeaderLoader = () => { }; const StyledSkeletonAddLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; box-sizing: border-box; display: flex; flex-direction: row; diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx index 3a3fd0296f..a18da23c11 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx @@ -1,12 +1,13 @@ import { type ActionDisplayProps } from '@/action-menu/actions/display/components/ActionDisplay'; import { getActionLabel } from '@/action-menu/utils/getActionLabel'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/display'; import { Button, IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledWrapper = styled.div` - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; `; export const ActionButton = ({ diff --git a/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx b/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx index 7e7d4830fc..9321dfa18c 100644 --- a/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx @@ -1,9 +1,9 @@ import { ActionComponent } from '@/action-menu/actions/display/components/ActionComponent'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; const StyledActionContainer = styled(motion.div)` display: flex; @@ -13,7 +13,7 @@ const StyledActionContainer = styled(motion.div)` export const PageHeaderActionMenuButtons = () => { const { actions } = useContext(ActionMenuContext); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const pinnedActions = actions.filter((entry) => entry.isPinned).toReversed(); diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx index 142927ef30..61e4cefd0b 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuDropdown.tsx @@ -16,7 +16,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useContext } from 'react'; import { IconLayoutSidebarRightExpand } from 'twenty-ui/display'; 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 f540dc971e..9ec4d36ca0 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx @@ -1,10 +1,12 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; 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 { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type TimelineCalendarEvent } from '~/generated/graphql'; type CalendarDayCardContentProps = { @@ -14,26 +16,26 @@ type CalendarDayCardContentProps = { const StyledCardContent = styled(CardContent)` align-items: flex-start; - border-color: ${({ theme }) => theme.border.color.light}; + border-color: ${themeCssVariables.border.color.light}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(3)}; - padding: ${({ theme }) => theme.spacing(2, 3)}; + gap: ${themeCssVariables.spacing[3]}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; `; const StyledDayContainer = styled.div` text-align: center; - width: ${({ theme }) => theme.spacing(6)}; + width: ${themeCssVariables.spacing[6]}; `; const StyledWeekDay = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.xxs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.xxs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledMonthDay = styled.div` - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledEvents = styled.div` @@ -41,7 +43,7 @@ const StyledEvents = styled.div` display: flex; flex: 1 0 auto; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; const StyledEventRow = styled(CalendarEventRow)` @@ -52,7 +54,7 @@ export const CalendarDayCardContent = ({ calendarEvents, divider, }: CalendarDayCardContentProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const endOfDayDate = endOfDay(getCalendarEventStartDate(calendarEvents[0])); const dayEndsIn = differenceInSeconds(endOfDayDate, Date.now()); 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 579513edfb..4725892f94 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx @@ -1,5 +1,4 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useCallback, useState } from 'react'; @@ -33,6 +32,7 @@ import { ChipVariant, } from 'twenty-ui/components'; import { IconCalendarEvent } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; type CalendarEventDetailsProps = { @@ -42,50 +42,47 @@ type CalendarEventDetailsProps = { const INPUT_ID_PREFIX = 'calendar-event-details'; const StyledContainer = styled.div` - background: ${({ theme }) => theme.background.secondary}; + background: ${themeCssVariables.background.secondary}; align-items: flex-start; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[6]}; + padding: ${themeCssVariables.spacing[6]}; width: 100%; box-sizing: border-box; `; const StyledEventChip = styled(Chip)` - gap: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[2]}; + padding-right: ${themeCssVariables.spacing[2]}; `; const StyledHeader = styled.header``; const StyledTitle = styled.h2<{ canceled?: boolean }>` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin: ${({ theme }) => theme.spacing(0, 0, 2)}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[0]} + ${themeCssVariables.spacing[2]}; - ${({ canceled }) => - canceled && - css` - text-decoration: line-through; - `} + ${({ canceled }) => (canceled ? 'text-decoration: line-through' : '')} `; const StyledCreatedAt = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledFields = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; width: 100%; `; const StyledPropertyBox = styled(PropertyBox)` - height: ${({ theme }) => theme.spacing(6)}; + height: ${themeCssVariables.spacing[6]}; padding: 0; width: 100%; `; 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 2af43d60ec..1d8b2c7e68 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventNotSharedContent.tsx @@ -1,30 +1,32 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +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: ${({ theme }) => theme.border.color.light}; - color: ${({ theme }) => theme.font.color.light}; + border-color: ${themeCssVariables.border.color.light}; + color: ${themeCssVariables.font.color.light}; flex: 1; - transition: color ${({ theme }) => theme.animation.duration.normal} ease; + transition: color ${themeCssVariables.animation.duration.normal} ease; width: 100%; `; const StyledVisibilityCardContent = styled(CardContent)` align-items: center; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(0, 1)}; - height: ${({ theme }) => theme.spacing(6)}; - background-color: ${({ theme }) => theme.background.transparent.lighter}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; + height: ${themeCssVariables.spacing[6]}; + background-color: ${themeCssVariables.background.transparent.lighter}; `; export const CalendarEventNotSharedContent = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( 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 f7fdb04def..70f81a2ac4 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsResponseStatusField.tsx @@ -1,6 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useRef } from 'react'; +import { useContext, useRef } from 'react'; +import { styled } from '@linaria/react'; import { type CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant'; import { ParticipantChip } from '@/activities/components/ParticipantChip'; @@ -8,6 +7,8 @@ import { PropertyBox } from '@/object-record/record-inline-cell/property-box/com 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'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledInlineCellBaseContainer = styled.div` align-items: center; @@ -15,21 +16,21 @@ const StyledInlineCellBaseContainer = styled.div` width: 100%; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; position: relative; user-select: none; `; const StyledPropertyBox = styled(PropertyBox)` - height: ${({ theme }) => theme.spacing(6)}; + height: ${themeCssVariables.spacing[6]}; padding: 0; width: 100%; `; const StyledIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; width: 16px; @@ -44,15 +45,15 @@ const StyledIconContainer = styled.div` const StyledLabelAndIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledLabelContainer = styled.div<{ width?: number }>` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - width: ${({ width }) => width}px; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + width: ${({ width }) => (width !== undefined ? `${width}px` : 'auto')}; `; const StyledDiv = styled.div` max-width: 70%; @@ -65,7 +66,7 @@ export const CalendarEventParticipantsResponseStatusField = ({ responseStatus: 'Yes' | 'Maybe' | 'No'; participants: CalendarEventParticipant[]; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const Icon = { Yes: , 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 6e22ff98f1..423e7eee57 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -1,5 +1,5 @@ -import { css, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { format } from 'date-fns'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; @@ -16,6 +16,8 @@ import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEv import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useOpenCalendarEventInCommandMenu } from '@/command-menu/hooks/useOpenCalendarEventInCommandMenu'; import { IconArrowRight } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type CalendarEventRowProps = { calendarEvent: TimelineCalendarEvent; @@ -25,39 +27,36 @@ type CalendarEventRowProps = { const StyledContainer = styled.div<{ showTitle?: boolean }>` align-items: center; display: inline-flex; - gap: ${({ theme }) => theme.spacing(3)}; - height: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[3]}; + height: ${themeCssVariables.spacing[6]}; position: relative; cursor: ${({ showTitle }) => (showTitle ? 'pointer' : 'not-allowed')}; `; const StyledAttendanceIndicator = styled.div<{ active?: boolean }>` - background-color: ${({ theme }) => theme.tag.background.gray}; + background-color: ${themeCssVariables.tag.background.gray}; height: 100%; - width: ${({ theme }) => theme.spacing(1)}; - border-radius: ${({ theme }) => theme.border.radius.xs}; + width: ${themeCssVariables.spacing[1]}; + border-radius: ${themeCssVariables.border.radius.xs}; - ${({ active, theme }) => - active && - css` - background-color: ${theme.tag.background.red}; - `} + ${({ active }) => + active ? `background-color: ${themeCssVariables.tag.background.red}` : ''} `; const StyledLabels = styled.div` align-items: center; display: flex; - color: ${({ theme }) => theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; flex: 1 0 auto; `; const StyledTime = styled.div` align-items: center; display: flex; - color: ${({ theme }) => theme.font.color.tertiary}; - gap: ${({ theme }) => theme.spacing(1)}; - width: ${({ theme }) => theme.spacing(26)}; + color: ${themeCssVariables.font.color.tertiary}; + gap: ${themeCssVariables.spacing[1]}; + width: ${themeCssVariables.spacing[26]}; `; const StyledTitle = styled.div<{ active: boolean; canceled: boolean }>` @@ -65,26 +64,20 @@ const StyledTitle = styled.div<{ active: boolean; canceled: boolean }>` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - width: ${({ theme }) => theme.spacing(10)}; - ${({ theme, active }) => - active && - css` - color: ${theme.font.color.primary}; - font-weight: ${theme.font.weight.medium}; - `} + width: ${themeCssVariables.spacing[10]}; + ${({ active }) => + active + ? `color: ${themeCssVariables.font.color.primary}; font-weight: ${themeCssVariables.font.weight.medium}` + : ''} - ${({ canceled }) => - canceled && - css` - text-decoration: line-through; - `} + ${({ canceled }) => (canceled ? 'text-decoration: line-through' : '')} `; export const CalendarEventRow = ({ calendarEvent, className, }: CalendarEventRowProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); const { openCalendarEventInCommandMenu } = useOpenCalendarEventInCommandMenu(); diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx index ad509af693..e9e420d2a4 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventsCard.tsx @@ -1,5 +1,5 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { format, getYear } from 'date-fns'; @@ -25,6 +25,7 @@ import { EMPTY_PLACEHOLDER_TRANSITION_PROPS, Section, } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type TimelineCalendarEventsWithTotal } from '~/generated/graphql'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; @@ -32,18 +33,18 @@ const StyledContainer = styled.div` box-sizing: border-box; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(8)}; - padding: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[8]}; + padding: ${themeCssVariables.spacing[6]}; width: 100%; overflow: scroll; `; const StyledYear = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; `; const StyledTitleContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; export const CalendarEventsCard = () => { diff --git a/packages/twenty-front/src/modules/activities/components/ActivityList.tsx b/packages/twenty-front/src/modules/activities/components/ActivityList.tsx index 75d4f2c325..ae5ad19134 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityList.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityList.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Card } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledList = styled(Card)` & > :not(:last-child) { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; } width: calc(100% - 2px); diff --git a/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx b/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx index 2d5a4501b3..7974043bed 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityRow.tsx @@ -1,16 +1,14 @@ -import styled from '@emotion/styled'; +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)<{ - clickable?: boolean; -}>` +const StyledRowContent = styled(CardContent)` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - height: ${({ theme }) => theme.spacing(12)}; - padding: ${({ theme }) => theme.spacing(0, 4)}; - cursor: ${({ clickable }) => (clickable === true ? 'pointer' : 'default')}; + gap: ${themeCssVariables.spacing[2]}; + height: ${themeCssVariables.spacing[12]}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[4]}; `; export const ActivityRow = ({ @@ -28,7 +26,7 @@ export const ActivityRow = ({ }; return ( - + {children} ); diff --git a/packages/twenty-front/src/modules/activities/components/ActivityTargetChips.tsx b/packages/twenty-front/src/modules/activities/components/ActivityTargetChips.tsx index dcc05bf3a0..e96ee4de05 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityTargetChips.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityTargetChips.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject'; import { RecordChip } from '@/object-record/components/RecordChip'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type ActivityTargetChipsProps = { activityTargetObjectRecords: ActivityTargetWithTargetRecord[]; @@ -12,7 +13,7 @@ type ActivityTargetChipsProps = { const StyledContainer = styled.div<{ maxWidth?: number }>` display: flex; flex-wrap: wrap; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : 'none')}; `; diff --git a/packages/twenty-front/src/modules/activities/components/CustomResolverFetchMoreLoader.tsx b/packages/twenty-front/src/modules/activities/components/CustomResolverFetchMoreLoader.tsx index dfdd32d737..f8f9576040 100644 --- a/packages/twenty-front/src/modules/activities/components/CustomResolverFetchMoreLoader.tsx +++ b/packages/twenty-front/src/modules/activities/components/CustomResolverFetchMoreLoader.tsx @@ -1,6 +1,7 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useInView } from 'react-intersection-observer'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type CustomResolverFetchMoreLoaderProps = { loading: boolean; @@ -14,11 +15,11 @@ const StyledContainer = styled.div` const StyledText = styled.div` align-items: center; box-shadow: none; - color: ${({ theme }) => theme.grayScale.gray9}; + color: ${themeCssVariables.grayScale.gray9}; display: flex; height: 32px; - margin-left: ${({ theme }) => theme.spacing(8)}; - padding-left: ${({ theme }) => theme.spacing(2)}; + margin-left: ${themeCssVariables.spacing[8]}; + padding-left: ${themeCssVariables.spacing[2]}; `; export const CustomResolverFetchMoreLoader = ({ diff --git a/packages/twenty-front/src/modules/activities/components/ParticipantChip.tsx b/packages/twenty-front/src/modules/activities/components/ParticipantChip.tsx index ee0ff6b9f9..44df0003d3 100644 --- a/packages/twenty-front/src/modules/activities/components/ParticipantChip.tsx +++ b/packages/twenty-front/src/modules/activities/components/ParticipantChip.tsx @@ -1,19 +1,23 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import React from 'react'; import { getDisplayNameFromParticipant } from '@/activities/emails/utils/getDisplayNameFromParticipant'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordChip } from '@/object-record/components/RecordChip'; import { Avatar } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledAvatar = styled(Avatar)` - margin-right: ${({ theme }) => theme.spacing(1)}; + margin-right: ${themeCssVariables.spacing[1]}; `; const StyledSenderName = styled.span<{ variant?: 'default' | 'bold' }>` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme, variant }) => - variant === 'bold' ? theme.font.weight.medium : theme.font.weight.regular}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${({ variant }) => + variant === 'bold' + ? themeCssVariables.font.weight.medium + : themeCssVariables.font.weight.regular}; overflow: hidden; text-overflow: ellipsis; `; @@ -23,23 +27,14 @@ const StyledContainer = styled.div` display: flex; `; -const StyledRecordChip = styled(RecordChip)<{ - participantChipVariant: 'default' | 'bold'; -}>` - font-weight: ${({ theme, participantChipVariant }) => - participantChipVariant === 'bold' - ? theme.font.weight.medium - : theme.font.weight.regular}; -`; - const StyledChip = styled.div` align-items: center; display: flex; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; height: 20px; box-sizing: border-box; white-space: nowrap; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; type ParticipantChipVariant = 'default' | 'bold'; @@ -65,10 +60,10 @@ export const ParticipantChip = ({ return ( {person ? ( - ) : ( diff --git a/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx index eee56973dd..66feefa7d8 100644 --- a/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/activities/components/SkeletonLoader.tsx @@ -1,27 +1,29 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSkeletonContainer = styled.div` align-items: center; width: 100%; - padding: ${({ theme }) => theme.spacing(8)}; + padding: ${themeCssVariables.spacing[8]}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; flex-wrap: wrap; align-content: flex-start; `; const StyledSkeletonSubSection = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; const StyledSkeletonSubSectionContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; justify-content: center; `; @@ -41,7 +43,7 @@ export const SKELETON_LOADER_HEIGHT_SIZES = { }; const SkeletonColumnLoader = ({ height }: { height: number }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const skeletonItems = Array.from({ length: 3 }).map((_, index) => ({ id: `skeleton-item-${index}`, })); diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadBottomBar.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadBottomBar.tsx index 7b56258711..771f075491 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadBottomBar.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadBottomBar.tsx @@ -1,15 +1,16 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconArrowBackUp, IconUserCircle } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledThreadBottomBar = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(6)}; - padding-right: ${({ theme }) => theme.spacing(6)}; - padding-top: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[2]}; + padding-left: ${themeCssVariables.spacing[6]}; + padding-right: ${themeCssVariables.spacing[6]}; + padding-top: ${themeCssVariables.spacing[4]}; `; export const ThreadBottomBar = () => { diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx index d83acafbe4..e9b2a362f8 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadHeader.tsx @@ -1,7 +1,8 @@ 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 { themeCssVariables } from 'twenty-ui/theme-constants'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; @@ -14,10 +15,10 @@ const StyledContainer = styled.div` align-items: flex-start; display: flex; flex-direction: column; - padding: ${({ theme }) => theme.spacing(6)}; - gap: ${({ theme }) => theme.spacing(6)}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; - background: ${({ theme }) => theme.background.secondary}; + padding: ${themeCssVariables.spacing[6]}; + gap: ${themeCssVariables.spacing[6]}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; + background: ${themeCssVariables.background.secondary}; `; const StyledHead = styled.div` @@ -26,16 +27,16 @@ const StyledHead = styled.div` const StyledHeading = styled.h2` margin: 0; - margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${themeCssVariables.spacing[3]}; max-width: 100%; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `; const StyledContent = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; width: 100%; `; diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx index 50fd780d9a..731fb831ed 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useState } from 'react'; import { EmailThreadMessageBody } from '@/activities/emails/components/EmailThreadMessageBody'; @@ -9,13 +9,14 @@ import { EmailThreadNotShared } from '@/activities/emails/components/EmailThread import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/constants'; import { MessageParticipantRole } from 'twenty-shared/types'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { MessageChannelVisibility } from '~/generated/graphql'; const StyledThreadMessage = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; flex-direction: column; - padding: ${({ theme }) => theme.spacing(4, 0)}; + padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[0]}; `; const StyledThreadMessageHeader = styled.div` @@ -23,12 +24,12 @@ const StyledThreadMessageHeader = styled.div` cursor: pointer; flex-direction: column; justify-content: space-between; - margin-bottom: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(0, 6)}; + margin-bottom: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[6]}; `; const StyledThreadMessageBody = styled.div` - padding: ${({ theme }) => theme.spacing(0, 6)}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[6]}; `; type EmailThreadMessageProps = { diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBody.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBody.tsx index 438504018f..20e94c4019 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBody.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBody.tsx @@ -1,25 +1,26 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { motion } from 'framer-motion'; import Linkify from 'linkify-react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseInOut } from 'twenty-ui/utilities'; const StyledThreadMessageBody = styled(motion.div)` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: column; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-top: ${themeCssVariables.spacing[4]}; white-space: pre-line; overflow-wrap: break-word; a { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; text-decoration: underline; - text-decoration-color: ${({ theme }) => theme.font.color.primary}; + text-decoration-color: ${themeCssVariables.font.color.primary}; &:hover { - color: ${({ theme }) => theme.font.color.tertiary}; - text-decoration-color: ${({ theme }) => theme.border.color.strong}; + color: ${themeCssVariables.font.color.tertiary}; + text-decoration-color: ${themeCssVariables.border.color.strong}; } } `; diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBodyPreview.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBodyPreview.tsx index 40d9d4353f..3c2a044f33 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBodyPreview.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageBodyPreview.tsx @@ -1,12 +1,13 @@ import React from 'react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledThreadMessageBodyPreview = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; `; type EmailThreadMessageBodyPreviewProps = { diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageReceivers.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageReceivers.tsx index 23cf30e1a3..59a1b1830a 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageReceivers.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageReceivers.tsx @@ -1,18 +1,20 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { getDisplayNameFromParticipant } from '@/activities/emails/utils/getDisplayNameFromParticipant'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EmailThreadMessageReceiversProps = { receivers: EmailThreadMessageParticipant[]; }; const StyledThreadMessageReceivers = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - font-size: ${({ theme }) => theme.font.size.xs}; - padding: ${({ theme }) => theme.spacing(2, 0, 0, 1)}; + font-size: ${themeCssVariables.font.size.xs}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[0]} + ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; width: 50%; `; diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx index 6dc9809bd2..a0a920677e 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadMessageSender.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ParticipantChip } from '@/activities/components/ParticipantChip'; import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { AppTooltip, TooltipPosition } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { beautifyPastDateRelativeToNow, @@ -18,8 +19,8 @@ const StyledEmailThreadMessageSender = styled.div` const StyledThreadMessageSentAt = styled.div` align-items: flex-end; display: flex; - 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 EmailThreadMessageSenderProps = { diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadNotShared.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadNotShared.tsx index 138220fcac..a92347f19b 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadNotShared.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadNotShared.tsx @@ -1,27 +1,29 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { AppTooltip, IconLock, TooltipDelay } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { MessageChannelVisibility } from '~/generated/graphql'; const StyledContainer = styled.div<{ isCompact?: boolean }>` align-items: center; display: flex; flex: ${({ isCompact }) => (isCompact ? '0 0 auto' : '1 0 0')}; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; height: 20px; margin-left: auto; width: ${({ isCompact }) => (isCompact ? 'auto' : '100%')}; - min-width: ${({ theme }) => `${theme.spacing(21)}`}; - padding: ${({ theme }) => theme.spacing(0, 1)}; + min-width: ${themeCssVariables.spacing[21]}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; border-radius: 4px; - border: 1px solid ${({ theme }) => theme.border.color.light}; - background: ${({ theme }) => theme.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + background: ${themeCssVariables.background.transparent.lighter}; - color: ${({ theme }) => theme.font.color.tertiary}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-weight: ${themeCssVariables.font.weight.regular}; + font-size: ${themeCssVariables.font.size.sm}; flex: 1; `; @@ -33,7 +35,7 @@ export const EmailThreadNotShared = ({ visibility, }: EmailThreadNotSharedProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const containerId = 'email-thread-not-shared'; const isCompact = visibility === MessageChannelVisibility.SUBJECT; 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 3e4c380a57..895073a0c3 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailThreadPreview.tsx @@ -1,10 +1,12 @@ -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import { ActivityRow } from '@/activities/components/ActivityRow'; import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared'; import { useOpenEmailThreadInCommandMenu } from '@/command-menu/hooks/useOpenEmailThreadInCommandMenu'; -import { useTheme } from '@emotion/react'; import { Avatar } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { MessageChannelVisibility, type TimelineThread, @@ -24,38 +26,38 @@ const StyledParticipantsContainer = styled.div` `; const StyledAvatar = styled(Avatar)` - margin-left: ${({ theme }) => theme.spacing(-1)}; + margin-left: calc(-1 * ${themeCssVariables.spacing[1]}); `; const StyledSenderNames = styled.span` display: flex; - margin: ${({ theme }) => theme.spacing(0, 1)}; + margin: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `; const StyledThreadCount = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledSubjectAndBody = styled.div` align-items: center; display: flex; flex: 1; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; overflow: hidden; `; const StyledSubject = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; `; const StyledBody = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -63,9 +65,9 @@ const StyledBody = styled.span` `; const StyledReceivedAt = styled.div` - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding: ${({ theme }) => theme.spacing(0, 1)}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.regular}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[1]}; `; type EmailThreadPreviewProps = { @@ -105,7 +107,7 @@ export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => { }; const isDisabled = visibility !== MessageChannelVisibility.SHARE_EVERYTHING; - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/activities/emails/components/EmailsCard.tsx b/packages/twenty-front/src/modules/activities/emails/components/EmailsCard.tsx index 047a3fe63d..399f669f2d 100644 --- a/packages/twenty-front/src/modules/activities/emails/components/EmailsCard.tsx +++ b/packages/twenty-front/src/modules/activities/emails/components/EmailsCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { ActivityList } from '@/activities/components/ActivityList'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; @@ -22,6 +22,7 @@ import { EMPTY_PLACEHOLDER_TRANSITION_PROPS, Section, } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type TimelineThread, type TimelineThreadsWithTotal, @@ -30,19 +31,20 @@ import { const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(6, 6, 2)}; + gap: ${themeCssVariables.spacing[6]}; + padding: ${themeCssVariables.spacing[6]} ${themeCssVariables.spacing[6]} + ${themeCssVariables.spacing[2]}; height: 100%; overflow: auto; `; const StyledH1Title = styled(H1Title)` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledEmailCount = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; `; export const EmailsCard = () => { diff --git a/packages/twenty-front/src/modules/activities/files/components/AttachmentList.tsx b/packages/twenty-front/src/modules/activities/files/components/AttachmentList.tsx index c19ba08009..f587bfff07 100644 --- a/packages/twenty-front/src/modules/activities/files/components/AttachmentList.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/AttachmentList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { lazy, type ReactElement, Suspense, useState } from 'react'; import { createPortal } from 'react-dom'; @@ -20,6 +20,7 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { IconDownload, IconX } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { PermissionFlagType, FeatureFlagKey, @@ -45,28 +46,29 @@ const StyledContainer = styled.div` display: flex; flex-direction: column; justify-content: center; - padding: ${({ theme }) => theme.spacing(2, 6, 6)}; - width: calc(100% - ${({ theme }) => theme.spacing(12)}); + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[6]} + ${themeCssVariables.spacing[6]}; + width: calc(100% - ${themeCssVariables.spacing[12]}); height: 100%; `; const StyledTitleBar = styled.h3` display: flex; justify-content: space-between; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[4]}; place-items: center; width: 100%; `; const StyledTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledCount = styled.span` - color: ${({ theme }) => theme.font.color.light}; - margin-left: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.light}; + margin-left: ${themeCssVariables.spacing[2]}; `; const StyledDropZoneContainer = styled.div` @@ -77,7 +79,7 @@ const StyledDropZoneContainer = styled.div` const StyledLoadingContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.primary}; + background: ${themeCssVariables.background.primary}; display: flex; height: 80vh; justify-content: center; @@ -85,9 +87,9 @@ const StyledLoadingContainer = styled.div` `; const StyledLoadingText = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledHeader = styled.div` @@ -99,7 +101,7 @@ const StyledHeader = styled.div` `; const StyledModalTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; `; const StyledModalHeader = styled(Modal.Header)` @@ -112,14 +114,14 @@ const StyledModalContent = styled(Modal.Content)` `; const StyledModal = styled(Modal)` - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledButtonContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const PREVIEW_MODAL_ID = 'preview-modal'; diff --git a/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx b/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx index 224c22bf23..c20324ab97 100644 --- a/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/AttachmentRow.tsx @@ -12,14 +12,15 @@ import { import { getFileCategoryFromExtension } from '@/object-record/record-field/ui/utils/getFileCategoryFromExtension'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { FileIcon } from '@/file/components/FileIcon'; import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag'; import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { isNavigationModifierPressed } from 'twenty-ui/utilities'; import { FeatureFlagKey, @@ -31,7 +32,7 @@ import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension'; const StyledLeftContent = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; width: 100%; overflow: auto; @@ -41,12 +42,12 @@ const StyledLeftContent = styled.div` const StyledRightContent = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing['0.5']}; `; const StyledCalendarIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; `; @@ -55,7 +56,7 @@ const StyledLink = styled.a` appearance: none; background: none; border: none; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; cursor: pointer; display: flex; font-family: inherit; @@ -66,7 +67,7 @@ const StyledLink = styled.a` width: 100%; :hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; @@ -84,7 +85,7 @@ export const AttachmentRow = ({ attachment, onPreview, }: AttachmentRowProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isEditing, setIsEditing] = useState(false); const isFilesFieldMigrated = useIsFeatureEnabled( diff --git a/packages/twenty-front/src/modules/activities/files/components/DocumentViewer.tsx b/packages/twenty-front/src/modules/activities/files/components/DocumentViewer.tsx index 3eb9f8c4bf..92db34973f 100644 --- a/packages/twenty-front/src/modules/activities/files/components/DocumentViewer.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/DocumentViewer.tsx @@ -7,13 +7,14 @@ import { import { getFileType } from '@/activities/files/utils/getFileType'; import DocViewer, { DocViewerRenderers } from '@cyntler/react-doc-viewer'; import '@cyntler/react-doc-viewer/dist/index.css'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconDownload } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension'; const MS_OFFICE_EXTENSIONS = [ @@ -32,7 +33,7 @@ const StyledDocumentViewerContainer = styled.div` height: calc(100vh - 200px); min-height: 500px; width: 100%; - background: ${({ theme }) => theme.background.secondary}; + background: ${themeCssVariables.background.secondary}; #react-doc-viewer #header-bar { display: none; @@ -60,58 +61,58 @@ const StyledUnavailablePreviewContainer = styled.div` align-items: center; justify-content: center; height: 100%; - gap: ${({ theme }) => theme.spacing(4)}; - padding: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[4]}; + padding: ${themeCssVariables.spacing[8]}; text-align: center; `; const StyledMessage = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.lg}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.lg}; max-width: 400px; `; const StyledLightMessage = 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}; `; const StyledTitle = 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 StyledCsvTable = styled.table` border-collapse: collapse; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; text-align: left; width: 100%; th { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - color: ${({ theme }) => theme.font.color.tertiary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - height: ${({ theme }) => theme.spacing(8)}; - padding: 0 ${({ theme }) => theme.spacing(2)}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; + color: ${themeCssVariables.font.color.tertiary}; + font-weight: ${themeCssVariables.font.weight.medium}; + height: ${themeCssVariables.spacing[8]}; + padding: 0 ${themeCssVariables.spacing[2]}; } td { - color: ${({ theme }) => theme.font.color.secondary}; - height: ${({ theme }) => theme.spacing(8)}; + color: ${themeCssVariables.font.color.secondary}; + height: ${themeCssVariables.spacing[8]}; max-width: 200px; overflow: hidden; - padding: 0 ${({ theme }) => theme.spacing(2)}; + padding: 0 ${themeCssVariables.spacing[2]}; text-overflow: ellipsis; white-space: nowrap; } tbody tr { - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; } tbody tr:hover { - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } `; @@ -200,7 +201,7 @@ export const DocumentViewer = ({ documentExtension, }: DocumentViewerProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [csvPreview, setCsvPreview] = useState( undefined, ); diff --git a/packages/twenty-front/src/modules/activities/files/components/DropZone.tsx b/packages/twenty-front/src/modules/activities/files/components/DropZone.tsx index 025d8c0368..c6b6f142c1 100644 --- a/packages/twenty-front/src/modules/activities/files/components/DropZone.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/DropZone.tsx @@ -1,42 +1,43 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useDropzone } from 'react-dropzone'; import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; import { IconUpload } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border: ${({ theme }) => `2px dashed ${theme.border.color.strong}`}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.secondary}; + border: 2px dashed ${themeCssVariables.border.color.strong}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; flex-direction: column; height: 100%; justify-content: center; - border-radius: ${({ theme }) => theme.border.radius.sm}; text-align: center; `; const StyledUploadDragTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - line-height: ${({ theme }) => theme.text.lineHeight.md}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.medium}; + line-height: ${themeCssVariables.text.lineHeight.md}; margin-bottom: 8px; `; const StyledUploadDragSubTitle = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.md}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.md}; `; const StyledUploadIcon = styled(IconUpload)` - color: ${({ theme }) => theme.font.color.tertiary}; - margin-bottom: ${({ theme }) => theme.spacing(3)}; + color: ${themeCssVariables.font.color.tertiary}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; type DropZoneProps = { @@ -49,7 +50,7 @@ export const DropZone = ({ onUploadFiles, }: DropZoneProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { maxFileSize } = useSpreadsheetImportInternal(); const { getRootProps, getInputProps, isDragActive } = useDropzone({ diff --git a/packages/twenty-front/src/modules/activities/files/components/FilesCard.tsx b/packages/twenty-front/src/modules/activities/files/components/FilesCard.tsx index b038914eb1..c458545475 100644 --- a/packages/twenty-front/src/modules/activities/files/components/FilesCard.tsx +++ b/packages/twenty-front/src/modules/activities/files/components/FilesCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ChangeEvent, useRef, useState } from 'react'; import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; diff --git a/packages/twenty-front/src/modules/activities/notes/components/NoteList.tsx b/packages/twenty-front/src/modules/activities/notes/components/NoteList.tsx index b46c5e238b..ef152d7d32 100644 --- a/packages/twenty-front/src/modules/activities/notes/components/NoteList.tsx +++ b/packages/twenty-front/src/modules/activities/notes/components/NoteList.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactElement } from 'react'; import { type Note } from '@/activities/types/Note'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { NoteTile } from './NoteTile'; @@ -24,25 +25,25 @@ const StyledContainer = styled.div` const StyledTitleBar = styled.h3` display: flex; justify-content: space-between; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[4]}; place-items: center; width: 100%; `; const StyledTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledCount = styled.span` - color: ${({ theme }) => theme.font.color.light}; - margin-left: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.light}; + margin-left: ${themeCssVariables.spacing[2]}; `; const StyledNoteContainer = styled.div` display: grid; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; grid-auto-rows: 1fr; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); width: 100%; diff --git a/packages/twenty-front/src/modules/activities/notes/components/NoteTile.tsx b/packages/twenty-front/src/modules/activities/notes/components/NoteTile.tsx index 55b08f9b53..58c37dcd47 100644 --- a/packages/twenty-front/src/modules/activities/notes/components/NoteTile.tsx +++ b/packages/twenty-front/src/modules/activities/notes/components/NoteTile.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell'; @@ -9,12 +9,13 @@ import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordIn import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordFieldsScopeContextProvider } from '@/object-record/record-field-list/contexts/RecordFieldsScopeContext'; import { FieldContextProvider } from '@/object-record/record-field/ui/components/FieldContextProvider'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCard = styled.div<{ isSingleNote: boolean }>` align-items: flex-start; - background: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; height: 300px; @@ -28,22 +29,22 @@ const StyledCardDetailsContainer = styled.div` cursor: pointer; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; height: calc(100% - 45px); justify-content: start; - padding: ${({ theme }) => theme.spacing(4)}; - width: calc(100% - ${({ theme }) => theme.spacing(8)}); + padding: ${themeCssVariables.spacing[4]}; + width: calc(100% - ${themeCssVariables.spacing[8]}); box-sizing: border-box; `; const StyledNoteTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledCardContent = styled.div` align-self: stretch; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; line-break: anywhere; overflow: hidden; text-overflow: ellipsis; @@ -54,14 +55,14 @@ const StyledCardContent = styled.div` const StyledFooter = styled.div` align-items: center; align-self: stretch; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; - color: ${({ theme }) => theme.font.color.primary}; + border-top: 1px solid ${themeCssVariables.border.color.light}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: center; - padding: ${({ theme }) => theme.spacing(2)}; - width: calc(100% - ${({ theme }) => theme.spacing(4)}); + padding: ${themeCssVariables.spacing[2]}; + width: calc(100% - ${themeCssVariables.spacing[4]}); `; export const NoteTile = ({ diff --git a/packages/twenty-front/src/modules/activities/notes/components/NotesCard.tsx b/packages/twenty-front/src/modules/activities/notes/components/NotesCard.tsx index c043431b05..dbfcb0f877 100644 --- a/packages/twenty-front/src/modules/activities/notes/components/NotesCard.tsx +++ b/packages/twenty-front/src/modules/activities/notes/components/NotesCard.tsx @@ -7,7 +7,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx index 4d6e6eca67..e80886d1ab 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx index aa5958c907..e515d9ba0b 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskList.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactElement } from 'react'; import { ActivityList } from '@/activities/components/ActivityList'; import { type Task } from '@/activities/types/Task'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { TaskRow } from './TaskRow'; type TaskListProps = { @@ -18,28 +19,28 @@ const StyledContainer = styled.div` display: flex; flex-direction: column; justify-content: center; - padding: 8px ${({ theme }) => theme.spacing(6)}; + padding: 8px ${themeCssVariables.spacing[6]}; - width: calc(100% - ${({ theme }) => theme.spacing(12)}); + width: calc(100% - ${themeCssVariables.spacing[12]}); `; const StyledTitleBar = styled.div` display: flex; justify-content: space-between; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[4]}; place-items: center; width: 100%; `; const StyledTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledCount = styled.span` - color: ${({ theme }) => theme.font.color.light}; - margin-left: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.light}; + margin-left: ${themeCssVariables.spacing[2]}; `; export const TaskList = ({ title, tasks, button }: TaskListProps) => ( diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx index 0ead5fe577..f62fc6f9ce 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskRow.tsx @@ -1,5 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { useContext } from 'react'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell'; @@ -16,12 +16,14 @@ import { RecordFieldsScopeContextProvider } from '@/object-record/record-field-l import { FieldContextProvider } from '@/object-record/record-field/ui/components/FieldContextProvider'; import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { Checkbox, CheckboxShape } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCompleteTask } from '@/activities/tasks/hooks/useCompleteTask'; const StyledTaskBody = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - max-width: calc(80% - ${({ theme }) => theme.spacing(2)}); + max-width: calc(80% - ${themeCssVariables.spacing[2]}); text-overflow: ellipsis; overflow: hidden; padding-bottom: 1px; @@ -30,9 +32,9 @@ const StyledTaskBody = styled.div` const StyledTaskTitle = styled.div<{ completed: boolean; }>` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - padding: 0 ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; + padding: 0 ${themeCssVariables.spacing[2]}; padding-bottom: 1px; text-decoration: ${({ completed }) => (completed ? 'line-through' : 'none')}; white-space: nowrap; @@ -46,11 +48,13 @@ const StyledDueDate = styled.div<{ isPast: boolean; }>` align-items: center; - color: ${({ theme, isPast }) => - isPast ? theme.font.color.danger : theme.font.color.secondary}; + color: ${({ isPast }) => + isPast + ? themeCssVariables.font.color.danger + : themeCssVariables.font.color.secondary}; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[1]}; white-space: nowrap; `; @@ -66,7 +70,7 @@ const StyledActivityTargetsContainer = styled.div` `; const StyledPlaceholder = styled.div` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; `; const StyledLeftSideContainer = styled.div` @@ -82,7 +86,7 @@ const StyledCheckboxContainer = styled.div` `; export const TaskRow = ({ task }: { task: Task }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { openRecordInCommandMenu } = useOpenRecordInCommandMenu(); const body = getActivitySummary(task?.bodyV2?.blocknote ?? null); diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TasksCard.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TasksCard.tsx index 54bd8f5f73..4148545235 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TasksCard.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TasksCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { TaskGroups } from '@/activities/tasks/components/TaskGroups'; import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx index d3bd559b29..e287f4e674 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactElement } from 'react'; import { EventsGroup } from '@/activities/timeline-activities/components/EventsGroup'; @@ -9,6 +9,7 @@ import { type ActivityTargetableObject } from '@/activities/types/ActivityTarget import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventListProps = { targetableObject: ActivityTargetableObject; @@ -24,7 +25,7 @@ const StyledTimelineContainer = styled.div` display: flex; flex: 1 0 0; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: flex-start; `; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx index a61b063a50..45c955a018 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventRow.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useContext } from 'react'; @@ -14,15 +14,16 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons'; const StyledTimelineItemContainer = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; height: 'auto'; justify-content: space-between; overflow: hidden; @@ -38,7 +39,7 @@ const StyledIconContainer = styled.div` display: flex; align-items: center; justify-content: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; height: 16px; width: 16px; margin: 5px; @@ -56,7 +57,7 @@ const StyledVerticalLineContainer = styled.div` `; const StyledVerticalLine = styled.div` - background: ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.border.color.light}; width: 2px; height: 100%; `; @@ -66,7 +67,7 @@ const StyledSummary = styled.summary` display: flex; flex: 1; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; width: 100%; `; @@ -75,10 +76,10 @@ const StyledItemContainer = styled.div<{ isMarginBottom?: boolean }>` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow: hidden; - margin-bottom: ${({ isMarginBottom, theme }) => - isMarginBottom ? theme.spacing(3) : 0}; + margin-bottom: ${({ isMarginBottom }) => + isMarginBottom ? themeCssVariables.spacing[3] : '0'}; min-height: 26px; `; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx index 175481e347..f241d539a0 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventsGroup.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { EventRow } from '@/activities/timeline-activities/components/EventRow'; import { type EventGroup } from '@/activities/timeline-activities/utils/groupEventsByMonth'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventsGroupProps = { group: EventGroup; @@ -14,22 +15,22 @@ type EventsGroupProps = { const StyledActivityGroup = styled.div` display: flex; flex-flow: column; - gap: ${({ theme }) => theme.spacing(4)}; - margin-bottom: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; + margin-bottom: ${themeCssVariables.spacing[4]}; width: 100%; `; const StyledActivityGroupContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(3)}; - margin-top: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${themeCssVariables.spacing[3]}; + margin-top: ${themeCssVariables.spacing[3]}; position: relative; `; const StyledActivityGroupBar = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; height: 100%; @@ -42,14 +43,14 @@ const StyledActivityGroupBar = styled.div` const StyledMonthSeperator = styled.div` align-items: center; align-self: stretch; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - font-size: ${({ theme }) => theme.font.size.xs}; + gap: ${themeCssVariables.spacing[4]}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + font-size: ${themeCssVariables.font.size.xs}; `; const StyledMonthSeperatorLine = styled.div` - background: ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.border.color.light}; border-radius: 50px; flex: 1 0 0; height: 1px; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx index bf75ebcd12..b86946a1ac 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/TimelineCard.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader'; import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; @@ -6,7 +6,6 @@ import { EventList } from '@/activities/timeline-activities/components/EventList import { useTimelineActivities } from '@/activities/timeline-activities/hooks/useTimelineActivities'; import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { t } from '@lingui/core/macro'; import { AnimatedPlaceholder, @@ -17,25 +16,26 @@ import { EMPTY_PLACEHOLDER_TRANSITION_PROPS, } from 'twenty-ui/layout'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledMainContainer = styled.div` align-items: flex-start; align-self: stretch; - border-top: ${({ theme }) => - useIsMobile() ? `1px solid ${theme.border.color.medium}` : 'none'}; + border-top: none; display: flex; flex-direction: column; overflow: auto; justify-content: center; - padding-top: ${({ theme }) => theme.spacing(6)}; - padding-right: ${({ theme }) => theme.spacing(6)}; - padding-left: ${({ theme }) => theme.spacing(6)}; - gap: ${({ theme }) => theme.spacing(4)}; + padding-top: ${themeCssVariables.spacing[6]}; + padding-right: ${themeCssVariables.spacing[6]}; + padding-left: ${themeCssVariables.spacing[6]}; + gap: ${themeCssVariables.spacing[4]}; @media (max-width: ${MOBILE_VIEWPORT}px) { - padding-right: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(1)}; + border-top: 1px solid ${themeCssVariables.border.color.medium}; + padding-right: ${themeCssVariables.spacing[1]}; + padding-left: ${themeCssVariables.spacing[1]}; } `; @@ -43,7 +43,7 @@ const StyledRightDrawerAnimatedPlaceholderEmptyContainer = styled( AnimatedPlaceholderEmptyContainer, )` height: auto; - padding-top: ${({ theme }) => theme.spacing(8)}; + padding-top: ${themeCssVariables.spacing[8]}; `; export const TimelineCard = () => { diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx index 0822beeadd..bffcec36c3 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/activity/components/EventRowActivity.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { @@ -13,11 +13,12 @@ import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordF import { isNonEmptyString } from '@sniptt/guards'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventRowActivityProps = EventRowDynamicComponentProps; const StyledLinkedActivity = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; cursor: pointer; text-decoration: underline; width: 100%; @@ -29,21 +30,21 @@ const StyledLinkedActivity = styled.span` const StyledRowContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: space-between; `; const StyledEventRow = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; width: 100%; `; const StyledRow = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow: hidden; `; @@ -51,12 +52,12 @@ const StyledItemTitleDate = styled.div` @media (max-width: ${MOBILE_VIEWPORT}px) { display: none; } - color: ${({ theme }) => theme.font.color.tertiary}; - padding: 0 ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: 0 ${themeCssVariables.spacing[1]}; `; export const StyledEventRowItemText = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; `; export const EventRowActivity = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx index 715549a278..5fb402c5f1 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { isUndefined } from '@sniptt/guards'; @@ -13,6 +13,7 @@ import { UserContext } from '@/users/contexts/UserContext'; import { useContext } from 'react'; import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { formatToHumanReadableDay, formatToHumanReadableMonth, @@ -26,14 +27,14 @@ const StyledEventCardCalendarEventContainer = styled.div<{ cursor: ${({ canOpen }) => (canOpen ? 'pointer' : 'not-allowed')}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; width: 100%; `; const StyledCalendarEventContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: center; overflow: hidden; width: 100%; @@ -43,13 +44,13 @@ const StyledCalendarEventTop = styled.div` align-items: center; display: flex; width: 100%; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; `; const StyledCalendarEventTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -57,37 +58,37 @@ const StyledCalendarEventTitle = styled.div` const StyledCalendarEventBody = styled.div` align-items: flex-start; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex: 1 0 0; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: center; `; const StyledCalendarEventDateCard = styled.div` display: flex; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; flex-direction: column; justify-content: center; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; - border-radius: ${({ theme }) => theme.spacing(1)}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-radius: ${themeCssVariables.spacing[1]}; + border: 1px solid ${themeCssVariables.border.color.medium}; `; const StyledCalendarEventDateCardMonth = styled.div` - color: ${({ theme }) => theme.font.color.danger}; - font-size: ${({ theme }) => theme.font.size.xxs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + color: ${themeCssVariables.font.color.danger}; + font-size: ${themeCssVariables.font.size.xxs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; `; const StyledCalendarEventDateCardDay = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; `; export const EventCardCalendarEvent = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx index fcfa147645..bd797d6913 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; @@ -11,19 +11,20 @@ import { StyledEventRowItemColumn, } from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; import { isTimelineActivityWithLinkedRecord } from '@/activities/timeline-activities/types/TimelineActivity'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventRowCalendarEventProps = EventRowDynamicComponentProps; const StyledEventRowCalendarEventContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledRowContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const EventRowCalendarEvent = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx index 502368d82e..0616307371 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCard.tsx @@ -1,6 +1,7 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Card } from 'twenty-ui/layout'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventCardProps = { children: React.ReactNode; @@ -12,10 +13,10 @@ const StyledCardContainer = styled.div` display: flex; flex-direction: column; flex-grow: 1; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; width: 400px; - padding: ${({ theme }) => theme.spacing(2)} 0px - ${({ theme }) => theme.spacing(1)} 0px; + padding: ${themeCssVariables.spacing[2]} 0px ${themeCssVariables.spacing[1]} + 0px; @media (max-width: ${MOBILE_VIEWPORT}px) { width: 300px; @@ -23,15 +24,15 @@ const StyledCardContainer = styled.div` `; const StyledCard = styled(Card)` - background: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; box-sizing: border-box; display: flex; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; flex-direction: column; align-items: flex-start; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: center; align-self: stretch; `; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx index f8fe48ae31..4c3ce89b04 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventCardToggleButton.tsx @@ -1,6 +1,7 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { IconButton } from 'twenty-ui/input'; import { IconChevronDown, IconChevronUp } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventCardToggleButtonProps = { isOpen: boolean; @@ -8,7 +9,7 @@ type EventCardToggleButtonProps = { }; const StyledButtonContainer = styled.div` - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; `; export const EventCardToggleButton = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx index 85682bf183..b09d2b9581 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/components/EventRowDynamicComponent.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { EventRowActivity } from '@/activities/timeline-activities/rows/activity/components/EventRowActivity'; import { EventRowCalendarEvent } from '@/activities/timeline-activities/rows/calendar/components/EventRowCalendarEvent'; @@ -7,6 +7,7 @@ import { EventRowMessage } from '@/activities/timeline-activities/rows/message/c import { type TimelineActivity } from '@/activities/timeline-activities/types/TimelineActivity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; export interface EventRowDynamicComponentProps { labelIdentifierValue: string; @@ -19,14 +20,14 @@ export interface EventRowDynamicComponentProps { export const StyledEventRowItemColumn = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const StyledEventRowItemAction = styled(StyledEventRowItemColumn)` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; export const EventRowDynamicComponent = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx index 6c65d37ce5..a74330005a 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { EventFieldDiffLabel } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel'; import { EventFieldDiffValue } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue'; @@ -6,6 +6,7 @@ import { EventFieldDiffValueEffect } from '@/activities/timeline-activities/rows import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { Trans } from '@lingui/react/macro'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventFieldDiffProps = { diffRecord: Record; @@ -18,7 +19,7 @@ const StyledEventFieldDiffContainer = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; height: 24px; max-width: 100%; overflow: hidden; @@ -27,7 +28,7 @@ const StyledEventFieldDiffContainer = styled.div` `; const StyledEmptyValue = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export const EventFieldDiff = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx index 1e7ac60b5c..57f86569db 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffLabel.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { Icon123, useIcons } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventFieldDiffLabelProps = { fieldMetadataItem: FieldMetadataItem; @@ -10,8 +11,8 @@ type EventFieldDiffLabelProps = { const StyledUpdatedFieldContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; - color: ${({ theme }) => theme.font.color.tertiary}; + gap: ${themeCssVariables.spacing[1]}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledUpdatedFieldIconContainer = styled.div` diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx index 967bb32e7f..cb4f4258f4 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiffValue.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { FieldDisplay } from '@/object-record/record-field/ui/components/FieldDisplay'; import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext'; import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventFieldDiffValueProps = { diffArtificialRecordStoreId: string; @@ -18,7 +19,7 @@ const StyledEventFieldDiffValue = styled.div` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; `; export const EventFieldDiffValue = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx index c74e2c536b..ac77fcb940 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObject.tsx @@ -4,23 +4,24 @@ import { StyledEventRowItemColumn, } from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; import { EventRowMainObjectUpdated } from '@/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventRowMainObjectProps = EventRowDynamicComponentProps; const StyledMainContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; width: 100%; `; const StyledRowContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: space-between; `; @@ -28,14 +29,14 @@ const StyledItemTitleDate = styled.div` @media (max-width: ${MOBILE_VIEWPORT}px) { display: none; } - color: ${({ theme }) => theme.font.color.tertiary}; - padding: 0 ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: 0 ${themeCssVariables.spacing[1]}; `; const StyledRow = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow: hidden; `; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx index a2567c02d8..1721579277 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/main-object/components/EventRowMainObjectUpdated.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; @@ -10,6 +10,7 @@ import { type TimelineActivity } from '@/activities/timeline-activities/types/Ti import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventRowMainObjectUpdatedProps = { mainObjectMetadataItem: ObjectMetadataItem; @@ -22,7 +23,7 @@ type EventRowMainObjectUpdatedProps = { const StyledRowContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: space-between; `; @@ -30,21 +31,21 @@ const StyledItemTitleDate = styled.div` @media (max-width: ${MOBILE_VIEWPORT}px) { display: none; } - color: ${({ theme }) => theme.font.color.tertiary}; - padding: 0 ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: 0 ${themeCssVariables.spacing[1]}; `; const StyledRow = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; overflow: hidden; `; const StyledEventRowMainObjectUpdatedContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; width: 100%; `; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx index 49fb50cfdc..127e4e4989 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage'; import { EventCardMessageBodyNotShared } from '@/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared'; @@ -11,6 +11,7 @@ import { Trans, useLingui } from '@lingui/react/macro'; import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledEventCardMessageContainer = styled.div<{ canOpen?: boolean }>` cursor: ${({ canOpen }) => (canOpen ? 'pointer' : 'not-allowed')}; @@ -22,27 +23,27 @@ const StyledEventCardMessageContainer = styled.div<{ canOpen?: boolean }>` const StyledEmailContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; justify-content: center; `; const StyledEmailTop = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledEmailTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `; const StyledEmailParticipants = 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}; `; const StyledEmailBody = styled.div` diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared.tsx index 559c526b2d..42268b5b3d 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared.tsx @@ -1,29 +1,30 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans } from '@lingui/react/macro'; import { IconLock } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledEmailBodyNotSharedContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.spacing(1)}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.spacing[1]}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; height: 80px; justify-content: center; - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; width: 100%; `; const StyledEmailBodyNotSharedIconContainer = styled.div` display: flex; - width: ${({ theme }) => theme.icon.size.sm}px; - height: ${({ theme }) => theme.icon.size.sm}px; + width: calc(${themeCssVariables.icon.size.sm} * 1px); + height: calc(${themeCssVariables.icon.size.sm} * 1px); justify-content: center; align-items: center; `; @@ -31,7 +32,7 @@ const StyledEmailBodyNotSharedIconContainer = styled.div` const StyledEmailBodyNotShared = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const EventCardMessageBodyNotShared = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageForbidden.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageForbidden.tsx index eee28a521e..92a15f8601 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageForbidden.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventCardMessageForbidden.tsx @@ -1,6 +1,8 @@ import { EventCardMessageBodyNotShared } from '@/activities/timeline-activities/rows/message/components/EventCardMessageBodyNotShared'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans } from '@lingui/react/macro'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; + const StyledEventCardMessageContainer = styled.div` display: flex; flex-direction: column; @@ -10,17 +12,17 @@ const StyledEventCardMessageContainer = styled.div` const StyledEmailContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; justify-content: center; width: 100%; `; const StyledEmailTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; display: flex; flex-direction: column; - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; export const EventCardMessageForbidden = ({ diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx index b40aa4fb2f..043f9dfda2 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/message/components/EventRowMessage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; @@ -11,19 +11,20 @@ import { } from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent'; import { EventCardMessage } from '@/activities/timeline-activities/rows/message/components/EventCardMessage'; import { isTimelineActivityWithLinkedRecord } from '@/activities/timeline-activities/types/TimelineActivity'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type EventRowMessageProps = EventRowDynamicComponentProps; const StyledEventRowMessageContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledRowContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const EventRowMessage = ({ diff --git a/packages/twenty-front/src/modules/ai/components/AIChatAssistantMessageRenderer.tsx b/packages/twenty-front/src/modules/ai/components/AIChatAssistantMessageRenderer.tsx index 2f47d38372..c793ceb711 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatAssistantMessageRenderer.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatAssistantMessageRenderer.tsx @@ -6,33 +6,35 @@ import { IconDotsVertical } from 'twenty-ui/display'; import { LazyMarkdownRenderer } from '@/ai/components/LazyMarkdownRenderer'; import { ToolStepRenderer } from '@/ai/components/ToolStepRenderer'; import { groupContiguousThinkingStepParts } from '@/ai/utils/groupContiguousThinkingStepParts'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { isToolUIPart, type ToolUIPart } from 'ai'; import { type ExtendedUIMessagePart } from 'twenty-shared/ai'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledMessagePartsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledLoadingIconContainer = styled.div` align-items: center; - border: ${({ theme }) => `1px solid ${theme.border.color.light}`}; - border-radius: ${({ theme }) => theme.border.radius.md}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; justify-content: center; - padding-inline: ${({ theme }) => theme.spacing(1)}; + padding-inline: ${themeCssVariables.spacing[1]}; `; const StyledLoadingIcon = styled(IconDotsVertical)` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; transform: rotate(90deg); `; const InitialLoadingIndicator = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( diff --git a/packages/twenty-front/src/modules/ai/components/AIChatBanner.tsx b/packages/twenty-front/src/modules/ai/components/AIChatBanner.tsx index dce8ea73e4..fcc4fea470 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatBanner.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatBanner.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { AppTooltip, @@ -7,27 +7,30 @@ import { IconInfoCircle, } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type AIChatBannerVariant = 'default' | 'warning'; const StyledBanner = styled.div<{ variant: AIChatBannerVariant }>` align-items: center; - background-color: ${({ theme, variant }) => + background-color: ${({ variant }) => variant === 'warning' - ? theme.background.transparent.orange - : theme.accent.secondary}; - border-radius: ${({ theme }) => theme.border.radius.md}; + ? themeCssVariables.background.transparent.orange + : themeCssVariables.accent.secondary}; + border-radius: ${themeCssVariables.border.radius.md}; box-sizing: border-box; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[2]}; width: 100%; `; const StyledIconContainer = styled.div<{ variant: AIChatBannerVariant }>` align-items: center; - color: ${({ theme, variant }) => - variant === 'warning' ? theme.color.orange : theme.color.blue}; + color: ${({ variant }) => + variant === 'warning' + ? themeCssVariables.color.orange + : themeCssVariables.color.blue}; display: flex; flex-shrink: 0; height: 16px; @@ -36,13 +39,15 @@ const StyledIconContainer = styled.div<{ variant: AIChatBannerVariant }>` `; const StyledMessage = styled.p<{ variant: AIChatBannerVariant }>` - color: ${({ theme, variant }) => - variant === 'warning' ? theme.color.orange : theme.color.blue}; + color: ${({ variant }) => + variant === 'warning' + ? themeCssVariables.color.orange + : themeCssVariables.color.blue}; flex-grow: 1; - font-family: ${({ theme }) => theme.font.family}; - font-size: ${({ theme }) => theme.font.size.sm}; + font-family: ${themeCssVariables.font.family}; + font-size: ${themeCssVariables.font.size.sm}; font-style: normal; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; line-height: 1.4; margin: 0; min-width: 0; diff --git a/packages/twenty-front/src/modules/ai/components/AIChatEmptyState.tsx b/packages/twenty-front/src/modules/ai/components/AIChatEmptyState.tsx index 6b6f83a7be..2f74e21334 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatEmptyState.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatEmptyState.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type Editor } from '@tiptap/react'; import { AIChatSuggestedPrompts } from '@/ai/components/suggested-prompts/AIChatSuggestedPrompts'; diff --git a/packages/twenty-front/src/modules/ai/components/AIChatErrorMessage.tsx b/packages/twenty-front/src/modules/ai/components/AIChatErrorMessage.tsx index a47abe027a..9026ef92a9 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatErrorMessage.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatErrorMessage.tsx @@ -1,42 +1,44 @@ import { useAgentChatContextOrThrow } from '@/ai/hooks/useAgentChatContextOrThrow'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; +import { useContext } from 'react'; import { IconAlertCircle, IconRefresh } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledErrorContainer = styled.div` align-items: center; - background: ${({ theme }) => theme.background.danger}; - border: 1px solid ${({ theme }) => theme.border.color.danger}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background: ${themeCssVariables.background.danger}; + border: 1px solid ${themeCssVariables.border.color.danger}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(2, 3)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; `; const StyledErrorIcon = styled.div` align-items: center; - color: ${({ theme }) => theme.color.red}; + color: ${themeCssVariables.color.red}; display: flex; `; const StyledErrorContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing['0.5']}; flex: 1; `; const StyledErrorTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledErrorMessage = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.xs}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.xs}; word-break: break-word; `; @@ -45,7 +47,7 @@ type AIChatErrorMessageProps = { }; export const AIChatErrorMessage = ({ error }: AIChatErrorMessageProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { handleRetry, isStreaming } = useAgentChatContextOrThrow(); return ( diff --git a/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx b/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx index 374d680cbe..ebe29a905c 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AgentChatFilePreview } from '@/ai/components/internal/AgentChatFilePreview'; import { AgentMessageRole } from '@/ai/constants/AgentMessageRole'; @@ -9,6 +9,7 @@ import { LightCopyIconButton } from '@/object-record/record-field/ui/components/ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { type ExtendedUIMessage } from 'twenty-shared/ai'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; @@ -26,16 +27,19 @@ const StyledMessageBubble = styled.div<{ isUser?: boolean }>` `; const StyledMessageText = styled.div<{ isUser?: boolean }>` - background: ${({ theme, isUser }) => - isUser ? theme.background.tertiary : theme.background.transparent}; - border-radius: ${({ theme, isUser }) => - isUser ? theme.border.radius.sm : '0'}; - color: ${({ theme, isUser }) => - isUser ? theme.font.color.secondary : theme.font.color.primary}; + background: ${({ isUser }) => + isUser ? themeCssVariables.background.tertiary : 'transparent'}; + border-radius: ${({ isUser }) => + isUser ? themeCssVariables.border.radius.sm : '0'}; + color: ${({ isUser }) => + isUser + ? themeCssVariables.font.color.secondary + : themeCssVariables.font.color.primary}; font-weight: ${({ isUser }) => (isUser ? 500 : 400)}; line-height: 1.4em; max-width: 100%; - padding: ${({ theme, isUser }) => (isUser ? `0 ${theme.spacing(2)}` : 0)}; + padding: ${({ isUser }) => + isUser ? `0 ${themeCssVariables.spacing[2]}` : '0'}; width: fit-content; word-wrap: break-word; overflow-wrap: break-word; @@ -50,14 +54,14 @@ const StyledMessageText = styled.div<{ isUser?: boolean }>` max-width: 100%; line-height: 1.4; padding: 1px 3px; - border-radius: ${({ theme }) => theme.border.radius.sm}; - background: ${({ theme }) => theme.background.tertiary}; + border-radius: ${themeCssVariables.border.radius.sm}; + background: ${themeCssVariables.background.tertiary}; } pre { - background: ${({ theme }) => theme.background.tertiary}; - padding: ${({ theme }) => theme.spacing(2)}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.tertiary}; + padding: ${themeCssVariables.spacing[2]}; + border-radius: ${themeCssVariables.border.radius.sm}; overflow-x: auto; max-width: 100%; @@ -69,16 +73,16 @@ const StyledMessageText = styled.div<{ isUser?: boolean }>` } p { - margin-block: ${({ isUser, theme }) => - isUser ? '0' : `${theme.spacing(1)}`}; + margin-block: ${({ isUser }) => + isUser ? '0' : themeCssVariables.spacing[1]}; line-height: 1.4em; } ul, ol { line-height: 1.4em; - margin: ${({ theme }) => theme.spacing(1)} 0; - padding-left: ${({ theme }) => theme.spacing(4)}; + margin: ${themeCssVariables.spacing[1]} 0; + padding-left: ${themeCssVariables.spacing[4]}; } ul { @@ -87,35 +91,35 @@ const StyledMessageText = styled.div<{ isUser?: boolean }>` li { line-height: 1.4em; - margin: ${({ theme }) => theme.spacing(0.5)} 0; - padding-bottom: ${({ theme }) => theme.spacing(0.5)}; - padding-top: ${({ theme }) => theme.spacing(0.5)}; + margin: ${themeCssVariables.spacing['0.5']} 0; + padding-bottom: ${themeCssVariables.spacing['0.5']}; + padding-top: ${themeCssVariables.spacing['0.5']}; } blockquote { - border-left: 3px solid ${({ theme }) => theme.border.color.medium}; - margin: ${({ theme }) => theme.spacing(2)} 0; - padding-left: ${({ theme }) => theme.spacing(2)}; - color: ${({ theme }) => theme.font.color.secondary}; + border-left: 3px solid ${themeCssVariables.border.color.medium}; + margin: ${themeCssVariables.spacing[2]} 0; + padding-left: ${themeCssVariables.spacing[2]}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledMessageFooter = 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}; justify-content: space-between; - margin-top: ${({ theme }) => theme.spacing(1)}; + margin-top: ${themeCssVariables.spacing[1]}; opacity: 0; pointer-events: none; - transition: opacity ${({ theme }) => theme.animation.duration.normal}s + transition: opacity calc(${themeCssVariables.animation.duration.normal} * 1s) ease-in-out; width: 100%; `; const StyledMessageTimestamp = styled.span` - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; `; const StyledMessageContainer = styled.div<{ isUser?: boolean }>` @@ -127,9 +131,9 @@ const StyledMessageContainer = styled.div<{ isUser?: boolean }>` const StyledFilesContainer = styled.div` display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; flex-wrap: wrap; - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; export const AIChatMessage = ({ diff --git a/packages/twenty-front/src/modules/ai/components/AIChatStandaloneError.tsx b/packages/twenty-front/src/modules/ai/components/AIChatStandaloneError.tsx index 6148861a82..7fc55fd2c2 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatStandaloneError.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatStandaloneError.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AIChatErrorRenderer } from '@/ai/components/AIChatErrorRenderer'; diff --git a/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx b/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx index 13c6d10beb..95f6e90e9c 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { EditorContent } from '@tiptap/react'; import { useState } from 'react'; import { LightButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { DropZone } from '@/activities/files/components/DropZone'; import { AgentChatFileUploadButton } from '@/ai/components/internal/AgentChatFileUploadButton'; @@ -25,11 +26,11 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; const StyledContainer = styled.div<{ isDraggingFile: boolean }>` - background: ${({ theme }) => theme.background.primary}; + background: ${themeCssVariables.background.primary}; height: ${({ isDraggingFile }) => isDraggingFile ? `calc(100% - 24px)` : '100%'}; - padding: ${({ isDraggingFile, theme }) => - isDraggingFile ? theme.spacing(3) : '0'}; + padding: ${({ isDraggingFile }) => + isDraggingFile ? themeCssVariables.spacing[3] : '0'}; display: flex; flex-direction: column; `; @@ -38,27 +39,28 @@ const StyledInputArea = styled.div<{ isMobile: boolean }>` align-items: flex-end; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding-inline: ${({ theme }) => theme.spacing(3)}; - padding-block: ${({ theme, isMobile }) => (isMobile ? 0 : theme.spacing(3))}; - background: ${({ theme }) => theme.background.primary}; + gap: ${themeCssVariables.spacing[2]}; + padding-inline: ${themeCssVariables.spacing[3]}; + padding-block: ${({ isMobile }) => + isMobile ? '0' : themeCssVariables.spacing[3]}; + background: ${themeCssVariables.background.primary}; `; const StyledInputBox = 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}; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; min-height: 140px; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; width: 100%; box-sizing: border-box; &:focus-within { - border-color: ${({ theme }) => theme.color.blue}; - box-shadow: 0px 0px 0px 3px ${({ theme }) => theme.color.transparent.blue2}; + border-color: ${themeCssVariables.color.blue}; + box-shadow: 0px 0px 0px 3px ${themeCssVariables.color.transparent.blue2}; } `; @@ -72,10 +74,10 @@ const StyledEditorWrapper = styled.div` background: transparent; border: none; box-shadow: none; - 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; outline: none; padding: 0; @@ -88,10 +90,10 @@ const StyledEditorWrapper = styled.div` } p.is-editor-empty:first-of-type::before { - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; content: attr(data-placeholder); float: left; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-weight: ${themeCssVariables.font.weight.regular}; height: 0; pointer-events: none; } @@ -102,9 +104,9 @@ const StyledScrollWrapper = styled(ScrollWrapper)` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; overflow-y: auto; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; width: calc(100% - 24px); `; @@ -118,13 +120,13 @@ const StyledButtonsContainer = styled.div` const StyledLeftButtonsContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing['0.5']}; `; const StyledRightButtonsContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledReadOnlyModelButton = styled(LightButton)` diff --git a/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx b/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx index f7b91f0a60..75541c0cd2 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatThreadGroup.tsx @@ -1,52 +1,54 @@ import { useAIChatThreadClick } from '@/ai/hooks/useAIChatThreadClick'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { useLingui } from '@lingui/react/macro'; import { IconSparkles } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type AgentChatThread } from '~/generated-metadata/graphql'; const StyledThreadsList = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledDateGroup = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; const StyledDateHeader = styled.div` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; const StyledThreadItem = styled.div<{ isSelected?: boolean }>` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(2)}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + gap: ${themeCssVariables.spacing[2]}; + border-radius: ${themeCssVariables.border.radius.sm}; transition: all 0.2s ease; - margin-bottom: ${({ theme }) => theme.spacing(1)}; + margin-bottom: ${themeCssVariables.spacing[1]}; border-left: 3px solid transparent; cursor: pointer; - padding: ${({ theme }) => theme.spacing(1)} 1px; + padding: ${themeCssVariables.spacing[1]} 1px; right: 3px; position: relative; width: calc(100% + 1px); &:hover { - background: ${({ theme }) => theme.background.transparent.light}; + background: ${themeCssVariables.background.transparent.light}; } `; const StyledSparkleIcon = styled.div` align-items: center; - background: ${({ theme }) => theme.background.transparent.blue}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.transparent.blue}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; justify-content: center; `; @@ -56,8 +58,8 @@ const StyledThreadContent = styled.div` `; const StyledThreadTitle = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.md}; font-weight: 500; overflow: hidden; text-overflow: ellipsis; @@ -72,7 +74,7 @@ export const AIChatThreadGroup = ({ title: string; }) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { handleThreadClick } = useAIChatThreadClick(); if (threads.length === 0) { diff --git a/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx b/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx index 0da9ca1b5e..26848572a3 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AIChatThreadGroup } from '@/ai/components/AIChatThreadGroup'; import { AIChatThreadsListEffect } from '@/ai/components/AIChatThreadsListEffect'; @@ -10,12 +10,13 @@ import { t } from '@lingui/core/macro'; import { Key } from 'ts-key-enum'; import { capitalize } from 'twenty-shared/utils'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { getOsControlSymbol } from 'twenty-ui/utilities'; import { useGetChatThreadsQuery } from '~/generated-metadata/graphql'; const StyledContainer = styled.div` - background: ${({ theme }) => theme.background.secondary}; - border-right: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.background.secondary}; + border-right: 1px solid ${themeCssVariables.border.color.light}; display: flex; flex-direction: column; height: 100%; @@ -24,14 +25,14 @@ const StyledContainer = styled.div` const StyledThreadsContainer = styled.div` flex: 1; overflow-y: auto; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledButtonsContainer = styled.div` display: flex; - padding: ${({ theme }) => theme.spacing(2, 2.5)}; + padding: ${themeCssVariables.spacing[2]} 10px; justify-content: flex-end; - border-top: 1px solid ${({ theme }) => theme.border.color.medium}; + border-top: 1px solid ${themeCssVariables.border.color.medium}; `; export const AIChatThreadsList = () => { diff --git a/packages/twenty-front/src/modules/ai/components/CodeExecutionDisplay.tsx b/packages/twenty-front/src/modules/ai/components/CodeExecutionDisplay.tsx index cc026595cc..a876d4313e 100644 --- a/packages/twenty-front/src/modules/ai/components/CodeExecutionDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/CodeExecutionDisplay.tsx @@ -1,8 +1,7 @@ import { TerminalOutput } from '@/ai/components/TerminalOutput'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext, useState } from 'react'; import { useLingui } from '@lingui/react/macro'; -import { useState } from 'react'; import { IconChevronDown, IconChevronUp, @@ -16,96 +15,97 @@ import { } from 'twenty-ui/display'; import { CodeEditor, LightIconButton } from 'twenty-ui/input'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; - margin: ${({ theme }) => theme.spacing(2)} 0; + margin: ${themeCssVariables.spacing[2]} 0; overflow: hidden; `; const StyledHeader = styled.div<{ status: 'success' | 'error' | 'running' }>` align-items: center; - background: ${({ theme }) => theme.background.secondary}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.background.secondary}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; `; const StyledHeaderLeft = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledHeaderRight = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledStatusBadge = styled.div<{ status: 'success' | 'error' | 'running'; }>` align-items: center; - background: ${({ status, theme }) => + background: ${({ status }) => status === 'success' - ? theme.background.transparent.success + ? themeCssVariables.background.transparent.success : status === 'error' - ? theme.background.transparent.danger - : theme.background.transparent.medium}; - border-radius: ${({ theme }) => theme.border.radius.pill}; - color: ${({ status, theme }) => + ? themeCssVariables.background.transparent.danger + : themeCssVariables.background.transparent.medium}; + border-radius: ${themeCssVariables.border.radius.pill}; + color: ${({ status }) => status === 'success' - ? theme.color.turquoise + ? themeCssVariables.color.turquoise : status === 'error' - ? theme.color.red - : theme.font.color.secondary}; + ? themeCssVariables.color.red + : themeCssVariables.font.color.secondary}; display: flex; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(0.5)} - ${({ theme }) => theme.spacing(2)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing['0.5']} ${themeCssVariables.spacing[2]}; `; const StyledTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledSection = styled.div` - border-top: 1px solid ${({ theme }) => theme.border.color.light}; + border-top: 1px solid ${themeCssVariables.border.color.light}; `; const StyledSectionHeader = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; + background: ${themeCssVariables.background.secondary}; cursor: pointer; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)}; - transition: background ${({ theme }) => theme.animation.duration.fast}s; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[3]}; + transition: background calc(${themeCssVariables.animation.duration.fast} * 1s); &:hover { - background: ${({ theme }) => theme.background.tertiary}; + background: ${themeCssVariables.background.tertiary}; } `; const StyledSectionHeaderLeft = 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-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledCodeEditorContainer = styled.div` @@ -115,14 +115,14 @@ const StyledCodeEditorContainer = styled.div` const StyledFilesGrid = styled.div` display: grid; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledFileCard = styled.div` - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; flex-direction: column; overflow: hidden; @@ -131,7 +131,7 @@ const StyledFileCard = styled.div` const StyledFilePreview = styled.div` align-items: center; aspect-ratio: 16 / 9; - background: ${({ theme }) => theme.background.tertiary}; + background: ${themeCssVariables.background.tertiary}; display: flex; justify-content: center; overflow: hidden; @@ -145,17 +145,16 @@ const StyledPreviewImage = styled.img` const StyledFileInfo = styled.div` align-items: center; - background: ${({ theme }) => theme.background.secondary}; + background: ${themeCssVariables.background.secondary}; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(1.5)} - ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing['1.5']} ${themeCssVariables.spacing[2]}; `; const StyledFileName = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.sm}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -163,11 +162,11 @@ const StyledFileName = styled.span` const StyledDownloadLink = styled.a` align-items: center; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; display: flex; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; @@ -203,7 +202,7 @@ export const CodeExecutionDisplay = ({ isRunning = false, }: CodeExecutionDisplayProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { copyToClipboard } = useCopyToClipboard(); const [isCodeExpanded, setIsCodeExpanded] = useState(false); const [isOutputExpanded, setIsOutputExpanded] = useState(true); diff --git a/packages/twenty-front/src/modules/ai/components/LazyMarkdownRenderer.tsx b/packages/twenty-front/src/modules/ai/components/LazyMarkdownRenderer.tsx index abfefdc6a6..801ad267ea 100644 --- a/packages/twenty-front/src/modules/ai/components/LazyMarkdownRenderer.tsx +++ b/packages/twenty-front/src/modules/ai/components/LazyMarkdownRenderer.tsx @@ -4,11 +4,16 @@ import { RECORD_REFERENCE_REGEX, RecordLink, } from '@/ai/components/RecordLink'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { lazy, Suspense } from 'react'; +import { + StyledMarkdownContainer, + StyledParagraph, + StyledSkeletonContainer, + StyledTableScrollContainer, +} from '@/ai/components/LazyMarkdownRendererStyledComponents'; +import { lazy, Suspense, useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { isDefined } from 'twenty-shared/utils'; +import { ThemeContext } from 'twenty-ui/theme'; const TextWithRecordLinks = ({ text }: { text: string }) => { const parts: React.ReactNode[] = []; @@ -72,11 +77,11 @@ const MarkdownRenderer = lazy(async () => { default: ({ children, TableScrollContainer, - StyledParagraph, + ParagraphComponent, }: { children: string; TableScrollContainer: React.ComponentType<{ children: React.ReactNode }>; - StyledParagraph: React.ComponentType<{ children: React.ReactNode }>; + ParagraphComponent: React.ComponentType<{ children: React.ReactNode }>; }) => ( { ), p: ({ children }) => ( - + {processChildrenForRecordLinks(children)} - + ), li: ({ children }) => (
  • {processChildrenForRecordLinks(children)}
  • @@ -125,194 +130,8 @@ const MarkdownRenderer = lazy(async () => { }; }); -const StyledMarkdownContainer = styled.div` - border-radius: ${({ theme }) => theme.border.radius.sm}; - line-height: 150%; - margin: ${({ theme }) => `${theme.spacing(1.5)} 0`}; - position: relative; - scroll-margin-top: ${({ theme }) => theme.spacing(10)}; - scroll-margin-bottom: ${({ theme }) => theme.spacing(10)}; - - &:empty { - display: none; - } - - .markdown-link { - color: ${({ theme }) => theme.accent.accent11}; - text-decoration: none; - -webkit-text-decoration: none; - } - - .markdown-link:visited { - color: ${({ theme }) => theme.accent.accent11}; - } - - .markdown-link:hover { - text-decoration: underline !important; - } - - strong, - b { - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - } - - h1, - h2, - h3 { - font-weight: ${({ theme }) => theme.font.weight.semiBold} !important; - } - - h1 { - font-size: 1.6em; - line-height: 1.25; - margin-bottom: 12px; - margin-top: 24px; - } - - h2 { - font-size: 1.3em; - line-height: 1.25; - margin-bottom: 10px; - margin-top: 20px; - } - - h3 { - font-size: 1.15em; - line-height: 1.25; - margin-bottom: 8px; - margin-top: 18px; - } - - h4 { - font-size: 1.05em; - line-height: 1.25; - margin-bottom: 8px; - margin-top: 16px; - } - - h5 { - font-size: 0.95em; - line-height: 1.25; - margin-bottom: 6px; - margin-top: 14px; - } - - h6 { - font-size: 0.85em; - line-height: 1.25; - margin-bottom: 6px; - margin-top: 12px; - } - - hr { - background-color: ${({ theme }) => theme.border.color.light} !important; - border: none; - height: 1px; - margin: ${({ theme }) => theme.spacing(4)} 0; - } - - ol:first-of-type:not(.nested), - ul:first-of-type:not(.nested) { - margin-top: ${({ theme }) => theme.spacing(1)} !important; - } - - ol:last-of-type:not(.nested), - ul:last-of-type:not(.nested) { - margin-bottom: ${({ theme }) => theme.spacing(1)} !important; - } - - li { - line-height: 150%; - margin-bottom: ${({ theme }) => theme.spacing(0.5)} !important; - margin-top: ${({ theme }) => theme.spacing(0.5)} !important; - padding-bottom: ${({ theme }) => theme.spacing(0.5)} !important; - padding-top: ${({ theme }) => theme.spacing(0.5)} !important; - } - - :not(pre) > code { - background-color: ${({ theme }) => theme.background.tertiary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.primary}; - font-family: ${({ theme }) => `${theme.code.font.family}, monospace`}; - font-size: 0.9em; - padding: 1.5px 3px; - transition: all ${({ theme }) => theme.animation.duration.fast}s ease; - } - - :not(pre) > code[style*='cursor: pointer'] { - background-color: ${({ theme }) => theme.background.secondary}; - border: ${({ theme }) => `1px solid ${theme.accent.accent10}`}; - color: ${({ theme }) => theme.accent.accent10}; - } - - :not(pre) > code[style*='cursor: pointer']:hover { - background-color: ${({ theme }) => theme.background.transparent.blue}; - } - - .markdown-code-outer-container { - border-radius: ${({ theme }) => theme.border.radius.md} !important; - overflow: hidden; - } - - .markdown-block-code { - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md} !important; - } - - .markdown-block-code * { - animation: none !important; - } - - img { - height: auto; - max-width: 100%; - } -`; - -// Using div instead of p to allow RecordLink (which contains div elements) as children -const StyledParagraph = styled.div` - line-height: inherit; - margin-block: ${({ theme }) => theme.spacing(2)}; - - &:first-child { - margin-block-start: 0; - } - - &:last-child { - margin-block-end: 0; - } -`; - -const StyledSkeletonContainer = styled.div` - display: flex; - flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - width: 100%; -`; - -const StyledTableScrollContainer = styled.div` - overflow-x: auto; - - table { - border-collapse: collapse; - margin-block: ${({ theme }) => theme.spacing(2)}; - } - - th, - td { - border: ${({ theme }) => `1px solid ${theme.border.color.light}`}; - padding: ${({ theme }) => theme.spacing(2)}; - } - - th { - background-color: ${({ theme }) => theme.background.secondary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - } -`; - const LoadingSkeleton = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( { }> {text} diff --git a/packages/twenty-front/src/modules/ai/components/LazyMarkdownRendererStyledComponents.tsx b/packages/twenty-front/src/modules/ai/components/LazyMarkdownRendererStyledComponents.tsx new file mode 100644 index 0000000000..644c45f7e0 --- /dev/null +++ b/packages/twenty-front/src/modules/ai/components/LazyMarkdownRendererStyledComponents.tsx @@ -0,0 +1,187 @@ +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; + +export const StyledMarkdownContainer = styled.div` + border-radius: ${themeCssVariables.border.radius.sm}; + line-height: 150%; + margin: ${themeCssVariables.spacing['1.5']} 0; + position: relative; + scroll-margin-top: ${themeCssVariables.spacing[10]}; + scroll-margin-bottom: ${themeCssVariables.spacing[10]}; + + &:empty { + display: none; + } + + .markdown-link { + color: ${themeCssVariables.accent.accent11}; + text-decoration: none; + -webkit-text-decoration: none; + } + + .markdown-link:visited { + color: ${themeCssVariables.accent.accent11}; + } + + .markdown-link:hover { + text-decoration: underline !important; + } + + strong, + b { + font-weight: ${themeCssVariables.font.weight.semiBold}; + } + + h1, + h2, + h3 { + font-weight: ${themeCssVariables.font.weight.semiBold} !important; + } + + h1 { + font-size: 1.6em; + line-height: 1.25; + margin-bottom: 12px; + margin-top: 24px; + } + + h2 { + font-size: 1.3em; + line-height: 1.25; + margin-bottom: 10px; + margin-top: 20px; + } + + h3 { + font-size: 1.15em; + line-height: 1.25; + margin-bottom: 8px; + margin-top: 18px; + } + + h4 { + font-size: 1.05em; + line-height: 1.25; + margin-bottom: 8px; + margin-top: 16px; + } + + h5 { + font-size: 0.95em; + line-height: 1.25; + margin-bottom: 6px; + margin-top: 14px; + } + + h6 { + font-size: 0.85em; + line-height: 1.25; + margin-bottom: 6px; + margin-top: 12px; + } + + hr { + background-color: ${themeCssVariables.border.color.light} !important; + border: none; + height: 1px; + margin: ${themeCssVariables.spacing[4]} 0; + } + + ol:first-of-type:not(.nested), + ul:first-of-type:not(.nested) { + margin-top: ${themeCssVariables.spacing[1]} !important; + } + + ol:last-of-type:not(.nested), + ul:last-of-type:not(.nested) { + margin-bottom: ${themeCssVariables.spacing[1]} !important; + } + + li { + line-height: 150%; + margin-bottom: ${themeCssVariables.spacing['0.5']} !important; + margin-top: ${themeCssVariables.spacing['0.5']} !important; + padding-bottom: ${themeCssVariables.spacing['0.5']} !important; + padding-top: ${themeCssVariables.spacing['0.5']} !important; + } + + :not(pre) > code { + background-color: ${themeCssVariables.background.tertiary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.primary}; + font-family: ${themeCssVariables.code.font.family}, monospace; + font-size: 0.9em; + padding: 1.5px 3px; + transition: all calc(${themeCssVariables.animation.duration.fast} * 1s) ease; + } + + :not(pre) > code[style*='cursor: pointer'] { + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.accent.accent10}; + color: ${themeCssVariables.accent.accent10}; + } + + :not(pre) > code[style*='cursor: pointer']:hover { + background-color: ${themeCssVariables.background.transparent.blue}; + } + + .markdown-code-outer-container { + border-radius: ${themeCssVariables.border.radius.md} !important; + overflow: hidden; + } + + .markdown-block-code { + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md} !important; + } + + .markdown-block-code * { + animation: none !important; + } + + img { + height: auto; + max-width: 100%; + } +`; + +export const StyledParagraph = styled.div` + line-height: inherit; + margin-block: ${themeCssVariables.spacing[2]}; + + &:first-child { + margin-block-start: 0; + } + + &:last-child { + margin-block-end: 0; + } +`; + +export const StyledSkeletonContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${themeCssVariables.spacing[2]}; + width: 100%; +`; + +export const StyledTableScrollContainer = styled.div` + overflow-x: auto; + + table { + border-collapse: collapse; + margin-block: ${themeCssVariables.spacing[2]}; + } + + th, + td { + border: 1px solid ${themeCssVariables.border.color.light}; + padding: ${themeCssVariables.spacing[2]}; + } + + th { + background-color: ${themeCssVariables.background.secondary}; + font-weight: ${themeCssVariables.font.weight.medium}; + } +`; diff --git a/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadDateSection.tsx b/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadDateSection.tsx index e2f22de51d..ef292c95f4 100644 --- a/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadDateSection.tsx +++ b/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadDateSection.tsx @@ -1,34 +1,35 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { IconComment } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { type AgentChatThread } from '~/generated-metadata/graphql'; import { beautifyPastDateRelativeToNowShort } from '~/utils/date-utils'; const StyledDateSection = styled.section` - margin-bottom: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; const StyledThreadList = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing['0.5']}; `; const StyledDateHeader = styled.div` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(0, 2)}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-bottom: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[0]} ${themeCssVariables.spacing[2]}; `; const StyledThreadTimestamp = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding-right: ${({ theme }) => theme.spacing(0.5)}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.regular}; + padding-right: ${themeCssVariables.spacing['0.5']}; `; export type NavigationDrawerAIChatThreadDateSectionProps = { diff --git a/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadsList.tsx b/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadsList.tsx index 7ab9b59c27..61e6626687 100644 --- a/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadsList.tsx +++ b/packages/twenty-front/src/modules/ai/components/NavigationDrawerAIChatThreadsList.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { NavigationDrawerAIChatThreadDateSection } from '@/ai/components/NavigationDrawerAIChatThreadDateSection'; import { AIChatSkeletonLoader } from '@/ai/components/internal/AIChatSkeletonLoader'; @@ -9,6 +9,7 @@ import { type DateGroupKey } from '@/ai/utils/dateGroupKey'; import { DATE_GROUP_KEYS } from '@/ai/utils/dateGroupKeys'; import { getDateGroupTitle } from '@/ai/utils/getDateGroupTitle'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useGetChatThreadsQuery } from '~/generated-metadata/graphql'; const StyledScrollableList = styled.div` @@ -17,8 +18,8 @@ const StyledScrollableList = styled.div` flex: 1; min-height: 0; overflow-y: auto; - padding: ${({ theme }) => theme.spacing(2, 0)}; - width: ${({ theme }) => `calc(100% - ${theme.spacing(2)})`}; + padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[0]}; + width: calc(100% - ${themeCssVariables.spacing[2]}); `; export const NavigationDrawerAIChatThreadsList = () => { diff --git a/packages/twenty-front/src/modules/ai/components/ReasoningSummaryDisplay.tsx b/packages/twenty-front/src/modules/ai/components/ReasoningSummaryDisplay.tsx index b40233ba1b..4dea7c66e5 100644 --- a/packages/twenty-front/src/modules/ai/components/ReasoningSummaryDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/ReasoningSummaryDisplay.tsx @@ -1,9 +1,10 @@ -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 { IconBrain, IconChevronDown, IconChevronUp } from 'twenty-ui/display'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { ShimmeringText } from '@/ai/components/ShimmeringText'; import { t } from '@lingui/core/macro'; @@ -11,27 +12,27 @@ import { t } from '@lingui/core/macro'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledThinkingText = styled.div` - 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}; `; const StyledReasoningContainer = styled.div` - background: ${({ theme }) => theme.background.transparent.lighter}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - padding: ${({ theme }) => theme.spacing(3)}; - border: 1px solid ${({ theme }) => theme.border.color.light}; + background: ${themeCssVariables.background.transparent.lighter}; + border-radius: ${themeCssVariables.border.radius.sm}; + padding: ${themeCssVariables.spacing[3]}; + border: 1px solid ${themeCssVariables.border.color.light}; `; const StyledReasoningText = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.sm}; - line-height: ${({ theme }) => theme.text.lineHeight.lg}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.sm}; + line-height: ${themeCssVariables.text.lineHeight.lg}; white-space: pre-wrap; `; @@ -39,24 +40,24 @@ const StyledToggleButton = styled.div` align-items: center; background: none; border: none; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; cursor: pointer; display: flex; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)} 0; - transition: color ${({ theme }) => theme.animation.duration.normal}s; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]} 0; + transition: color calc(${themeCssVariables.animation.duration.normal} * 1s); &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledIconContainer = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const ReasoningSummaryDisplay = ({ @@ -66,7 +67,7 @@ export const ReasoningSummaryDisplay = ({ content: string; isThinking?: boolean; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isExpanded, setIsExpanded] = useState(false); const hasContent = content.trim().length > 0; diff --git a/packages/twenty-front/src/modules/ai/components/RoutingDebugDisplay.tsx b/packages/twenty-front/src/modules/ai/components/RoutingDebugDisplay.tsx index fcbd65caac..1023fedbbf 100644 --- a/packages/twenty-front/src/modules/ai/components/RoutingDebugDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/RoutingDebugDisplay.tsx @@ -1,10 +1,11 @@ -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, IconChevronUp } from 'twenty-ui/display'; import { JsonTree } from 'twenty-ui/json-visualizer'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useLingui } from '@lingui/react/macro'; import { type DataMessagePart } from 'twenty-shared/ai'; @@ -14,8 +15,8 @@ import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - margin-top: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + margin-top: ${themeCssVariables.spacing[2]}; `; const StyledToggleButton = styled.div` @@ -24,23 +25,23 @@ const StyledToggleButton = styled.div` border: none; cursor: pointer; display: flex; - color: ${({ theme }) => theme.font.color.tertiary}; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)} 0; - transition: color ${({ theme }) => theme.animation.duration.normal}s; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]} 0; + transition: color calc(${themeCssVariables.animation.duration.normal} * 1s); + font-size: ${themeCssVariables.font.size.sm}; &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledContentContainer = styled.div` - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; min-width: 0; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledJsonTreeContainer = styled.div` @@ -52,48 +53,52 @@ const StyledJsonTreeContainer = styled.div` `; const StyledTabContainer = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; - gap: ${({ theme }) => theme.spacing(3)}; - margin-bottom: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; const StyledTab = styled.div<{ isActive: boolean }>` - color: ${({ theme, isActive }) => - isActive ? theme.font.color.primary : theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme, isActive }) => - isActive ? theme.font.weight.medium : theme.font.weight.regular}; + color: ${({ isActive }) => + isActive + ? themeCssVariables.font.color.primary + : themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${({ isActive }) => + isActive + ? themeCssVariables.font.weight.medium + : themeCssVariables.font.weight.regular}; cursor: pointer; - transition: color ${({ theme }) => theme.animation.duration.normal}s; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + transition: color calc(${themeCssVariables.animation.duration.normal} * 1s); + padding-bottom: ${themeCssVariables.spacing[2]}; &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledTimingSection = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledTimingRow = styled.div` align-items: center; display: flex; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(1)} 0; + padding: ${themeCssVariables.spacing[1]} 0; `; const StyledTimingLabel = styled.span` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; const StyledTimingValue = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; `; type TabType = 'timing' | 'details' | 'context'; @@ -319,7 +324,7 @@ type RoutingDebugDisplayProps = { export const RoutingDebugDisplay = ({ debug }: RoutingDebugDisplayProps) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { copyToClipboard } = useCopyToClipboard(); const [isExpanded, setIsExpanded] = useState(false); const [activeTab, setActiveTab] = useState('timing'); diff --git a/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx b/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx index 9661a3d98e..f12bec2083 100644 --- a/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/RoutingStatusDisplay.tsx @@ -1,16 +1,17 @@ import { RoutingDebugDisplay } from '@/ai/components/RoutingDebugDisplay'; import { ShimmeringText } from '@/ai/components/ShimmeringText'; -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 { type DataMessagePart } from 'twenty-shared/ai'; import { IconChevronDown, IconChevronUp, IconCpu } from 'twenty-ui/display'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +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 StyledToggleButton = styled.div<{ isExpandable: boolean }>` @@ -19,39 +20,41 @@ const StyledToggleButton = styled.div<{ isExpandable: boolean }>` border: none; cursor: ${({ isExpandable }) => (isExpandable ? 'pointer' : 'auto')}; display: flex; - color: ${({ theme }) => theme.font.color.tertiary}; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)} 0; - transition: color ${({ theme }) => theme.animation.duration.normal}s; + color: ${themeCssVariables.font.color.tertiary}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]} 0; + transition: color calc(${themeCssVariables.animation.duration.normal} * 1s); &:hover { - color: ${({ isExpandable, theme }) => - isExpandable ? theme.font.color.secondary : theme.font.color.tertiary}; + color: ${({ isExpandable }) => + isExpandable + ? themeCssVariables.font.color.secondary + : themeCssVariables.font.color.tertiary}; } `; const StyledDisplayMessage = 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}; `; const StyledIconTextContainer = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; svg { - min-width: ${({ theme }) => theme.icon.size.sm}px; + min-width: calc(${themeCssVariables.icon.size.sm} * 1px); } `; const StyledContentContainer = styled.div` - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; min-width: 0; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; export const RoutingStatusDisplay = ({ @@ -59,7 +62,7 @@ export const RoutingStatusDisplay = ({ }: { data: DataMessagePart['routing-status']; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isExpanded, setIsExpanded] = useState(false); const isLoading = data.state === 'loading'; const isDebugMode = process.env.IS_DEBUG_MODE === 'true'; diff --git a/packages/twenty-front/src/modules/ai/components/ShimmeringText.tsx b/packages/twenty-front/src/modules/ai/components/ShimmeringText.tsx index df97aa6050..21bf49041c 100644 --- a/packages/twenty-front/src/modules/ai/components/ShimmeringText.tsx +++ b/packages/twenty-front/src/modules/ai/components/ShimmeringText.tsx @@ -1,12 +1,13 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledShimmeringText = styled.div` - background: ${({ theme }) => theme.font.color.light} + background: ${themeCssVariables.font.color.light} linear-gradient( 90deg, - ${({ theme }) => theme.font.color.light} 0%, - ${({ theme }) => theme.font.color.primary} 50%, - ${({ theme }) => theme.font.color.light} 100% + ${themeCssVariables.font.color.light} 0%, + ${themeCssVariables.font.color.primary} 50%, + ${themeCssVariables.font.color.light} 100% ); background-size: 200% 100%; background-position: -200% top; diff --git a/packages/twenty-front/src/modules/ai/components/TerminalOutput.tsx b/packages/twenty-front/src/modules/ai/components/TerminalOutput.tsx index 660ce8985e..d21cba6804 100644 --- a/packages/twenty-front/src/modules/ai/components/TerminalOutput.tsx +++ b/packages/twenty-front/src/modules/ai/components/TerminalOutput.tsx @@ -1,88 +1,94 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { IconCopy, IconTerminal } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` display: flex; flex-direction: column; - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; overflow: hidden; `; const StyledHeader = styled.div` align-items: center; - background: ${({ theme }) => theme.background.tertiary}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + background: ${themeCssVariables.background.tertiary}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}; `; const StyledHeaderLeft = 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}; - gap: ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.sm}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledTabContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledTab = styled.button<{ isActive: boolean; hasError?: boolean }>` - background: ${({ isActive, theme }) => - isActive ? theme.background.secondary : 'transparent'}; + background: ${({ isActive }) => + isActive ? themeCssVariables.background.secondary : 'transparent'}; border: none; - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ isActive, hasError, theme }) => + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${({ isActive, hasError }) => hasError - ? theme.color.red + ? themeCssVariables.color.red : isActive - ? theme.font.color.primary - : theme.font.color.tertiary}; + ? themeCssVariables.font.color.primary + : themeCssVariables.font.color.tertiary}; cursor: pointer; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ isActive, theme }) => - isActive ? theme.font.weight.medium : theme.font.weight.regular}; - padding: ${({ theme }) => theme.spacing(0.5)} - ${({ theme }) => theme.spacing(1)}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${({ isActive }) => + isActive + ? themeCssVariables.font.weight.medium + : themeCssVariables.font.weight.regular}; + padding: ${themeCssVariables.spacing['0.5']} ${themeCssVariables.spacing[1]}; &:hover { - background: ${({ theme }) => theme.background.secondary}; - color: ${({ hasError, theme }) => - hasError ? theme.color.red : theme.font.color.primary}; + background: ${themeCssVariables.background.secondary}; + color: ${({ hasError }) => + hasError + ? themeCssVariables.color.red + : themeCssVariables.font.color.primary}; } `; const StyledOutputArea = styled.div<{ isError?: boolean }>` - background: ${({ theme }) => theme.background.tertiary}; - color: ${({ isError, theme }) => - isError ? theme.color.red : theme.font.color.primary}; + background: ${themeCssVariables.background.tertiary}; + color: ${({ isError }) => + isError + ? themeCssVariables.color.red + : themeCssVariables.font.color.primary}; font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; line-height: 1.5; max-height: 300px; min-height: 100px; overflow-y: auto; - padding: ${({ theme }) => theme.spacing(2)}; + padding: ${themeCssVariables.spacing[2]}; white-space: pre-wrap; word-break: break-word; `; const StyledEmptyMessage = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; font-style: italic; `; const StyledCursor = styled.span` animation: blink 1s step-end infinite; - background: ${({ theme }) => theme.font.color.primary}; + background: ${themeCssVariables.font.color.primary}; display: inline-block; height: 1em; margin-left: 2px; diff --git a/packages/twenty-front/src/modules/ai/components/ThinkingStepsDisplay.tsx b/packages/twenty-front/src/modules/ai/components/ThinkingStepsDisplay.tsx index ff615e8459..d126fca33f 100644 --- a/packages/twenty-front/src/modules/ai/components/ThinkingStepsDisplay.tsx +++ b/packages/twenty-front/src/modules/ai/components/ThinkingStepsDisplay.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { plural, t } from '@lingui/core/macro'; import { useState } from 'react'; import { type ToolUIPart } from 'ai'; @@ -12,6 +12,7 @@ import { } from 'twenty-ui/display'; import { JsonTree } from 'twenty-ui/json-visualizer'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type JsonValue } from 'type-fest'; import { ToolOutputResultSchema } from '@/ai/schemas/toolOutputResultSchema'; @@ -32,184 +33,190 @@ import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` display: flex; flex-direction: column; - font-family: ${({ theme }) => theme.font.family}; - gap: ${({ theme }) => theme.spacing(1)}; + font-family: ${themeCssVariables.font.family}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledStepsContentContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(1)}; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + padding-top: ${themeCssVariables.spacing[1]}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSummaryText = styled.span` color: inherit; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.md}; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.md}; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; `; const StyledSummaryButton = styled.button` align-items: center; background: none; border: none; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.tertiary}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.tertiary}; cursor: pointer; display: flex; font-family: inherit; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; min-height: 24px; padding: 0; width: fit-content; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } &:focus-visible { - outline: 2px solid ${({ theme }) => theme.color.blue}; + outline: 2px solid ${themeCssVariables.color.blue}; outline-offset: 2px; } `; const StyledSummaryChevronContainer = styled.div<{ isExpanded: boolean }>` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; justify-content: center; transform: rotate(${({ isExpanded }) => (isExpanded ? '90deg' : '0deg')}); - transition: transform ${({ theme }) => theme.animation.duration.fast}s + transition: transform calc(${themeCssVariables.animation.duration.fast} * 1s) ease-in-out; `; const StyledRowsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledRow = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; min-height: 24px; `; const StyledRowLabel = styled.span` color: inherit; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.md}; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.md}; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; `; const StyledToolRowLabel = styled.div` color: inherit; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.md}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.md}; max-width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; white-space: nowrap; `; const StyledReasoningContainer = styled.div` padding-left: calc( - ${({ theme }) => theme.icon.size.sm}px + ${({ theme }) => theme.spacing(2)} + ${themeCssVariables.icon.size.sm} * 1px + ${themeCssVariables.spacing[2]} ); `; const StyledReasoningText = styled.p` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.lg}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.lg}; margin: 0; white-space: pre-wrap; `; const StyledOrbitLoaderIcon = styled(ThinkingOrbitLoaderIcon)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledIconContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; justify-content: center; - min-width: ${({ theme }) => theme.icon.size.sm}px; + min-width: calc(${themeCssVariables.icon.size.sm} * 1px); `; const StyledRowLabelContainer = styled.div` align-items: center; display: flex; flex: 1; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; min-width: 0; `; const StyledChevronContainer = styled.div<{ isExpanded: boolean }>` align-items: center; - color: ${({ theme }) => theme.font.color.light}; + color: ${themeCssVariables.font.color.light}; display: flex; justify-content: center; transform: rotate(${({ isExpanded }) => (isExpanded ? '90deg' : '0deg')}); - transition: transform ${({ theme }) => theme.animation.duration.fast}s + transition: transform calc(${themeCssVariables.animation.duration.fast} * 1s) ease-in-out; `; const StyledToolRowContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledToolRowButton = styled.button<{ isExpandable: boolean }>` align-items: center; background: none; border: none; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; cursor: ${({ isExpandable }) => (isExpandable ? 'pointer' : 'default')}; display: flex; font-family: inherit; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; min-height: 24px; padding: 0; text-align: left; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; width: 100%; &:hover { - color: ${({ theme, isExpandable }) => - isExpandable ? theme.font.color.primary : theme.font.color.tertiary}; + color: ${({ isExpandable }) => + isExpandable + ? themeCssVariables.font.color.primary + : themeCssVariables.font.color.tertiary}; } &:focus-visible { - outline: 2px solid ${({ theme }) => theme.color.blue}; + outline: 2px solid ${themeCssVariables.color.blue}; outline-offset: 2px; } `; const StyledToolDetailsContainer = styled.div` - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - margin-left: ${({ theme }) => theme.spacing(3)}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; + margin-left: ${themeCssVariables.spacing[3]}; min-width: 0; overflow: hidden; `; const StyledToolTabList = styled(TabList)` - background-color: ${({ theme }) => theme.background.secondary}; - padding-left: ${({ theme }) => theme.spacing(1)}; + background-color: ${themeCssVariables.background.secondary}; + padding-left: ${themeCssVariables.spacing[1]}; `; const StyledToolDetailsContent = styled.div` @@ -217,11 +224,11 @@ const StyledToolDetailsContent = styled.div` `; const StyledToolJsonContent = styled.div` - padding: ${({ theme }) => theme.spacing(1)}; + padding: ${themeCssVariables.spacing[1]}; `; const StyledJsonTreeContainer = styled.div` - font-size: ${({ theme }) => theme.font.size.md}; + font-size: ${themeCssVariables.font.size.md}; overflow-x: auto; li, @@ -235,10 +242,10 @@ const StyledJsonTreeContainer = styled.div` `; const StyledToolErrorText = styled.p` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - line-height: ${({ theme }) => theme.text.lineHeight.lg}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.regular}; + line-height: ${themeCssVariables.text.lineHeight.lg}; margin: 0; white-space: pre-wrap; `; diff --git a/packages/twenty-front/src/modules/ai/components/ToolStepRenderer.tsx b/packages/twenty-front/src/modules/ai/components/ToolStepRenderer.tsx index eadbdb6b4e..bcdc5f8deb 100644 --- a/packages/twenty-front/src/modules/ai/components/ToolStepRenderer.tsx +++ b/packages/twenty-front/src/modules/ai/components/ToolStepRenderer.tsx @@ -1,10 +1,11 @@ -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, IconChevronUp } from 'twenty-ui/display'; import { JsonTree } from 'twenty-ui/json-visualizer'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { CodeExecutionDisplay } from '@/ai/components/CodeExecutionDisplay'; import { ShimmeringText } from '@/ai/components/ShimmeringText'; @@ -24,16 +25,16 @@ import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` display: flex; flex-direction: column; - font-family: ${({ theme }) => theme.font.family}; - gap: ${({ theme }) => theme.spacing(2)}; + font-family: ${themeCssVariables.font.family}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledContentContainer = styled.div` - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.sm}; min-width: 0; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledJsonTreeContainer = styled.div` @@ -50,75 +51,80 @@ const StyledToggleButton = styled.div<{ isExpandable: boolean }>` border: none; cursor: ${({ isExpandable }) => (isExpandable ? 'pointer' : 'auto')}; display: flex; - color: ${({ theme }) => theme.font.color.tertiary}; - gap: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)} 0; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; + color: ${themeCssVariables.font.color.tertiary}; + gap: ${themeCssVariables.spacing[1]}; + padding: ${themeCssVariables.spacing[1]} 0; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; justify-content: space-between; width: 100%; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; const StyledToolName = styled.span` - background: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ theme }) => theme.font.color.light}; - font-family: ${({ theme }) => theme.font.family}; - font-size: ${({ theme }) => theme.font.size.xs}; - padding: ${({ theme }) => theme.spacing(0.5)} - ${({ theme }) => theme.spacing(1)}; + background: ${themeCssVariables.background.transparent.light}; + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${themeCssVariables.font.color.light}; + font-family: ${themeCssVariables.font.family}; + font-size: ${themeCssVariables.font.size.xs}; + padding: ${themeCssVariables.spacing['0.5']} ${themeCssVariables.spacing[1]}; `; const StyledLeftContent = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledRightContent = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledDisplayMessage = 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}; `; const StyledIconTextContainer = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; svg { - min-width: ${({ theme }) => theme.icon.size.sm}px; + min-width: calc(${themeCssVariables.icon.size.sm} * 1px); } `; const StyledTabContainer = styled.div` - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; - gap: ${({ theme }) => theme.spacing(3)}; - margin-bottom: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; const StyledTab = styled.div<{ isActive: boolean }>` - color: ${({ theme, isActive }) => - isActive ? theme.font.color.primary : theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme, isActive }) => - isActive ? theme.font.weight.medium : theme.font.weight.regular}; + color: ${({ isActive }) => + isActive + ? themeCssVariables.font.color.primary + : themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${({ isActive }) => + isActive + ? themeCssVariables.font.weight.medium + : themeCssVariables.font.weight.regular}; cursor: pointer; - transition: color ${({ theme }) => theme.animation.duration.fast}s ease-in-out; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + transition: color calc(${themeCssVariables.animation.duration.fast} * 1s) + ease-in-out; + padding-bottom: ${themeCssVariables.spacing[2]}; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; @@ -132,7 +138,7 @@ export const ToolStepRenderer = ({ isStreaming: boolean; }) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { copyToClipboard } = useCopyToClipboard(); const [isExpanded, setIsExpanded] = useState(false); const [activeTab, setActiveTab] = useState('output'); @@ -200,7 +206,6 @@ export const ToolStepRenderer = ({ ); } - // For execute_tool, the actual result is nested inside output.result const outputResult = ToolOutputResultSchema.safeParse(output); const unwrappedOutput = rawToolName === 'execute_tool' && outputResult.success diff --git a/packages/twenty-front/src/modules/ai/components/__stories__/AIChatMessage.stories.tsx b/packages/twenty-front/src/modules/ai/components/__stories__/AIChatMessage.stories.tsx index fff098b58e..5683cd18a9 100644 --- a/packages/twenty-front/src/modules/ai/components/__stories__/AIChatMessage.stories.tsx +++ b/packages/twenty-front/src/modules/ai/components/__stories__/AIChatMessage.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 { userEvent, within } from 'storybook/test'; import { type ExtendedUIMessage } from 'twenty-shared/ai'; diff --git a/packages/twenty-front/src/modules/ai/components/__tests__/AIChatAssistantMessageRenderer.test.tsx b/packages/twenty-front/src/modules/ai/components/__tests__/AIChatAssistantMessageRenderer.test.tsx index ba2200ed68..368c23cacb 100644 --- a/packages/twenty-front/src/modules/ai/components/__tests__/AIChatAssistantMessageRenderer.test.tsx +++ b/packages/twenty-front/src/modules/ai/components/__tests__/AIChatAssistantMessageRenderer.test.tsx @@ -1,4 +1,3 @@ -import { ThemeProvider as EmotionThemeProvider } from '@emotion/react'; import { render, screen } from '@testing-library/react'; import { THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme'; import { type ExtendedUIMessagePart } from 'twenty-shared/ai'; @@ -43,14 +42,12 @@ jest.mock('@/ai/components/CodeExecutionDisplay', () => ({ const renderAssistantRenderer = (messageParts: ExtendedUIMessagePart[]) => { return render( - - - - - , + + + , ); }; diff --git a/packages/twenty-front/src/modules/ai/components/__tests__/ThinkingStepsDisplay.test.tsx b/packages/twenty-front/src/modules/ai/components/__tests__/ThinkingStepsDisplay.test.tsx index 9a355ab6da..442282a742 100644 --- a/packages/twenty-front/src/modules/ai/components/__tests__/ThinkingStepsDisplay.test.tsx +++ b/packages/twenty-front/src/modules/ai/components/__tests__/ThinkingStepsDisplay.test.tsx @@ -1,4 +1,3 @@ -import { ThemeProvider as EmotionThemeProvider } from '@emotion/react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme'; @@ -81,15 +80,13 @@ const renderThinkingStepsDisplay = ({ hasAssistantTextResponseStarted?: boolean; }) => { return render( - - - - - , + + + , ); }; diff --git a/packages/twenty-front/src/modules/ai/components/internal/AIChatContextUsageButton.tsx b/packages/twenty-front/src/modules/ai/components/internal/AIChatContextUsageButton.tsx index a17916f214..a69d5c2cc4 100644 --- a/packages/twenty-front/src/modules/ai/components/internal/AIChatContextUsageButton.tsx +++ b/packages/twenty-front/src/modules/ai/components/internal/AIChatContextUsageButton.tsx @@ -1,11 +1,12 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { HorizontalSeparator } from 'twenty-ui/display'; import { ProgressBar } from 'twenty-ui/feedback'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { ContextUsageProgressRing } from '@/ai/components/internal/ContextUsageProgressRing'; import { SettingsBillingLabelValueItem } from '@/billing/components/internal/SettingsBillingLabelValueItem'; @@ -26,31 +27,34 @@ const StyledTrigger = styled.div<{ hasUsage: boolean }>` height: 24px; justify-content: center; min-width: 24px; - transition: background ${({ theme }) => theme.animation.duration.fast}s ease; + transition: background calc(${themeCssVariables.animation.duration.fast} * 1s) + ease; &:hover { - background: ${({ theme, hasUsage }) => - hasUsage ? theme.background.transparent.light : 'transparent'}; + background: ${({ hasUsage }) => + hasUsage + ? themeCssVariables.background.transparent.light + : 'transparent'}; } `; const StyledHoverCard = styled.div` - background: ${({ theme }) => theme.background.primary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; + background: ${themeCssVariables.background.primary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; + box-shadow: ${themeCssVariables.boxShadow.strong}; min-width: 280px; position: absolute; left: 0; bottom: calc(100% + 8px); - z-index: ${({ theme }) => theme.lastLayerZIndex}; + z-index: ${themeCssVariables.lastLayerZIndex}; `; const StyledSection = 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 StyledRow = styled.div` @@ -60,16 +64,16 @@ const StyledRow = styled.div` `; const StyledContextWindowValue = styled.span` - 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 StyledSectionTitle = styled.span` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const formatTokenCount = (count: number): string => { @@ -86,8 +90,6 @@ const formatTokenCount = (count: number): string => { }; const formatCredits = (credits: number): string => { - // Credits are already in display units from the API (internal / 1000) - // Show up to 1 decimal for fractional values, none for whole numbers if (Number.isInteger(credits)) { return credits.toLocaleString(); } @@ -112,7 +114,7 @@ const getCachedLabel = (lastMessage: AgentChatLastMessageUsage): string => { export const AIChatContextUsageButton = () => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isHovered, setIsHovered] = useState(false); const agentChatUsage = useAtomStateValue(agentChatUsageState); diff --git a/packages/twenty-front/src/modules/ai/components/internal/AIChatSkeletonLoader.tsx b/packages/twenty-front/src/modules/ai/components/internal/AIChatSkeletonLoader.tsx index bd856da1fa..70677d08b6 100644 --- a/packages/twenty-front/src/modules/ai/components/internal/AIChatSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/ai/components/internal/AIChatSkeletonLoader.tsx @@ -1,19 +1,21 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSkeletonContainer = styled.div` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(6)}; - padding: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[6]}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledMessageBubble = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; const StyledMessageSkeleton = styled.div` @@ -23,7 +25,7 @@ const StyledMessageSkeleton = styled.div` const NUMBER_OF_SKELETONS = 6; export const AIChatSkeletonLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; width: 100%; `; @@ -15,7 +16,7 @@ const StyledPreviewsContainer = styled.div` display: flex; flex-direction: row; flex-wrap: wrap; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; export const AgentChatContextPreview = () => { diff --git a/packages/twenty-front/src/modules/ai/components/internal/AgentChatFilePreview.tsx b/packages/twenty-front/src/modules/ai/components/internal/AgentChatFilePreview.tsx index 8bba266064..71c47331db 100644 --- a/packages/twenty-front/src/modules/ai/components/internal/AgentChatFilePreview.tsx +++ b/packages/twenty-front/src/modules/ai/components/internal/AgentChatFilePreview.tsx @@ -2,8 +2,8 @@ import { type AttachmentFileCategory } from '@/activities/files/types/Attachment import { getFileType } from '@/activities/files/utils/getFileType'; import { useFileCategoryColors } from '@/file/hooks/useFileCategoryColors'; import { IconMapping } from '@/file/utils/fileIconMappings'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; +import { useContext } from 'react'; import { type FileUIPart } from 'ai'; import { isDefined } from 'twenty-shared/utils'; import { @@ -14,6 +14,7 @@ import { } from 'twenty-ui/components'; import { type IconComponent, IconX } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; +import { ThemeContext } from 'twenty-ui/theme'; export const AgentChatFilePreview = ({ file, @@ -24,7 +25,7 @@ export const AgentChatFilePreview = ({ onRemove?: () => void; isUploading?: boolean; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const iconColors: Record = useFileCategoryColors(); diff --git a/packages/twenty-front/src/modules/ai/components/internal/AgentChatFileUploadButton.tsx b/packages/twenty-front/src/modules/ai/components/internal/AgentChatFileUploadButton.tsx index d6b48125bd..2a9298e49c 100644 --- a/packages/twenty-front/src/modules/ai/components/internal/AgentChatFileUploadButton.tsx +++ b/packages/twenty-front/src/modules/ai/components/internal/AgentChatFileUploadButton.tsx @@ -1,16 +1,17 @@ import { useAIChatFileUpload } from '@/ai/hooks/useAIChatFileUpload'; import { agentChatSelectedFilesState } from '@/ai/states/agentChatSelectedFilesState'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import React, { useRef } from 'react'; import { IconPlus } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledFileUploadContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledFileInput = styled.input` diff --git a/packages/twenty-front/src/modules/ai/components/internal/ContextUsageProgressRing.tsx b/packages/twenty-front/src/modules/ai/components/internal/ContextUsageProgressRing.tsx index cefcbbf1c4..56c585f7a0 100644 --- a/packages/twenty-front/src/modules/ai/components/internal/ContextUsageProgressRing.tsx +++ b/packages/twenty-front/src/modules/ai/components/internal/ContextUsageProgressRing.tsx @@ -1,5 +1,7 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type ContextUsageProgressRingProps = { percentage: number; @@ -15,8 +17,8 @@ const StyledBackgroundCircle = styled.circle` fill: none; stroke: color-mix( in srgb, - ${({ theme }) => theme.border.color.strong} 50%, - ${({ theme }) => theme.background.quaternary} 50% + ${themeCssVariables.border.color.strong} 50%, + ${themeCssVariables.background.quaternary} 50% ); `; @@ -30,7 +32,7 @@ export const ContextUsageProgressRing = ({ size = 16, strokeWidth = 2, }: ContextUsageProgressRingProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const normalizedPercentage = Math.min(Math.max(percentage, 0), 100); const radius = (size - strokeWidth) / 2; diff --git a/packages/twenty-front/src/modules/ai/components/suggested-prompts/AIChatSuggestedPrompts.tsx b/packages/twenty-front/src/modules/ai/components/suggested-prompts/AIChatSuggestedPrompts.tsx index f40951ade5..5fd76d216a 100644 --- a/packages/twenty-front/src/modules/ai/components/suggested-prompts/AIChatSuggestedPrompts.tsx +++ b/packages/twenty-front/src/modules/ai/components/suggested-prompts/AIChatSuggestedPrompts.tsx @@ -1,8 +1,9 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { type Editor } from '@tiptap/react'; import { LightButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { DEFAULT_SUGGESTED_PROMPTS, @@ -14,18 +15,18 @@ import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomStat const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[2]}; `; const StyledTitle = styled.div` align-content: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: grid; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; height: 24px; - padding: ${({ theme }) => `0 ${theme.spacing(2)}`}; + padding: 0 ${themeCssVariables.spacing[2]}; `; const StyledSuggestedPromptButton = styled(LightButton)` diff --git a/packages/twenty-front/src/modules/auth/components/AuthModal.tsx b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx index 3f825f1ea6..612bce2fbd 100644 --- a/packages/twenty-front/src/modules/auth/components/AuthModal.tsx +++ b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx @@ -3,7 +3,7 @@ import { AUTH_MODAL_ID } from '@/auth/constants/AuthModalId'; import { getAuthModalConfig } from '@/auth/utils/getAuthModalConfig'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import React from 'react'; import { useLocation } from 'react-router-dom'; diff --git a/packages/twenty-front/src/modules/auth/components/Logo.tsx b/packages/twenty-front/src/modules/auth/components/Logo.tsx index 957ed33be8..0135ed0c3b 100644 --- a/packages/twenty-front/src/modules/auth/components/Logo.tsx +++ b/packages/twenty-front/src/modules/auth/components/Logo.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isNonEmptyString } from '@sniptt/guards'; import { AppPath } from 'twenty-shared/types'; import { getImageAbsoluteURI, isDefined } from 'twenty-shared/utils'; import { Avatar } from 'twenty-ui/display'; import { UndecoratedLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useRedirectToDefaultDomain } from '~/modules/domain-manager/hooks/useRedirectToDefaultDomain'; @@ -15,32 +16,32 @@ type LogoProps = { }; const StyledContainer = styled.div` - height: ${({ theme }) => theme.spacing(12)}; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + height: ${themeCssVariables.spacing[12]}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[4]}; position: relative; - width: ${({ theme }) => theme.spacing(12)}; + width: ${themeCssVariables.spacing[12]}; `; const StyledSecondaryLogo = styled.img` - border-radius: ${({ theme }) => theme.border.radius.xs}; - height: ${({ theme }) => theme.spacing(6)}; - width: ${({ theme }) => theme.spacing(6)}; + border-radius: ${themeCssVariables.border.radius.xs}; + height: ${themeCssVariables.spacing[6]}; + width: ${themeCssVariables.spacing[6]}; `; const StyledSecondaryLogoContainer = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.primary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - bottom: ${({ theme }) => `-${theme.spacing(3)}`}; + background-color: ${themeCssVariables.background.primary}; + border-radius: ${themeCssVariables.border.radius.sm}; + bottom: calc(-1 * ${themeCssVariables.spacing[3]}); display: flex; - height: ${({ theme }) => theme.spacing(7)}; + height: ${themeCssVariables.spacing[7]}; justify-content: center; position: absolute; - right: ${({ theme }) => `-${theme.spacing(3)}`}; - width: ${({ theme }) => theme.spacing(7)}; + right: calc(-1 * ${themeCssVariables.spacing[3]}); + width: ${themeCssVariables.spacing[7]}; `; const StyledPrimaryLogo = styled.div<{ src: string }>` diff --git a/packages/twenty-front/src/modules/auth/components/SubTitle.tsx b/packages/twenty-front/src/modules/auth/components/SubTitle.tsx index 90492b0e69..4c6fefd548 100644 --- a/packages/twenty-front/src/modules/auth/components/SubTitle.tsx +++ b/packages/twenty-front/src/modules/auth/components/SubTitle.tsx @@ -1,7 +1,8 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSubTitle = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; text-align: center; `; diff --git a/packages/twenty-front/src/modules/auth/components/Title.tsx b/packages/twenty-front/src/modules/auth/components/Title.tsx index 52dba36072..67983cd0f9 100644 --- a/packages/twenty-front/src/modules/auth/components/Title.tsx +++ b/packages/twenty-front/src/modules/auth/components/Title.tsx @@ -1,5 +1,6 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import React from 'react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseIn } from 'twenty-ui/utilities'; type TitleProps = React.PropsWithChildren & { @@ -8,12 +9,12 @@ type TitleProps = React.PropsWithChildren & { }; const StyledTitle = styled.div>` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.xl}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme, noMarginTop }) => - !noMarginTop ? theme.spacing(4) : 0}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.xl}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${({ noMarginTop }) => + !noMarginTop ? themeCssVariables.spacing[4] : '0'}; `; export const Title = ({ diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx index 1c1cad803c..12e7e1ea08 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; @@ -17,13 +17,14 @@ import { IconMicrosoft, } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseIn } from 'twenty-ui/utilities'; const StyledContainer = styled.div` display: flex; flex-direction: column; align-items: center; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; width: 100%; `; @@ -35,14 +36,14 @@ const StyledTextContainer = styled.div` `; const StyledEmail = styled.span` - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledButtonsContainer = styled.div` display: flex; flex-direction: column; align-items: center; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; width: 100%; max-width: 240px; `; @@ -51,22 +52,22 @@ const StyledBottomLinks = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; justify-content: center; `; const StyledLinkButton = styled.button` background: none; border: none; - font-family: ${({ theme }) => theme.font.family}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-family: ${themeCssVariables.font.family}; + font-size: ${themeCssVariables.font.size.xs}; + font-weight: ${themeCssVariables.font.weight.regular}; line-height: 140%; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; cursor: pointer; &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } &:disabled { @@ -76,7 +77,7 @@ const StyledLinkButton = styled.button` `; const StyledDot = styled.div` - background: ${({ theme }) => theme.font.color.light}; + background: ${themeCssVariables.font.color.light}; border-radius: 50%; height: 2px; width: 2px; diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx index cf3a92dc0d..c7f07b03ee 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/FooterNote.tsx @@ -1,18 +1,19 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans } from '@lingui/react/macro'; import { useWorkspaceBypass } from '@/auth/sign-in-up/hooks/useWorkspaceBypass'; import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCopyContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; max-width: 280px; text-align: center; & > a { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; text-decoration: none; &:hover { @@ -23,11 +24,11 @@ const StyledCopyContainer = styled.div` const StyledLinksContainer = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; flex-wrap: nowrap; - font-size: ${({ theme }) => theme.font.size.sm}; - gap: ${({ theme }) => theme.spacing(2)}; + font-size: ${themeCssVariables.font.size.sm}; + gap: ${themeCssVariables.spacing[2]}; justify-content: center; max-width: 100%; text-align: center; @@ -37,7 +38,7 @@ const StyledLinksContainer = styled.div` & > button { background: none; border: none; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; cursor: pointer; font: inherit; padding: 0; @@ -50,7 +51,7 @@ const StyledLinksContainer = styled.div` `; const StyledSeparator = styled.span` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export const FooterNote = () => { diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx index 30384c0916..8bc0e30f76 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpGlobalScopeForm.tsx @@ -1,10 +1,10 @@ import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState'; import { returnToPathState } from '@/auth/states/returnToPathState'; import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { motion } from 'framer-motion'; +import { useContext } from 'react'; import { FormProvider } from 'react-hook-form'; import { ClickToActionLink, UndecoratedLink } from 'twenty-ui/navigation'; @@ -27,30 +27,32 @@ import { IconChevronRight, IconPlus, } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type AvailableWorkspace } from '~/generated-metadata/graphql'; import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { isNonEmptyString } from '@sniptt/guards'; const StyledContentContainer = styled(motion.div)` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; min-width: 200px; `; const StyledWorkspaceContainer = styled.div` - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; overflow: hidden; width: 100%; > * { - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; &:last-child { border-bottom: none; @@ -63,7 +65,7 @@ const StyledWorkspaceItem = styled.div` flex-direction: row; align-items: center; width: 100%; - height: ${({ theme }) => theme.spacing(15)}; + height: ${themeCssVariables.spacing[15]}; padding: 0; overflow: hidden; @@ -71,7 +73,7 @@ const StyledWorkspaceItem = styled.div` justify-content: space-between; &:hover { - background-color: ${({ theme }) => theme.background.transparent.light}; + background-color: ${themeCssVariables.background.transparent.light}; } &:last-child { @@ -82,9 +84,9 @@ const StyledWorkspaceItem = styled.div` const StyledWorkspaceContent = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; width: 100%; - padding: 0 ${({ theme }) => theme.spacing(4)}; + padding: 0 ${themeCssVariables.spacing[4]}; `; const StyledWorkspaceTextContainer = styled.div` @@ -94,29 +96,29 @@ const StyledWorkspaceTextContainer = styled.div` `; const StyledWorkspaceLogo = styled.div` - border-radius: ${({ theme }) => theme.border.radius.sm}; - height: ${({ theme }) => theme.spacing(6)}; - width: ${({ theme }) => theme.spacing(6)}; - background-color: ${({ theme }) => theme.background.transparent.light}; + border-radius: ${themeCssVariables.border.radius.sm}; + height: ${themeCssVariables.spacing[6]}; + width: ${themeCssVariables.spacing[6]}; + background-color: ${themeCssVariables.background.transparent.light}; display: flex; justify-content: center; align-items: center; `; const StyledWorkspaceName = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - padding-bottom: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.medium}; + padding-bottom: ${themeCssVariables.spacing[1]}; `; const StyledWorkspaceUrl = styled.div` - 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 StyledChevronIcon = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; display: flex; `; @@ -133,7 +135,7 @@ export const SignInUpGlobalScopeForm = () => { const { createWorkspace } = useSignUpInNewWorkspace(); const availableWorkspaces = useAtomStateValue(availableWorkspacesState); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); const { form } = useSignInUpForm(); diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx index 484a30eb4d..2f977dad61 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx @@ -9,16 +9,17 @@ import { useWorkspaceBypass } from '@/auth/sign-in-up/hooks/useWorkspaceBypass'; import { SignInUpStep } from '@/auth/states/signInUpStepState'; import { workspaceAuthBypassProvidersState } from '@/workspace/states/workspaceAuthBypassProvidersState'; import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans } from '@lingui/react/macro'; import { FormProvider } from 'react-hook-form'; import { HorizontalSeparator } from 'twenty-ui/display'; import { ClickToActionLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; const StyledContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; min-width: 200px; `; 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 33faf652f7..6287f3c4d2 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 @@ -1,16 +1,17 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { Pill } from 'twenty-ui/components'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledPill = styled(Pill)` - background: ${({ theme }) => theme.color.blue3}; - border: 1px solid ${({ theme }) => theme.color.blue5}; - border-radius: ${({ theme }) => theme.border.radius.pill}; - color: ${({ theme }) => theme.color.blue}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; + 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}; position: absolute; - right: -${({ theme }) => theme.spacing(5)}; - top: -${({ theme }) => theme.spacing(2)}; + right: calc(-1 * ${themeCssVariables.spacing[5]}); + top: calc(-1 * ${themeCssVariables.spacing[2]}); `; export const LastUsedPill = () => { diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpEmailField.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpEmailField.tsx index bfa76103d9..3707d3da68 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpEmailField.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpEmailField.tsx @@ -1,17 +1,18 @@ import { type Form } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { motion } from 'framer-motion'; import { Controller, useFormContext } from 'react-hook-form'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledFullWidthMotionDiv = styled(motion.div)` width: 100%; `; const StyledInputContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; export const SignInUpEmailField = ({ diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpPasswordField.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpPasswordField.tsx index 95299d067a..cccac77c27 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpPasswordField.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpPasswordField.tsx @@ -1,19 +1,21 @@ import { type Form } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { SignInUpMode } from '@/auth/types/signInUpMode'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { motion } from 'framer-motion'; +import { useContext } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { StyledText } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledFullWidthMotionDiv = styled(motion.div)` width: 100%; `; const StyledInputContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; export const SignInUpPasswordField = ({ @@ -24,7 +26,7 @@ export const SignInUpPasswordField = ({ signInUpMode: SignInUpMode; }) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const form = useFormContext
    (); return ( diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOButtonStyles.ts b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOButtonStyles.ts index 874e2fdd3c..d04418b7a5 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOButtonStyles.ts +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOButtonStyles.ts @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; export const StyledSSOButtonContainer = styled.div` position: relative; diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOIdentityProviderSelection.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOIdentityProviderSelection.tsx index 88fbfc65a6..88a87213ee 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOIdentityProviderSelection.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpSSOIdentityProviderSelection.tsx @@ -2,18 +2,19 @@ import { useSSO } from '@/auth/sign-in-up/hooks/useSSO'; import { guessSSOIdentityProviderIconByUrl } from '@/settings/security/utils/guessSSOIdentityProviderIconByUrl'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState'; import React from 'react'; import { isDefined } from 'twenty-shared/utils'; import { HorizontalSeparator } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; const StyledContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; `; export const SignInUpSSOIdentityProviderSelection = () => { diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx index 0b5f05ddc8..d88aa1323e 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx @@ -5,34 +5,36 @@ import { signInUpStepState, } from '@/auth/states/signInUpStepState'; import { extractSecretFromOtpUri } from '@/settings/two-factor-authentication/utils/extractSecretFromOtpUri'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; +import { useContext } from 'react'; import QRCode from 'react-qr-code'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { IconCopy } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; import { MainButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledMainContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; text-align: center; `; const StyledTextContainer = styled.div` align-items: center; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - color: ${({ theme }) => theme.font.color.tertiary}; + margin-bottom: ${themeCssVariables.spacing[4]}; + color: ${themeCssVariables.font.color.tertiary}; max-width: 280px; text-align: center; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; & > a { - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; text-decoration: none; &:hover { @@ -51,24 +53,24 @@ const StyledForm = styled.div` const StyledCopySetupKeyLink = styled.button` background: none; border: none; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; cursor: pointer; display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-top: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + font-size: ${themeCssVariables.font.size.sm}; + margin-top: ${themeCssVariables.spacing[2]}; padding: 0; text-decoration: underline; &:hover { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; export const SignInUpTwoFactorAuthenticationProvision = () => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { copyToClipboard } = useCopyToClipboard(); const qrCode = useAtomStateValue(qrCodeState); const setSignInUpStep = useSetAtomState(signInUpStepState); diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationVerification.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationVerification.tsx index dba5f1bc38..482abdb4fb 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationVerification.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationVerification.tsx @@ -1,5 +1,4 @@ -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useAuth } from '@/auth/hooks/useAuth'; import { @@ -21,13 +20,14 @@ import { Controller } from 'react-hook-form'; import { AppPath } from 'twenty-shared/types'; import { MainButton } from 'twenty-ui/input'; import { ClickToActionLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; const StyledMainContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; text-align: center; `; @@ -47,12 +47,12 @@ const StyledSlot = styled.div<{ isActive: boolean }>` align-items: center; justify-content: center; transition: all 0.3s; - border-top: 1px solid ${({ theme }) => theme.border.color.medium}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; - border-right: 1px solid ${({ theme }) => theme.border.color.medium}; + border-top: 1px solid ${themeCssVariables.border.color.medium}; + border-bottom: 1px solid ${themeCssVariables.border.color.medium}; + border-right: 1px solid ${themeCssVariables.border.color.medium}; &:first-of-type { - border-left: 1px solid ${({ theme }) => theme.border.color.medium}; + border-left: 1px solid ${themeCssVariables.border.color.medium}; border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; } @@ -64,19 +64,15 @@ const StyledSlot = styled.div<{ isActive: boolean }>` .group:hover &, .group:focus-within & { - border-color: ${({ theme }) => theme.border.color.medium}; + border-color: ${themeCssVariables.border.color.medium}; } - outline: 0; - outline-color: ${({ theme }) => theme.border.color.medium}; - - ${({ isActive, theme }) => - isActive && - css` - outline-width: 1px; - outline-style: solid; - outline-color: ${theme.border.color.strong}; - `} + outline-width: ${({ isActive }) => (isActive ? '1px' : '0')}; + outline-style: ${({ isActive }) => (isActive ? 'solid' : 'none')}; + outline-color: ${({ isActive }) => + isActive + ? themeCssVariables.border.color.strong + : themeCssVariables.border.color.medium}; `; const StyledPlaceholderChar = styled.div` @@ -119,7 +115,7 @@ const StyledCaretContainer = styled.div` const StyledCaret = styled.div` width: 1px; height: 2rem; - background-color: ${({ theme }) => theme.font.color.light}; + background-color: ${themeCssVariables.font.color.light}; `; const FakeCaret = () => { @@ -138,7 +134,7 @@ const StyledDashContainer = styled.div` `; const StyledDash = styled.div` - background-color: ${({ theme }) => theme.font.color.primary}; + background-color: ${themeCssVariables.font.color.primary}; border-radius: 9999px; height: 0.25rem; width: 0.75rem; @@ -166,16 +162,16 @@ const StyledSlotGroup = styled.div` `; const StyledTextContainer = styled.div` align-items: center; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - color: ${({ theme }) => theme.font.color.tertiary}; + margin-bottom: ${themeCssVariables.spacing[4]}; + color: ${themeCssVariables.font.color.tertiary}; max-width: 280px; text-align: center; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; `; const StyledActionBackLinkContainer = styled.div` - margin: ${({ theme }) => theme.spacing(3)} 0 0; + margin: ${themeCssVariables.spacing[3]} 0 0; `; export const SignInUpTOTPVerification = () => { diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithCredentials.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithCredentials.tsx index f99e43d79b..730d5d70ff 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithCredentials.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithCredentials.tsx @@ -15,7 +15,7 @@ import { AuthenticatedMethod } from '@/auth/types/AuthenticatedMethod.enum'; import { SignInUpMode } from '@/auth/types/signInUpMode'; import { isRequestingCaptchaTokenState } from '@/captcha/states/isRequestingCaptchaTokenState'; import { captchaState } from '@/client-config/states/captchaState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useMemo, useState } from 'react'; import { useFormContext } from 'react-hook-form'; diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithGoogle.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithGoogle.tsx index e05e948932..c4b7a67df7 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithGoogle.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithGoogle.tsx @@ -7,18 +7,18 @@ import { } from '@/auth/states/signInUpStepState'; import { AuthenticatedMethod } from '@/auth/types/AuthenticatedMethod.enum'; import { type SocialSSOSignInUpActionType } from '@/auth/types/socialSSOSignInUp.type'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; -import { memo } from 'react'; +import { memo, useContext } from 'react'; import { HorizontalSeparator, IconGoogle } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { LastUsedPill } from './LastUsedPill'; import { StyledSSOButtonContainer } from './SignInUpSSOButtonStyles'; const GoogleIcon = memo(() => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ; }); diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithMicrosoft.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithMicrosoft.tsx index eeb4c581a2..fe7fc4306c 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithMicrosoft.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithMicrosoft.tsx @@ -7,10 +7,11 @@ import { } from '@/auth/states/signInUpStepState'; import { AuthenticatedMethod } from '@/auth/types/AuthenticatedMethod.enum'; import { type SocialSSOSignInUpActionType } from '@/auth/types/socialSSOSignInUp.type'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; +import { useContext } from 'react'; import { HorizontalSeparator, IconMicrosoft } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { LastUsedPill } from './LastUsedPill'; @@ -23,7 +24,7 @@ export const SignInUpWithMicrosoft = ({ action: SocialSSOSignInUpActionType; isGlobalScope?: boolean; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); const signInUpStep = useAtomStateValue(signInUpStepState); diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithSSO.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithSSO.tsx index e4fa255792..eccf3b0e6b 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithSSO.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpWithSSO.tsx @@ -10,16 +10,17 @@ import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthPro import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; +import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { HorizontalSeparator, IconLock } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; import { LastUsedPill } from './LastUsedPill'; import { StyledSSOButtonContainer } from './SignInUpSSOButtonStyles'; export const SignInUpWithSSO = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { t } = useLingui(); const setSignInUpStep = useSetAtomState(signInUpStepState); const workspaceAuthProviders = useAtomStateValue(workspaceAuthProvidersState); diff --git a/packages/twenty-front/src/modules/error-handler/components/AppFullScreenErrorFallback.tsx b/packages/twenty-front/src/modules/error-handler/components/AppFullScreenErrorFallback.tsx index 0376fa986a..9598cc6eca 100644 --- a/packages/twenty-front/src/modules/error-handler/components/AppFullScreenErrorFallback.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/AppFullScreenErrorFallback.tsx @@ -1,19 +1,20 @@ import { AppErrorDisplay } from '@/error-handler/components/internal/AppErrorDisplay'; import { type AppErrorDisplayProps } from '@/error-handler/types/AppErrorDisplayProps'; import { PageBody } from '@/ui/layout/page/components/PageBody'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type AppFullScreenErrorFallbackProps = AppErrorDisplayProps; const StyledContainer = styled.div` - background: ${({ theme }) => theme.background.noisy}; + background: ${themeCssVariables.background.noisy}; box-sizing: border-box; display: flex; height: 100vh; width: 100vw; - padding-top: ${({ theme }) => theme.spacing(3)}; - padding-left: ${({ theme }) => theme.spacing(3)}; + padding-top: ${themeCssVariables.spacing[3]}; + padding-left: ${themeCssVariables.spacing[3]}; `; export const AppFullScreenErrorFallback = ({ diff --git a/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx b/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx index 3867c3f37e..df077c1b8f 100644 --- a/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx +++ b/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx @@ -1,9 +1,10 @@ import { type AppErrorDisplayProps } from '@/error-handler/types/AppErrorDisplayProps'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { motion } from 'framer-motion'; import { IconReload } from 'twenty-ui/display'; import { THEME_DARK } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type AppRootErrorFallbackProps = AppErrorDisplayProps; @@ -17,8 +18,8 @@ const StyledContainer = styled.div` `; const StyledPanel = styled.div` - background: ${({ theme }) => theme.grayScale.gray1}; - border: 1px solid ${({ theme }) => theme.grayScale.gray5}; + background: ${themeCssVariables.grayScale.gray1}; + border: 1px solid ${themeCssVariables.grayScale.gray5}; border-radius: 8px; height: 100%; overflow-x: auto; @@ -66,13 +67,13 @@ const StyledEmptyTextContainer = styled.div` `; const StyledEmptyTitle = styled.div` - color: ${({ theme }) => theme.grayScale.gray12}; + color: ${themeCssVariables.grayScale.gray12}; font-size: 1.23rem; font-weight: 600; `; const StyledEmptySubTitle = styled.div` - color: ${({ theme }) => theme.grayScale.gray11}; + color: ${themeCssVariables.grayScale.gray11}; font-size: 0.92rem; font-weight: 400; line-height: 1.5; @@ -83,9 +84,9 @@ const StyledEmptySubTitle = styled.div` const StyledButton = styled.button` align-items: center; - background: ${({ theme }) => theme.grayScale.gray1}; - border: 1px solid ${({ theme }) => theme.grayScale.gray5}; - color: ${({ theme }) => theme.grayScale.gray12}; + background: ${themeCssVariables.grayScale.gray1}; + border: 1px solid ${themeCssVariables.grayScale.gray5}; + color: ${themeCssVariables.grayScale.gray12}; border-radius: 8px; cursor: pointer; display: flex; @@ -94,7 +95,7 @@ const StyledButton = styled.button` `; const StyledIcon = styled(IconReload)` - color: ${({ theme }) => theme.grayScale.gray12}; + color: ${themeCssVariables.grayScale.gray12}; margin-right: 8px; `; diff --git a/packages/twenty-front/src/modules/file/components/FileIcon.tsx b/packages/twenty-front/src/modules/file/components/FileIcon.tsx index fbfd9d80fc..e682a25766 100644 --- a/packages/twenty-front/src/modules/file/components/FileIcon.tsx +++ b/packages/twenty-front/src/modules/file/components/FileIcon.tsx @@ -1,10 +1,12 @@ import { type AttachmentFileCategory } from '@/activities/files/types/AttachmentFileCategory'; import { useFileIconColors } from '@/file/hooks/useFileIconColors'; import { IconMapping } from '@/file/utils/fileIconMappings'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { type FileCategory } from 'twenty-shared/types'; import { AvatarOrIcon } from 'twenty-ui/components'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; type FileIconSize = 'small' | 'medium'; @@ -13,8 +15,8 @@ const StyledIconContainer = styled.div<{ }>` align-items: center; background: ${({ background }) => background}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.grayScale.gray1}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.grayScale.gray1}; display: flex; flex-shrink: 0; justify-content: center; @@ -28,7 +30,7 @@ export const FileIcon = ({ fileCategory: AttachmentFileCategory | FileCategory; size?: FileIconSize; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const iconColors = useFileIconColors(); const Icon = IconMapping[fileCategory]; diff --git a/packages/twenty-front/src/modules/file/hooks/useFileCategoryColors.ts b/packages/twenty-front/src/modules/file/hooks/useFileCategoryColors.ts index a8e8b1dad9..029c661e62 100644 --- a/packages/twenty-front/src/modules/file/hooks/useFileCategoryColors.ts +++ b/packages/twenty-front/src/modules/file/hooks/useFileCategoryColors.ts @@ -1,15 +1,15 @@ import { type AttachmentFileCategory } from '@/activities/files/types/AttachmentFileCategory'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; -import { type ThemeColor } from 'twenty-ui/theme'; +import { type ThemeColor, ThemeContext } from 'twenty-ui/theme'; export const useFileCategoryColors = (): Record< AttachmentFileCategory, string > => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular: CoreObjectNameSingular.Attachment, }); diff --git a/packages/twenty-front/src/modules/file/hooks/useFileIconColors.ts b/packages/twenty-front/src/modules/file/hooks/useFileIconColors.ts index 81efa70c4f..4cd85f4fa5 100644 --- a/packages/twenty-front/src/modules/file/hooks/useFileIconColors.ts +++ b/packages/twenty-front/src/modules/file/hooks/useFileIconColors.ts @@ -1,12 +1,13 @@ import { type AttachmentFileCategory } from '@/activities/files/types/AttachmentFileCategory'; -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; import { type FileCategory } from 'twenty-shared/types'; +import { ThemeContext } from 'twenty-ui/theme'; export const useFileIconColors = (): Record< AttachmentFileCategory | FileCategory, string > => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return { ARCHIVE: theme.color.gray, diff --git a/packages/twenty-front/src/modules/front-components/components/FrontComponentRenderer.tsx b/packages/twenty-front/src/modules/front-components/components/FrontComponentRenderer.tsx index 32d6de909a..192eea8b33 100644 --- a/packages/twenty-front/src/modules/front-components/components/FrontComponentRenderer.tsx +++ b/packages/twenty-front/src/modules/front-components/components/FrontComponentRenderer.tsx @@ -5,11 +5,11 @@ import { frontComponentApplicationTokenPairComponentState } from '@/front-compon import { getFrontComponentUrl } from '@/front-components/utils/getFrontComponentUrl'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; -import { useCallback } from 'react'; +import { useCallback, useContext } from 'react'; import { FrontComponentRenderer as SharedFrontComponentRenderer } from 'twenty-sdk/front-component-renderer'; import { isDefined } from 'twenty-shared/utils'; +import { ThemeContext } from 'twenty-ui/theme'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useFindOneFrontComponentQuery } from '~/generated-metadata/graphql'; @@ -20,7 +20,7 @@ type FrontComponentRendererProps = { export const FrontComponentRenderer = ({ frontComponentId, }: FrontComponentRendererProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { enqueueErrorSnackBar } = useSnackBar(); const setFrontComponentApplicationTokenPair = useSetAtomComponentState( diff --git a/packages/twenty-front/src/modules/geo-map/components/PlaceAutocompleteSelect.tsx b/packages/twenty-front/src/modules/geo-map/components/PlaceAutocompleteSelect.tsx index 62141b31c7..b8d0ecfe00 100644 --- a/packages/twenty-front/src/modules/geo-map/components/PlaceAutocompleteSelect.tsx +++ b/packages/twenty-front/src/modules/geo-map/components/PlaceAutocompleteSelect.tsx @@ -3,7 +3,7 @@ import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useMemo, useRef } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type SelectOption } from 'twenty-ui/input'; diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx index 70b965b182..3b59008e9a 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader.tsx @@ -1,19 +1,21 @@ 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 { useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSkeletonColumn = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; height: 76px; - padding-left: ${({ theme }) => theme.spacing(1)}; + padding-left: ${themeCssVariables.spacing[1]}; `; export const NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader: React.FC = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.betweenSiblingsGap}; + gap: ${themeCssVariables.betweenSiblingsGap}; `; type NavigationDrawerSectionForWorkspaceItemsProps = { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts index d058fca5ac..380e64592f 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts @@ -1,9 +1,10 @@ import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType'; import { getIconForObjectType } from '@/object-metadata/utils/getIconForObjectType'; -import { useTheme } from '@emotion/react'; +import { useContext } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; export const useGetStandardObjectIcon = (objectNameSingular: string) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { Icon, IconColor } = { Icon: getIconForObjectType(objectNameSingular), diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getIconColorForObjectType.ts b/packages/twenty-front/src/modules/object-metadata/utils/getIconColorForObjectType.ts index b7176a2454..0cbcba1534 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getIconColorForObjectType.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getIconColorForObjectType.ts @@ -1,11 +1,11 @@ -import { type Theme } from '@emotion/react'; +import { type ThemeType } from 'twenty-ui/theme'; export const getIconColorForObjectType = ({ objectType, theme, }: { objectType: string; - theme: Theme; + theme: ThemeType; }): string => { switch (objectType) { case 'note': diff --git a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx index c802c70ae1..16bb5ed648 100644 --- a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx +++ b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx @@ -25,6 +25,7 @@ export type RecordChipProps = { className?: string; variant?: ChipVariant.Highlighted | ChipVariant.Transparent; forceDisableClick?: boolean; + isBold?: boolean; maxWidth?: number; to?: string | undefined; size?: ChipSize; @@ -39,6 +40,7 @@ export const RecordChip = ({ record, className, variant, + isBold = false, maxWidth, to, size, @@ -85,6 +87,7 @@ export const RecordChip = ({ ` align-items: center; display: flex; justify-content: center; border: 2px solid ${({ color }) => color}; - border-radius: ${({ theme }) => theme.border.radius.rounded}; + border-radius: ${themeCssVariables.border.radius.rounded}; box-shadow: ${({ color }) => color && `-4px 4px 0 -2px ${color}`}; height: 36px; width: 36px; @@ -20,7 +22,7 @@ type OnboardingModalCircularIconProps = { export const OnboardingModalCircularIcon = ({ Icon, }: OnboardingModalCircularIconProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const color = theme.background.invertedPrimary; return ( diff --git a/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx b/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx index 364ac47bb5..7c8f22b294 100644 --- a/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx +++ b/packages/twenty-front/src/modules/onboarding/components/OnboardingSyncEmailsSettingsCard.tsx @@ -1,7 +1,8 @@ import { ONBOARDING_SYNC_EMAILS_OPTIONS } from '@/onboarding/constants/OnboardingSyncEmailsOptions'; import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; import { SettingsAccountsVisibilityIcon } from '@/settings/accounts/components/SettingsAccountsVisibilityIcon'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { MessageChannelVisibility } from '~/generated/graphql'; type OnboardingSyncEmailsSettingsCardProps = { @@ -10,7 +11,7 @@ type OnboardingSyncEmailsSettingsCardProps = { }; const StyledCardMedia = styled(SettingsAccountsVisibilityIcon)` - width: ${({ theme }) => theme.spacing(10)}; + width: ${themeCssVariables.spacing[10]}; `; export const OnboardingSyncEmailsSettingsCard = ({ diff --git a/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx b/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx index 6b03ffaebd..7270bd6e3a 100644 --- a/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx +++ b/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx @@ -11,6 +11,7 @@ const StyledTableRow = styled('div', { onClick?: () => void; to?: string; gridAutoColumns?: string; + gridTemplateColumns?: string; mobileGridAutoColumns?: string; }>` background-color: ${({ isSelected, theme }) => @@ -18,6 +19,10 @@ const StyledTableRow = styled('div', { border-radius: ${({ theme }) => theme.border.radius.sm}; display: grid; grid-auto-columns: ${({ gridAutoColumns }) => gridAutoColumns ?? '1fr'}; + ${({ gridTemplateColumns }) => + gridTemplateColumns + ? `grid-template-columns: ${gridTemplateColumns};` + : ''}; @media (max-width: ${MOBILE_VIEWPORT}px) { grid-auto-columns: ${({ mobileGridAutoColumns, gridAutoColumns }) => @@ -35,31 +40,44 @@ const StyledTableRow = styled('div', { onClick || to ? theme.background.transparent.light : 'transparent'}; cursor: ${({ onClick, to }) => (onClick || to ? 'pointer' : 'default')}; } + + &[data-clickable='true'] { + cursor: pointer; + } `; type TableRowProps = { isSelected?: boolean; + isClickable?: boolean; onClick?: () => void; to?: string; className?: string; + style?: React.CSSProperties; gridAutoColumns?: string; + gridTemplateColumns?: string; mobileGridAutoColumns?: string; }; export const TableRow = ({ isSelected, + isClickable, onClick, to, className, + style, children, gridAutoColumns, + gridTemplateColumns, mobileGridAutoColumns, }: React.PropsWithChildren) => ( ` &.scroll-wrapper-x-enabled { overflow-x: overlay; } @@ -17,7 +17,7 @@ const StyledScrollWrapper = styled.div` overflow-x: hidden; overflow-y: hidden; width: 100%; - height: 100%; + height: ${({ autoHeight }) => (autoHeight ? 'auto' : '100%')}; `; export type ScrollWrapperProps = { @@ -25,6 +25,7 @@ export type ScrollWrapperProps = { className?: string; defaultEnableXScroll?: boolean; defaultEnableYScroll?: boolean; + autoHeight?: boolean; componentInstanceId: string; }; @@ -34,6 +35,7 @@ export const ScrollWrapper = ({ className, defaultEnableXScroll = true, defaultEnableYScroll = true, + autoHeight = false, }: ScrollWrapperProps) => { const setScrollWrapperScrollTop = useSetAtomComponentState( scrollWrapperScrollTopComponentState, @@ -70,6 +72,7 @@ export const ScrollWrapper = ({ {children} diff --git a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteLink.tsx b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteLink.tsx index fca47c8069..08bdc9d838 100644 --- a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteLink.tsx +++ b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteLink.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { useLingui } from '@lingui/react/macro'; import { IconLink } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledContainer = styled.div` @@ -14,7 +15,7 @@ const StyledContainer = styled.div` const StyledLinkContainer = styled.div` flex: 1; - margin-right: ${({ theme }) => theme.spacing(2)}; + margin-right: ${themeCssVariables.spacing[2]}; `; type WorkspaceInviteLinkProps = { diff --git a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx index c4d13216c1..9108eb78ed 100644 --- a/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx +++ b/packages/twenty-front/src/modules/workspace/components/WorkspaceInviteTeam.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; @@ -23,13 +23,14 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContainer = styled.div` display: flex; flex-direction: row; align-items: center; - gap: ${({ theme }) => theme.spacing(2)}; - padding-bottom: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[2]}; + padding-bottom: ${themeCssVariables.spacing[3]}; @media (max-width: ${MOBILE_VIEWPORT}px) { flex-wrap: wrap; diff --git a/packages/twenty-front/src/pages/auth/Authorize.tsx b/packages/twenty-front/src/pages/auth/Authorize.tsx index 330730a630..99ceaf142a 100644 --- a/packages/twenty-front/src/pages/auth/Authorize.tsx +++ b/packages/twenty-front/src/pages/auth/Authorize.tsx @@ -1,5 +1,5 @@ import { FIND_APPLICATION_REGISTRATION_BY_CLIENT_ID } from '@/settings/application-registrations/graphql/queries/findApplicationRegistrationByClientId'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { AppPath } from 'twenty-shared/types'; @@ -12,6 +12,7 @@ import { isDefined } from 'twenty-shared/utils'; import { Avatar } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; import { UndecoratedLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAuthorizeAppMutation } from '~/generated-metadata/graphql'; import { useNavigateApp } from '~/hooks/useNavigateApp'; @@ -28,28 +29,28 @@ const StyledAppsContainer = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; justify-content: center; `; const StyledText = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; font-family: 'Inter'; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - padding: ${({ theme }) => theme.spacing(6)} 0px; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + padding: ${themeCssVariables.spacing[6]} 0px; `; const StyledCardWrapper = styled.div` display: flex; - background-color: ${({ theme }) => theme.background.primary}; + background-color: ${themeCssVariables.background.primary}; flex-direction: column; align-items: center; justify-content: center; width: 400px; - padding: ${({ theme }) => theme.spacing(6)}; - box-shadow: ${({ theme }) => theme.boxShadow.strong}; - border-radius: ${({ theme }) => theme.border.radius.md}; + padding: ${themeCssVariables.spacing[6]}; + box-shadow: ${themeCssVariables.boxShadow.strong}; + border-radius: ${themeCssVariables.border.radius.md}; `; const StyledButtonContainer = styled.div` @@ -62,15 +63,15 @@ const StyledButtonContainer = styled.div` const StyledScopeList = styled.ul` list-style: none; padding: 0; - margin: 0 0 ${({ theme }) => theme.spacing(4)} 0; + margin: 0 0 ${themeCssVariables.spacing[4]} 0; width: 100%; `; const StyledScopeItem = styled.li` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; - padding: ${({ theme }) => theme.spacing(1)} 0; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.md}; + padding: ${themeCssVariables.spacing[1]} 0; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; &:last-child { border-bottom: none; @@ -78,10 +79,10 @@ const StyledScopeItem = styled.li` `; const StyledErrorText = styled.div` - color: ${({ theme }) => theme.color.red}; - font-size: ${({ theme }) => theme.font.size.sm}; + color: ${themeCssVariables.color.red}; + font-size: ${themeCssVariables.font.size.sm}; text-align: center; - padding: ${({ theme }) => theme.spacing(2)} 0; + padding: ${themeCssVariables.spacing[2]} 0; width: 100%; `; diff --git a/packages/twenty-front/src/pages/auth/PasswordReset.tsx b/packages/twenty-front/src/pages/auth/PasswordReset.tsx index 3a4e894b68..793db3df69 100644 --- a/packages/twenty-front/src/pages/auth/PasswordReset.tsx +++ b/packages/twenty-front/src/pages/auth/PasswordReset.tsx @@ -13,15 +13,14 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { TextInput } from '@/ui/input/components/TextInput'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { ApolloError } from '@apollo/client'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { zodResolver } from '@hookform/resolvers/zod'; import { msg } from '@lingui/core/macro'; import { i18n } from '@lingui/core'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { motion } from 'framer-motion'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { useParams } from 'react-router-dom'; @@ -29,6 +28,8 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { AppPath } from 'twenty-shared/types'; import { MainButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseIn } from 'twenty-ui/utilities'; import { z } from 'zod'; import { @@ -60,8 +61,8 @@ const StyledMainContainer = styled.div` `; const StyledContentContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(8)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + margin-top: ${themeCssVariables.spacing[4]}; width: 200px; `; @@ -77,11 +78,11 @@ const StyledFullWidthMotionDiv = styled(motion.div)` `; const StyledInputContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(3)}; + margin-bottom: ${themeCssVariables.spacing[3]}; `; const StyledMainButton = styled(MainButton)` - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; export const PasswordReset = () => { @@ -98,7 +99,7 @@ export const PasswordReset = () => { const [isTokenValid, setIsTokenValid] = useState(false); const [isTargetUserPasswordSet, setIsTargetUserPasswordSet] = useState(false); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const passwordResetToken = useParams().passwordResetToken; diff --git a/packages/twenty-front/src/pages/auth/SignInUp.tsx b/packages/twenty-front/src/pages/auth/SignInUp.tsx index e572ad71fb..b34e029d24 100644 --- a/packages/twenty-front/src/pages/auth/SignInUp.tsx +++ b/packages/twenty-front/src/pages/auth/SignInUp.tsx @@ -5,7 +5,7 @@ import { signInUpStepState, } from '@/auth/states/signInUpStepState'; import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; @@ -34,6 +34,7 @@ import { useLingui } from '@lingui/react/macro'; import { useSearchParams } from 'react-router-dom'; import { isDefined } from 'twenty-shared/utils'; import { Loader } from 'twenty-ui/feedback'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseIn } from 'twenty-ui/utilities'; import { type PublicWorkspaceData } from '~/generated-metadata/graphql'; @@ -41,9 +42,9 @@ const StyledLoaderContainer = styled.div` align-items: center; display: flex; justify-content: center; - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; width: 100%; - margin-bottom: ${({ theme }) => theme.spacing(8)}; + margin-bottom: ${themeCssVariables.spacing[8]}; `; const StandardContent = ({ diff --git a/packages/twenty-front/src/pages/not-found/NotFound.tsx b/packages/twenty-front/src/pages/not-found/NotFound.tsx index d68e4603c2..88db9589b5 100644 --- a/packages/twenty-front/src/pages/not-found/NotFound.tsx +++ b/packages/twenty-front/src/pages/not-found/NotFound.tsx @@ -10,8 +10,9 @@ import { AppPath } from 'twenty-shared/types'; import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices'; import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedPlaceholder, AnimatedPlaceholderEmptyTextContainer, @@ -23,8 +24,8 @@ import { UndecoratedLink } from 'twenty-ui/navigation'; const StyledBackDrop = styled.div` align-items: center; - backdrop-filter: ${({ theme }) => theme.blur.light}; - background: ${({ theme }) => theme.background.transparent.secondary}; + backdrop-filter: ${themeCssVariables.blur.light}; + background: ${themeCssVariables.background.transparent.secondary}; display: flex; flex-direction: column; height: 100%; diff --git a/packages/twenty-front/src/pages/onboarding/BookCall.tsx b/packages/twenty-front/src/pages/onboarding/BookCall.tsx index 17d3b540b7..14961ff6df 100644 --- a/packages/twenty-front/src/pages/onboarding/BookCall.tsx +++ b/packages/twenty-front/src/pages/onboarding/BookCall.tsx @@ -1,5 +1,6 @@ import Cal from '@calcom/embed-react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { Link } from 'react-router-dom'; import { currentUserState } from '@/auth/states/currentUserState'; @@ -7,12 +8,13 @@ import { calendarBookingPageIdState } from '@/client-config/states/calendarBooki import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { AppPath } from 'twenty-shared/types'; import { IconChevronLeft, IconChevronRightPipe } from 'twenty-ui/display'; import { LightButton } from 'twenty-ui/input'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useIsMobile } from 'twenty-ui/utilities'; import { OnboardingStatus, @@ -22,7 +24,7 @@ import { const StyledModalFooter = styled(Modal.Footer)` height: auto; justify-content: center; - padding: ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[3]}; `; const StyledModalContent = styled(Modal.Content)` @@ -30,13 +32,9 @@ const StyledModalContent = styled(Modal.Content)` padding: 0; `; -const StyledScrollWrapper = styled(ScrollWrapper)<{ isMobile: boolean }>` - ${({ isMobile }) => !isMobile && 'height: auto;'} -`; - export const BookCall = () => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const calendarBookingPageId = useAtomStateValue(calendarBookingPageIdState); const setNextOnboardingStatus = useSetNextOnboardingStatus(); const currentUser = useAtomStateValue(currentUserState); @@ -54,9 +52,9 @@ export const BookCall = () => { return ( <> - { name: `${currentUser?.firstName} ${currentUser?.lastName}`, }} /> - + {isPlanRequired ? ( diff --git a/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx b/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx index 78ebb06bb1..bb614926b6 100644 --- a/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx +++ b/packages/twenty-front/src/pages/onboarding/BookCallDecision.tsx @@ -2,22 +2,23 @@ import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { Modal } from '@/ui/layout/modal/components/Modal'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { Link } from 'react-router-dom'; import { AppPath } from 'twenty-shared/types'; import { LightButton, MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useSkipBookOnboardingStepMutation } from '~/generated-metadata/graphql'; const StyledCoverImage = styled.img` - border-radius: ${({ theme }) => theme.border.radius.sm}; + border-radius: ${themeCssVariables.border.radius.sm}; height: 204px; object-fit: cover; width: 320px; `; const StyledModalContent = styled(Modal.Content)` - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; `; const StyledTitleContainer = styled.div` @@ -31,7 +32,7 @@ const StyledButtonContainer = styled.div` align-items: center; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; width: 100%; `; diff --git a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx index a9ecdad682..e71dcab80f 100644 --- a/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx +++ b/packages/twenty-front/src/pages/onboarding/ChooseYourPlan.tsx @@ -1,5 +1,5 @@ import { Modal } from '@/ui/layout/modal/components/Modal'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; import { ChooseYourPlanContent } from '~/pages/onboarding/internal/ChooseYourPlanContent'; import { billingState } from '@/client-config/states/billingState'; diff --git a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx index ce64f43ef0..5885f5037d 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useCallback, useState } from 'react'; import { Controller, type SubmitHandler, useForm } from 'react-hook-form'; @@ -27,17 +27,18 @@ import { Trans, useLingui } from '@lingui/react/macro'; import { isDefined } from 'twenty-shared/utils'; import { H2Title } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledContentContainer = styled.div` width: 100%; `; const StyledSectionContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; `; const StyledButtonContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; width: 200px; `; @@ -45,7 +46,7 @@ const StyledComboInputContainer = styled.div` display: flex; flex-direction: row; > * + * { - margin-left: ${({ theme }) => theme.spacing(4)}; + margin-left: ${themeCssVariables.spacing[4]}; } `; diff --git a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx index 5dbf6c87eb..4e9c688f3f 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useCallback, useState } from 'react'; import { Controller, type SubmitHandler, useForm } from 'react-hook-form'; @@ -25,6 +25,7 @@ import { isDefined } from 'twenty-shared/utils'; import { H2Title } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useActivateWorkspaceMutation } from '~/generated-metadata/graphql'; const StyledContentContainer = styled.div` @@ -32,11 +33,11 @@ const StyledContentContainer = styled.div` `; const StyledSectionContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; `; const StyledButtonContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; width: 200px; `; @@ -44,9 +45,9 @@ const StyledLoaderContainer = styled.div` align-items: center; display: flex; justify-content: center; - margin-top: ${({ theme }) => theme.spacing(8)}; + margin-top: ${themeCssVariables.spacing[8]}; width: 100%; - margin-bottom: ${({ theme }) => theme.spacing(8)}; + margin-bottom: ${themeCssVariables.spacing[8]}; `; enum PendingCreationLoaderStep { diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index f87b6fd83e..3a22476cd3 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -8,7 +8,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { TextInput } from '@/ui/input/components/TextInput'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { zodResolver } from '@hookform/resolvers/zod'; import { Trans, useLingui } from '@lingui/react/macro'; import { useCallback } from 'react'; @@ -24,6 +24,7 @@ import { isDefined } from 'twenty-shared/utils'; import { IconCopy, SeparatorLineText } from 'twenty-ui/display'; import { LightButton, MainButton } from 'twenty-ui/input'; import { ClickToActionLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { z } from 'zod'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; import { useCreateWorkspaceInvitation } from '@/workspace-invitation/hooks/useCreateWorkspaceInvitation'; @@ -31,8 +32,8 @@ import { useCreateWorkspaceInvitation } from '@/workspace-invitation/hooks/useCr const StyledAnimatedContainer = styled.div` display: flex; flex-direction: column; - padding: ${({ theme }) => theme.spacing(8)} 0; - gap: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[8]} 0; + gap: ${themeCssVariables.spacing[4]}; overflow-y: scroll; overflow-x: hidden; width: 100%; @@ -50,7 +51,7 @@ const StyledButtonContainer = styled.div` `; const StyledActionSkipLinkContainer = styled.div` - margin: ${({ theme }) => theme.spacing(3)} 0 0; + margin: ${themeCssVariables.spacing[3]} 0 0; `; const validationSchema = z.object({ diff --git a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx index aedac2cfef..62c5dc538d 100644 --- a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx +++ b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx @@ -4,7 +4,7 @@ import { currentUserState } from '@/auth/states/currentUserState'; import { OnboardingModalCircularIcon } from '@/onboarding/components/OnboardingModalCircularIcon'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; @@ -13,12 +13,13 @@ import { isDefined } from 'twenty-shared/utils'; import { IconCheck } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AnimatedEaseIn } from 'twenty-ui/utilities'; import { useGetCurrentUserLazyQuery } from '~/generated-metadata/graphql'; import { useNavigateApp } from '~/hooks/useNavigateApp'; const StyledModalContent = styled(Modal.Content)` - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; `; const StyledTitleContainer = styled.div` diff --git a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx index 3b30d917ee..183f869f4b 100644 --- a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx +++ b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx @@ -1,6 +1,5 @@ -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 { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; import { Key } from 'ts-key-enum'; @@ -23,6 +22,8 @@ import { AppPath, ConnectedAccountProvider } from 'twenty-shared/types'; import { IconGoogle, IconMicrosoft } from 'twenty-ui/display'; import { MainButton } from 'twenty-ui/input'; import { ClickToActionLink } from 'twenty-ui/navigation'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { CalendarChannelVisibility, MessageChannelVisibility, @@ -35,25 +36,25 @@ const StyledSyncEmailsContainer = styled.div` display: flex; flex-direction: row; width: 100%; - margin: ${({ theme }) => theme.spacing(8)} 0; - gap: ${({ theme }) => theme.spacing(2)}; + margin: ${themeCssVariables.spacing[8]} 0; + gap: ${themeCssVariables.spacing[2]}; `; const StyledActionLinkContainer = styled.div` display: flex; flex-direction: row; - margin: ${({ theme }) => theme.spacing(3)} 0 0; - padding-top: ${({ theme }) => theme.spacing(2)}; + margin: ${themeCssVariables.spacing[3]} 0 0; + padding-top: ${themeCssVariables.spacing[2]}; `; const StyledProviderContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; export const SyncEmails = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { triggerApisOAuth } = useTriggerApisOAuth(); const setNextOnboardingStatus = useSetNextOnboardingStatus(); const [visibility, setVisibility] = useState( diff --git a/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx b/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx index 8ac822acb0..eb25ee883c 100644 --- a/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx +++ b/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx @@ -10,7 +10,7 @@ import { useBaseLicensedPriceByPlanKeyAndInterval } from '@/billing/hooks/useBas import { useBaseProductByPlanKey } from '@/billing/hooks/useBaseProductByPlanKey'; import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession'; import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { AppPath } from 'twenty-shared/types'; @@ -19,31 +19,34 @@ import { isDefined } from 'twenty-shared/utils'; import { Loader } from 'twenty-ui/feedback'; import { CardPicker, MainButton } from 'twenty-ui/input'; import { CAL_LINK, ClickToActionLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { BillingPlanKey, type Billing } from '~/generated-metadata/graphql'; const StyledSubscriptionContainer = styled.div<{ withLongerMarginBottom: boolean; }>` - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; flex-direction: column; - margin: ${({ theme }) => theme.spacing(8)} 0 - ${({ theme, withLongerMarginBottom }) => - theme.spacing(withLongerMarginBottom ? 8 : 2)}; + margin: ${themeCssVariables.spacing[8]} 0 + ${({ withLongerMarginBottom }) => + withLongerMarginBottom + ? themeCssVariables.spacing[8] + : themeCssVariables.spacing[2]}; width: 100%; `; const StyledSubscriptionPriceContainer = styled.div` align-items: center; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; display: flex; flex-direction: column; - margin: ${({ theme }) => theme.spacing(4)} ${({ theme }) => theme.spacing(3)} - 0 ${({ theme }) => theme.spacing(4)}; - padding-bottom: ${({ theme }) => theme.spacing(3)}; + margin: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]} 0 + ${themeCssVariables.spacing[4]}; + padding-bottom: ${themeCssVariables.spacing[3]}; `; const StyledBenefitsContainer = styled.div` @@ -52,7 +55,7 @@ const StyledBenefitsContainer = styled.div` flex-direction: column; width: 100%; gap: 16px; - padding: ${({ theme }) => theme.spacing(4)} ${({ theme }) => theme.spacing(3)}; + padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]}; `; const StyledOrganizationBenefitsContainer = styled.div` @@ -61,28 +64,28 @@ const StyledOrganizationBenefitsContainer = styled.div` flex-direction: column; width: 100%; gap: 16px; - padding: ${({ theme }) => theme.spacing(4)} ${({ theme }) => theme.spacing(3)}; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]}; + border-bottom: 1px solid ${themeCssVariables.border.color.light}; `; const StyledChooseTrialContainer = styled.div` display: flex; flex-direction: row; width: 100%; - margin-bottom: ${({ theme }) => theme.spacing(8)}; - gap: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[8]}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledLinkGroup = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; justify-content: center; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-top: ${themeCssVariables.spacing[4]}; > span { - background-color: ${({ theme }) => theme.font.color.light}; + background-color: ${themeCssVariables.font.color.light}; border-radius: 50%; height: 2px; width: 2px; diff --git a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx b/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx index 644753f22c..63f9ca060b 100644 --- a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { FormProvider } from 'react-hook-form'; import QRCode from 'react-qr-code'; @@ -19,24 +19,25 @@ import { H2Title } from 'twenty-ui/display'; import { Loader } from 'twenty-ui/feedback'; import { Section } from 'twenty-ui/layout'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledQRCodeContainer = styled.div` - margin: ${({ theme }) => theme.spacing(4)} 0; + margin: ${themeCssVariables.spacing[4]} 0; display: flex; flex-direction: column; align-items: flex-start; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; const StyledQRCodeWrapper = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; justify-content: center; - padding: ${({ theme }) => theme.spacing(4)}; + padding: ${themeCssVariables.spacing[4]}; `; const StyledOTPContainer = styled.div` @@ -49,8 +50,8 @@ const StyledQRCode = styled(QRCode)` `; const StyledCopySetupKeyText = 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}; text-align: left; line-height: 1.5; `; @@ -58,21 +59,21 @@ const StyledCopySetupKeyText = styled.div` const StyledCopySetupKeyLink = styled.button` background: none; border: none; - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; cursor: pointer; display: inline; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${themeCssVariables.font.size.sm}; padding: 0; text-decoration: underline; margin-left: 0; &:hover { - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; } `; const StyledDivider = styled.div` - margin: ${({ theme }) => theme.spacing(6)} 0; + margin: ${themeCssVariables.spacing[6]} 0; width: 100%; `; diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx index a71e25612a..d1c06a55d5 100644 --- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx +++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminConfigVariableDetails.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { Form, useParams } from 'react-router-dom'; @@ -18,6 +18,7 @@ import { SettingsPath, type ConfigVariableValue } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { H3Title, IconCheck, IconPencil, IconX } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { ConfigSource, useGetDatabaseConfigVariableQuery, @@ -26,18 +27,18 @@ import { const StyledForm = styled(Form)` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; width: 100%; `; const StyledH3Title = styled(H3Title)` - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${themeCssVariables.spacing[2]}; `; const StyledRow = styled.div` display: flex; align-items: flex-end; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledButtonContainer = styled.div` diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx index 77c0c4a2cb..e559393fe7 100644 --- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx +++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx @@ -4,13 +4,14 @@ import { SettingsAdminIndicatorHealthContext } from '@/settings/admin-panel/heal import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useParams } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { H2Title, H3Title } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { AdminPanelHealthServiceStatus, HealthIndicatorId, @@ -20,8 +21,8 @@ import { const StyledTitleContainer = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; - margin-top: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[2]}; `; export const SettingsAdminIndicatorHealthStatus = () => { diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx index 2c1a3985c3..216d9455bf 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAI.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Link } from 'react-router-dom'; import { SettingsOptionCardContentButton } from '@/settings/components/SettingsOptions/SettingsOptionCardContentButton'; diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAIPrompts.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAIPrompts.tsx index 8d52705f64..3d6dd36211 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAIPrompts.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAIPrompts.tsx @@ -1,5 +1,5 @@ import { ApolloError } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useDebouncedCallback } from 'use-debounce'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; @@ -16,6 +16,7 @@ import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { H2Title } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useGetAiSystemPromptPreviewQuery, useUpdateWorkspaceMutation, @@ -24,16 +25,16 @@ import { const StyledFormContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; const StyledTokenBadge = styled.span` - background: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.xs}; - padding: ${({ theme }) => theme.spacing(0.5)} - ${({ theme }) => theme.spacing(1.5)}; + background: ${themeCssVariables.background.transparent.light}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.xs}; + padding: ${themeCssVariables.spacing['0.5']} + ${themeCssVariables.spacing['1.5']}; white-space: nowrap; `; diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx index 66e48e6cbb..61a4b124da 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAgentForm.tsx @@ -1,5 +1,5 @@ import { ApolloError } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useParams } from 'react-router-dom'; import { useDebouncedCallback } from 'use-debounce'; @@ -24,6 +24,7 @@ import { IconSettings, } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type CreateAgentInput, useCreateOneAgentMutation, @@ -49,12 +50,12 @@ const StyledContentContainer = styled.div` display: flex; flex: 1; flex-direction: column; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; width: 100%; `; const StyledTabList = styled(TabList)` - margin-bottom: ${({ theme }) => theme.spacing(8)}; + margin-bottom: ${themeCssVariables.spacing[8]}; `; export const SettingsAgentForm = ({ mode }: { mode: 'create' | 'edit' }) => { diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx index 47fb180871..20ea8dd829 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsAgentTurnDetail.tsx @@ -7,7 +7,7 @@ import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useQuery } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import Skeleton from 'react-loading-skeleton'; import { useParams } from 'react-router-dom'; @@ -15,15 +15,16 @@ import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { H2Title, Status } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { GET_AGENT_TURNS } from '@/ai/graphql/queries/getAgentTurns'; const StyledTable = styled(Table)` - margin-top: ${({ theme }) => theme.spacing(3)}; + margin-top: ${themeCssVariables.spacing[3]}; `; const StyledTableHeaderRow = styled(TableRow)` grid-template-columns: 140px 80px 1fr; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledTableRow = styled(TableRow)` @@ -31,12 +32,12 @@ const StyledTableRow = styled(TableRow)` `; const StyledDateCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledScoreCell = styled(TableCell)` align-items: center; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledCommentCell = styled(TableCell)` @@ -48,24 +49,24 @@ const StyledCommentCell = styled(TableCell)` const StyledMessagesContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; const StyledMessageBubble = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledMessageRole = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; text-transform: uppercase; `; const StyledMessageContent = styled.div` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; max-width: 100%; `; diff --git a/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx b/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx index a744571e1c..a8f7ef7998 100644 --- a/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx +++ b/packages/twenty-front/src/pages/settings/ai/SettingsSkillForm.tsx @@ -1,5 +1,5 @@ import { ApolloError } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useParams } from 'react-router-dom'; import { useDebouncedCallback } from 'use-debounce'; @@ -14,7 +14,6 @@ import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { TextArea } from '@/ui/input/components/TextArea'; import { TitleInput } from '@/ui/input/components/TitleInput'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; -import { useTheme } from '@emotion/react'; import { t } from '@lingui/core/macro'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; @@ -30,6 +29,8 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Card, Section } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useActivateSkillMutation, useCreateSkillMutation, @@ -45,20 +46,20 @@ import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import Skeleton from 'react-loading-skeleton'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; const StyledFormContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; const StyledIconNameRow = styled.div` align-items: flex-start; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledNameContainer = styled.div` @@ -66,30 +67,30 @@ const StyledNameContainer = styled.div` `; const StyledAdvancedSettingsOuterContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(4)}; + padding-top: ${themeCssVariables.spacing[4]}; `; const StyledAdvancedSettingsContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; width: 100%; `; const StyledHeaderTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - font-size: ${({ theme }) => theme.font.size.lg}; + color: ${themeCssVariables.font.color.primary}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + font-size: ${themeCssVariables.font.size.lg}; width: fit-content; max-width: 420px; & > input:disabled { - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; } `; const StyledDangerButtonsContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; type SkillFormValues = { @@ -108,7 +109,7 @@ export const SettingsSkillForm = ({ mode }: { mode: 'create' | 'edit' }) => { const navigate = useNavigateSettings(); const navigateApp = useNavigateApp(); const { enqueueErrorSnackBar } = useSnackBar(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [isSubmitting, setIsSubmitting] = useState(false); const [isReadonlyMode, setIsReadonlyMode] = useState(false); const [originalFormValues, setOriginalFormValues] = diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentTableRow.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentTableRow.tsx index d4bc645549..d00ffc93c0 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentTableRow.tsx @@ -1,11 +1,12 @@ -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 { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { OverflowingTextWithTooltip, useIcons } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type Agent } from '~/generated-metadata/graphql'; export type SettingsAIAgentTableRowProps = { @@ -19,20 +20,20 @@ export const StyledAIAgentTableRow = styled(TableRow)` `; const StyledNameTableCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; overflow: hidden; `; const StyledActionTableCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; const StyledIconContainer = styled.div` flex-shrink: 0; - height: ${({ theme }) => theme.spacing(4)}; + height: ${themeCssVariables.spacing[4]}; `; export const SettingsAIAgentTableRow = ({ @@ -40,7 +41,7 @@ export const SettingsAIAgentTableRow = ({ agent, link, }: SettingsAIAgentTableRowProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const Icon = getIcon(agent.icon || 'IconRobot'); diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentsTable.tsx index 3268eb0433..70712adb33 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentsTable.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIAgentsTable.tsx @@ -1,6 +1,6 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; @@ -10,7 +10,6 @@ import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableH import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; -import { useTheme } from '@emotion/react'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { @@ -21,6 +20,8 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { MenuItemToggle } from 'twenty-ui/navigation'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { SETTINGS_AI_AGENT_TABLE_METADATA } from '~/pages/settings/ai/constants/SettingsAiAgentTableMetadata'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; @@ -33,8 +34,8 @@ import { const StyledSearchAndFilterContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[2]}; width: 100%; `; @@ -43,18 +44,18 @@ const StyledSearchInput = styled(SettingsTextInput)` `; const StyledTable = styled(Table)` - margin-top: ${({ theme }) => theme.spacing(3)}; + margin-top: ${themeCssVariables.spacing[3]}; `; const StyledTableHeaderRow = styled(StyledAIAgentTableRow)` - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; export const SettingsAIAgentsTable = () => { const { data, loading } = useFindManyAgentsQuery(); const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [searchTerm, setSearchTerm] = useState(''); const [showWorkflowAgents, setShowWorkflowAgents] = useState(false); diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIMCP.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIMCP.tsx index 84131ef4a6..23baf8c142 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIMCP.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIMCP.tsx @@ -1,21 +1,22 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { H2Title, IconCopy } from 'twenty-ui/display'; import { Button, CodeEditor } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledWrapper = styled.div` - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.light}; + border-radius: ${themeCssVariables.border.radius.md}; `; const StyledCopyButton = styled.div` position: absolute; - top: ${({ theme }) => theme.spacing(3)}; - right: ${({ theme }) => theme.spacing(3)}; + top: ${themeCssVariables.spacing[3]}; + right: ${themeCssVariables.spacing[3]}; z-index: 1; `; diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx index 327cfe36c0..d8d68593cc 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { DEFAULT_FAST_MODEL } from '@/ai/constants/DefaultFastModel'; import { DEFAULT_SMART_MODEL } from '@/ai/constants/DefaultSmartModel'; @@ -23,12 +23,13 @@ import { IconTwentyStar, } from 'twenty-ui/display'; import { Card, Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useUpdateWorkspaceMutation } from '~/generated-metadata/graphql'; import { getModelIcon } from '~/pages/settings/ai/utils/getModelIcon'; import { getModelProviderLabel } from '~/pages/settings/ai/utils/getModelProviderLabel'; const StyledSearchContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSearchInput = styled(SettingsTextInput)` diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentDetailSkeletonLoader.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentDetailSkeletonLoader.tsx index c5ae6554b8..71d4ea529c 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentDetailSkeletonLoader.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentDetailSkeletonLoader.tsx @@ -1,25 +1,27 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSkeletonContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; `; const StyledFormSection = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledIconNameRow = styled.div` align-items: flex-start; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledIconContainer = styled.div` @@ -31,7 +33,7 @@ const StyledNameContainer = styled.div` `; export const SettingsAgentDetailSkeletonLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(6)}; - margin-top: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[6]}; + margin-top: ${themeCssVariables.spacing[4]}; `; const StyledEmptyMessage = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; type SettingsAgentEvalsTabProps = { diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentLogsTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentLogsTab.tsx index 507dd120e6..78b76875fe 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentLogsTab.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentLogsTab.tsx @@ -3,7 +3,7 @@ import { Table } from '@/ui/layout/table/components/Table'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; import Skeleton from 'react-loading-skeleton'; @@ -19,18 +19,19 @@ import { AnimatedPlaceholderEmptyTitle, } from 'twenty-ui/layout'; import { UndecoratedLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useEvaluateAgentTurnMutation, useGetAgentTurnsQuery, } from '~/generated-metadata/graphql'; const StyledTable = styled(Table)` - margin-top: ${({ theme }) => theme.spacing(3)}; + margin-top: ${themeCssVariables.spacing[3]}; `; const StyledTableHeaderRow = styled(TableRow)` grid-template-columns: 140px 80px 1fr 40px; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledTableRow = styled(TableRow)` @@ -39,11 +40,11 @@ const StyledTableRow = styled(TableRow)` const StyledScoreCell = styled(TableCell)` align-items: center; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledDateCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledInputCell = styled(TableCell)` @@ -54,7 +55,7 @@ const StyledInputCell = styled(TableCell)` const StyledActionCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; type SettingsAgentLogsTabProps = { diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentModelCapabilities.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentModelCapabilities.tsx index cb9c1462e1..343c7f60c5 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentModelCapabilities.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentModelCapabilities.tsx @@ -1,5 +1,5 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import { aiModelsState } from '@/client-config/states/aiModelsState'; import { InputLabel } from '@/ui/input/components/InputLabel'; @@ -9,27 +9,31 @@ import { IconBrandX, IconWorld } from 'twenty-ui/display'; import { Checkbox } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledCheckboxContainer = styled.div<{ disabled: boolean }>` display: flex; align-items: center; justify-content: space-between; - padding: ${({ theme }) => theme.spacing(1)}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + padding: ${themeCssVariables.spacing[1]}; + border-radius: ${themeCssVariables.border.radius.sm}; transition: background-color - ${({ theme }) => theme.animation.duration.normal}s ease; + calc(${themeCssVariables.animation.duration.normal} * 1s) ease; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; &:hover { - background-color: ${({ theme, disabled }) => - disabled ? 'transparent' : theme.background.transparent.light}; + background-color: ${({ disabled }) => + disabled + ? 'transparent' + : themeCssVariables.background.transparent.light}; } `; const StyledCheckboxLabel = styled.div` display: flex; align-items: center; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; type ModelConfiguration = { @@ -56,7 +60,7 @@ export const SettingsAgentModelCapabilities = ({ onConfigurationChange, disabled = false, }: SettingsAgentModelCapabilitiesProps) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const aiModels = useAtomStateValue(aiModelsState); const selectedModel = aiModels.find((m) => m.modelId === selectedModelId); diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentResponseFormat.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentResponseFormat.tsx index d8be740149..508c67bd6b 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentResponseFormat.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentResponseFormat.tsx @@ -1,7 +1,7 @@ import { type OutputSchemaField } from '@/ai/constants/OutputFieldTypeOptions'; import { Select } from '@/ui/input/components/Select'; import { WorkflowOutputSchemaBuilder } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowOutputSchemaBuilder'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; import { @@ -9,11 +9,12 @@ import { type AgentResponseSchema, } from 'twenty-shared/ai'; 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]}; `; type SettingsAgentResponseFormatProps = { diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx index 5665c50864..381475b3d3 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentRoleTab.tsx @@ -1,5 +1,5 @@ import { getOperationName } from '@apollo/client/utilities'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { v4 } from 'uuid'; @@ -13,6 +13,7 @@ import { isDefined } from 'twenty-shared/utils'; import { H2Title, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAssignRoleToAgentMutation, useCreateOneRoleMutation, @@ -21,9 +22,9 @@ import { import { type SettingsAIAgentFormValues } from '~/pages/settings/ai/hooks/useSettingsAgentFormState'; const StyledWarningText = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-bottom: ${({ theme }) => theme.spacing(4)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; type SettingsAgentRoleTabProps = { diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentSettingsTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentSettingsTab.tsx index fc2f6f3ea9..f183f32eb3 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentSettingsTab.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAgentSettingsTab.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { @@ -15,6 +15,7 @@ import { isDefined } from 'twenty-shared/utils'; import { H2Title, IconTrash } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type Agent } from '~/generated-metadata/graphql'; import { SettingsAgentDeleteConfirmationModal } from '~/pages/settings/ai/components/SettingsAgentDeleteConfirmationModal'; import { SettingsAgentResponseFormat } from '~/pages/settings/ai/components/SettingsAgentResponseFormat'; @@ -26,13 +27,13 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState const StyledFormContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledIconNameRow = styled.div` align-items: flex-start; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledNameContainer = styled.div` @@ -40,9 +41,9 @@ const StyledNameContainer = styled.div` `; const StyledErrorMessage = styled.div` - color: ${({ theme }) => theme.color.red}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-top: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.color.red}; + font-size: ${themeCssVariables.font.size.sm}; + margin-top: ${themeCssVariables.spacing[1]}; `; const DELETE_AGENT_MODAL_ID = 'delete-agent-modal'; diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx index 5565ef6813..c4629bd908 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useIcons, OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type Skill } from '~/generated-metadata/graphql'; @@ -14,14 +15,13 @@ export type SettingsSkillTableRowProps = { link?: string; }; -export const StyledSkillTableRow = styled(TableRow)<{ isActive?: boolean }>` +export const StyledSkillTableRow = styled(TableRow)` grid-template-columns: 1fr 120px 36px; - opacity: ${({ isActive = true }) => (isActive ? 1 : 0.5)}; `; const StyledNameTableCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; overflow: hidden; `; @@ -34,7 +34,7 @@ const StyledIconContainer = styled.div` const StyledActionTableCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; export const SettingsSkillTableRow = ({ @@ -46,7 +46,11 @@ export const SettingsSkillTableRow = ({ const Icon = getIcon(skill.icon ?? 'IconSparkles'); return ( - + diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx index a3aa01dc14..6138864930 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx @@ -1,6 +1,6 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useMemo, useState } from 'react'; +import { useContext, useMemo, useState } from 'react'; import Skeleton from 'react-loading-skeleton'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -12,7 +12,6 @@ import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableH import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; -import { useTheme } from '@emotion/react'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { @@ -24,6 +23,8 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { MenuItemToggle, UndecoratedLink } from 'twenty-ui/navigation'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useActivateSkillMutation, @@ -40,9 +41,9 @@ import { const StyledSearchAndFilterContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; align-items: center; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSearchInput = styled(SettingsTextInput)` @@ -51,14 +52,14 @@ const StyledSearchInput = styled(SettingsTextInput)` `; const StyledTableHeaderRow = styled(StyledSkillTableRow)` - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledFooterContainer = styled.div` align-items: center; display: flex; justify-content: flex-end; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-top: ${themeCssVariables.spacing[4]}; `; export const SettingsSkillsTable = () => { @@ -67,7 +68,7 @@ export const SettingsSkillsTable = () => { const [deleteSkill] = useDeleteSkillMutation(); const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); const [searchTerm, setSearchTerm] = useState(''); const [showDeactivated, setShowDeactivated] = useState(true); diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsSystemToolTableRow.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsSystemToolTableRow.tsx index 377d729677..db23666a39 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsSystemToolTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsSystemToolTableRow.tsx @@ -1,5 +1,5 @@ import { useLazyQuery } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useState } from 'react'; @@ -20,6 +20,7 @@ import { } from 'twenty-ui/display'; import { JsonTree } from 'twenty-ui/json-visualizer'; import { AnimatedExpandableContainer } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type JsonValue } from 'type-fest'; @@ -40,21 +41,18 @@ export type SettingsSystemToolTableRowProps = { tool: SystemTool; }; -export const StyledSystemToolTableRow = styled(TableRow)<{ - isExpandable?: boolean; -}>` +export const StyledSystemToolTableRow = styled(TableRow)` grid-template-columns: 1fr 100px 36px; opacity: 0.7; - cursor: ${({ isExpandable }) => (isExpandable ? 'pointer' : 'default')}; - &:hover { - opacity: ${({ isExpandable }) => (isExpandable ? 0.85 : 0.7)}; + &[data-clickable='true']:hover { + opacity: 0.85; } `; const StyledNameTableCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; overflow: hidden; `; @@ -67,26 +65,26 @@ const StyledIconContainer = styled.div` const StyledActionTableCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; const StyledExpandableContent = styled.div` - background-color: ${({ theme }) => theme.background.secondary}; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; - padding: ${({ theme }) => theme.spacing(4)}; + background-color: ${themeCssVariables.background.secondary}; + border-top: 1px solid ${themeCssVariables.border.color.light}; + padding: ${themeCssVariables.spacing[4]}; `; const StyledSectionTitle = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.medium}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledDescription = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-bottom: ${({ theme }) => theme.spacing(4)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; const getCategoryIcon = (category: string) => { @@ -110,7 +108,6 @@ export const SettingsSystemToolTableRow = ({ const [isExpanded, setIsExpanded] = useState(false); const { copyToClipboard } = useCopyToClipboard(); - // Fetch inputSchema for this specific tool on first expand const [fetchSchema, { data: schemaData, loading: schemaLoading }] = useLazyQuery(GET_TOOL_INPUT_SCHEMA, { variables: { toolName: tool.name }, @@ -135,7 +132,7 @@ export const SettingsSystemToolTableRow = ({ diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolTableRow.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolTableRow.tsx index 09cd5b048f..9e03ae886d 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolTableRow.tsx @@ -1,10 +1,11 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { IconCode, OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type LogicFunction } from '~/generated-metadata/graphql'; @@ -23,8 +24,8 @@ export const StyledToolTableRow = styled(TableRow)` `; const StyledNameTableCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; overflow: hidden; `; @@ -37,7 +38,7 @@ const StyledIconContainer = styled.div` const StyledActionTableCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; export const SettingsToolTableRow = ({ diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx index 9546945cff..9779f26073 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx @@ -1,6 +1,6 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useMemo, useState } from 'react'; +import { useContext, useMemo, useState } from 'react'; import Skeleton from 'react-loading-skeleton'; import { useGetToolIndex } from '@/ai/hooks/useGetToolIndex'; @@ -11,7 +11,6 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; -import { useTheme } from '@emotion/react'; import { useNavigate } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; @@ -23,6 +22,8 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; import { SettingsSystemToolTableRow } from './SettingsSystemToolTableRow'; @@ -33,9 +34,9 @@ import { const StyledSearchAndFilterContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; align-items: center; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSearchInput = styled(SettingsTextInput)` @@ -44,14 +45,14 @@ const StyledSearchInput = styled(SettingsTextInput)` `; const StyledTableHeaderRow = styled(StyledToolTableRow)` - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledFooterContainer = styled.div` align-items: center; display: flex; justify-content: flex-end; - margin-top: ${({ theme }) => theme.spacing(4)}; + margin-top: ${themeCssVariables.spacing[4]}; `; export const SettingsToolsTable = () => { @@ -60,14 +61,13 @@ export const SettingsToolsTable = () => { const { createLogicFunction } = usePersistLogicFunction(); const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const navigate = useNavigate(); const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); const [customSearchTerm, setCustomSearchTerm] = useState(''); const [builtInSearchTerm, setBuiltInSearchTerm] = useState(''); const [isCreating, setIsCreating] = useState(false); - // Filter to only show logic functions that are marked as tools const tools = useMemo( () => logicFunctions.filter((fn) => fn.isTool === true), [logicFunctions], @@ -88,7 +88,6 @@ export const SettingsToolsTable = () => { [tools, customSearchTerm], ); - // System tools from the tool index (excluding logic function tools which are shown separately) const systemTools = useMemo( () => toolIndex.filter( @@ -128,8 +127,6 @@ export const SettingsToolsTable = () => { const newLogicFunction = result.response.data.createOneLogicFunction; enqueueSuccessSnackBar({ message: t`Tool created` }); - // Navigate to the logic function detail page - // The applicationId might be null for workspace-level functions const applicationId = (newLogicFunction as { applicationId?: string }) .applicationId; if (isDefined(applicationId)) { diff --git a/packages/twenty-front/src/pages/settings/ai/forms/components/SettingsAIAgentForm.tsx b/packages/twenty-front/src/pages/settings/ai/forms/components/SettingsAIAgentForm.tsx index f13ad5aec9..322e607c0b 100644 --- a/packages/twenty-front/src/pages/settings/ai/forms/components/SettingsAIAgentForm.tsx +++ b/packages/twenty-front/src/pages/settings/ai/forms/components/SettingsAIAgentForm.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useAiModelOptions } from '@/ai/hooks/useAiModelOptions'; @@ -7,6 +7,7 @@ import { Select } from '@/ui/input/components/Select'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { TextArea } from '@/ui/input/components/TextArea'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/computeMetadataNameFromLabel'; import { SettingsAgentModelCapabilities } from '~/pages/settings/ai/components/SettingsAgentModelCapabilities'; import { type SettingsAIAgentFormValues } from '~/pages/settings/ai/hooks/useSettingsAgentFormState'; @@ -14,13 +15,13 @@ import { type SettingsAIAgentFormValues } from '~/pages/settings/ai/hooks/useSet const StyledFormContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledIconNameRow = styled.div` align-items: flex-start; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; const StyledNameContainer = styled.div` @@ -28,9 +29,9 @@ const StyledNameContainer = styled.div` `; const StyledErrorMessage = styled.div` - color: ${({ theme }) => theme.color.red}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-top: ${({ theme }) => theme.spacing(1)}; + color: ${themeCssVariables.color.red}; + font-size: ${themeCssVariables.font.size.sm}; + margin-top: ${themeCssVariables.spacing[1]}; `; type SettingsAIAgentFormProps = { diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx index 11fa16e105..4c63623c06 100644 --- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx +++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx @@ -17,7 +17,7 @@ import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; import { useMutation, useQuery } from '@apollo/client'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { useState } from 'react'; @@ -42,6 +42,7 @@ import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { applicationRegistrationClientSecretFamilyState } from '~/pages/settings/applications/states/applicationRegistrationClientSecretFamilyState'; const DELETE_REGISTRATION_MODAL_ID = 'delete-application-registration-modal'; @@ -51,51 +52,51 @@ const StyledInputContainer = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; width: 100%; `; const StyledRedirectUriRow = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(1)} 0; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[1]} 0; `; const StyledRedirectUriValue = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; font-family: monospace; word-break: break-all; `; const StyledVariableRow = 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(2)}; - padding: ${({ theme }) => theme.spacing(2)} 0; + gap: ${themeCssVariables.spacing[2]}; + padding: ${themeCssVariables.spacing[2]} 0; `; const StyledVariableInfo = styled.div` flex: 1; display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(0.5)}; + gap: ${themeCssVariables.spacing['0.5']}; `; const StyledVariableKey = styled.span` - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; font-family: monospace; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledVariableDescription = 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}; `; const StyledRotateContainer = styled.div` - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; `; type ServerVariable = { diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx index dd5bd8df4b..038c0d9f89 100644 --- a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx +++ b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx @@ -5,7 +5,7 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa import { TabList } from '@/ui/layout/tab-list/components/TabList'; 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 { t } from '@lingui/core/macro'; import { useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; @@ -26,6 +26,7 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { PermissionFlagType } from '~/generated-metadata/graphql'; import { useMarketplaceApps } from '~/pages/settings/applications/hooks/useMarketplaceApps'; import { SettingsApplicationPermissionsTab } from '~/pages/settings/applications/tabs/SettingsApplicationPermissionsTab'; @@ -36,21 +37,21 @@ const AVAILABLE_APPLICATION_DETAIL_ID = 'available-application-detail'; const StyledHeader = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; justify-content: space-between; - margin-bottom: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; `; const StyledHeaderLeft = styled.div` align-items: center; display: flex; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; `; const StyledLogo = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.tertiary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + background-color: ${themeCssVariables.background.tertiary}; + border-radius: ${themeCssVariables.border.radius.sm}; display: flex; flex-shrink: 0; height: 48px; @@ -67,12 +68,12 @@ const StyledLogoImage = styled.img` const StyledLogoPlaceholder = styled.div` align-items: center; - background-color: ${({ theme }) => theme.color.blue}; - border-radius: ${({ theme }) => theme.border.radius.xs}; - color: ${({ theme }) => theme.font.color.inverted}; + background-color: ${themeCssVariables.color.blue}; + border-radius: ${themeCssVariables.border.radius.xs}; + color: ${themeCssVariables.font.color.inverted}; display: flex; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.medium}; height: 32px; justify-content: center; width: 32px; @@ -81,23 +82,23 @@ const StyledLogoPlaceholder = styled.div` const StyledHeaderInfo = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(1)}; + gap: ${themeCssVariables.spacing[1]}; `; const StyledAppName = styled.div` - 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}; `; const StyledAppDescription = styled.div` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.md}; `; const StyledContentContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; `; const StyledMainContent = styled.div` @@ -111,7 +112,7 @@ const StyledSidebar = styled.div` `; const StyledSidebarSection = styled.div` - padding: ${({ theme }) => theme.spacing(3)} 0; + padding: ${themeCssVariables.spacing[3]} 0; &:first-of-type { padding-top: 0; @@ -119,24 +120,24 @@ const StyledSidebarSection = styled.div` `; const StyledSidebarLabel = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.tertiary}; + font-size: ${themeCssVariables.font.size.sm}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSidebarValue = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.md}; + font-weight: ${themeCssVariables.font.weight.medium}; `; const StyledContentItem = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - font-size: ${({ theme }) => theme.font.size.sm}; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + font-size: ${themeCssVariables.font.size.sm}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[2]}; &:last-of-type { margin-bottom: 0; @@ -145,11 +146,11 @@ const StyledContentItem = styled.div` const StyledLink = styled.a` align-items: center; - color: ${({ theme }) => theme.font.color.primary}; + color: ${themeCssVariables.font.color.primary}; display: flex; - font-size: ${({ theme }) => theme.font.size.sm}; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(2)}; + font-size: ${themeCssVariables.font.size.sm}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[2]}; text-decoration: none; &:hover { @@ -163,13 +164,13 @@ const StyledLink = styled.a` const StyledScreenshotsContainer = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; + background-color: ${themeCssVariables.background.secondary}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.md}; display: flex; height: 300px; justify-content: center; - margin-bottom: ${({ theme }) => theme.spacing(4)}; + margin-bottom: ${themeCssVariables.spacing[4]}; overflow: hidden; `; @@ -181,17 +182,19 @@ const StyledScreenshotImage = styled.img` const StyledScreenshotThumbnails = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(6)}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[6]}; `; const StyledThumbnail = styled.div<{ isSelected?: boolean }>` align-items: center; - background-color: ${({ theme }) => theme.background.secondary}; + background-color: ${themeCssVariables.background.secondary}; border: 1px solid - ${({ theme, isSelected }) => - isSelected ? theme.color.blue : theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + ${({ isSelected }) => + isSelected + ? themeCssVariables.color.blue + : themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.sm}; cursor: pointer; display: flex; flex: 1; @@ -200,7 +203,7 @@ const StyledThumbnail = styled.div<{ isSelected?: boolean }>` overflow: hidden; &:hover { - border-color: ${({ theme }) => theme.color.blue}; + border-color: ${themeCssVariables.color.blue}; } `; @@ -211,30 +214,30 @@ const StyledThumbnailImage = styled.img` `; const StyledSectionTitle = styled.h2` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.lg}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin: 0 0 ${({ theme }) => theme.spacing(3)} 0; + color: ${themeCssVariables.font.color.primary}; + font-size: ${themeCssVariables.font.size.lg}; + font-weight: ${themeCssVariables.font.weight.semiBold}; + margin: 0 0 ${themeCssVariables.spacing[3]} 0; `; const StyledAboutText = styled.p` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.md}; line-height: 1.6; - margin: 0 0 ${({ theme }) => theme.spacing(6)} 0; + margin: 0 0 ${themeCssVariables.spacing[6]} 0; white-space: pre-line; `; const StyledProvidersList = styled.ul` - color: ${({ theme }) => theme.font.color.secondary}; - font-size: ${({ theme }) => theme.font.size.md}; + color: ${themeCssVariables.font.color.secondary}; + font-size: ${themeCssVariables.font.size.md}; list-style-type: disc; margin: 0; - padding-left: ${({ theme }) => theme.spacing(5)}; + padding-left: ${themeCssVariables.spacing[5]}; `; const StyledProviderItem = styled.li` - margin-bottom: ${({ theme }) => theme.spacing(1)}; + margin-bottom: ${themeCssVariables.spacing[1]}; `; export const SettingsAvailableApplicationDetails = () => { diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTable.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTable.tsx index cf9c77fcdb..a46c7247e1 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTable.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTable.tsx @@ -3,12 +3,13 @@ import { Table } from '@/ui/layout/table/components/Table'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { TableSection } from '@/ui/layout/table/components/TableSection'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { useMemo, useState } from 'react'; import { H2Title } from 'twenty-ui/display'; import { SearchInput } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { SettingsApplicationDataTableRow } from '~/pages/settings/applications/components/SettingsApplicationDataTableRow'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; @@ -40,12 +41,12 @@ const StyledEmptyHeader = styled(TableHeader)` `; const StyledSearchInputContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledEmptyState = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - padding: ${({ theme }) => theme.spacing(8)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: ${themeCssVariables.spacing[8]}; text-align: center; `; diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTableRow.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTableRow.tsx index 7f27781d5c..3cf5cb217b 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDataTableRow.tsx @@ -9,11 +9,13 @@ import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { TableSubRow } from '@/ui/layout/table/components/TableSubRow'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; +import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronDown, IconChevronRight, useIcons } from 'twenty-ui/display'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type ApplicationDataTableRow } from '~/pages/settings/applications/components/SettingsApplicationDataTable'; @@ -21,11 +23,11 @@ const MAIN_ROW_GRID_COLUMNS = '180px 1fr 98.7px 36px'; const FIELD_SUB_ROW_GRID_COLUMNS = '180px 1fr'; const StyledFieldDivider = styled.div` - border-top: 1px solid ${({ theme }) => theme.border.color.light}; + border-top: 1px solid ${themeCssVariables.border.color.light}; `; const StyledFieldNameTableCell = styled(StyledNameTableCell)` - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; `; export const SettingsApplicationDataTableRow = ({ @@ -37,7 +39,7 @@ export const SettingsApplicationDataTableRow = ({ isExpanded: boolean; onToggle: () => void; }) => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { getIcon } = useIcons(); const Icon = getIcon(row.icon); diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDetailSkeletonLoader.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDetailSkeletonLoader.tsx index 37299b8bad..5cb2cc84b4 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDetailSkeletonLoader.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationDetailSkeletonLoader.tsx @@ -1,23 +1,25 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +import { useContext } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSkeletonContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(8)}; + gap: ${themeCssVariables.spacing[8]}; `; const StyledFormSection = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const SettingsApplicationDetailSkeletonLoader = () => { - const theme = useTheme(); + const { theme } = useContext(ThemeContext); return ( theme.font.color.primary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.primary}; + gap: ${themeCssVariables.spacing[2]}; `; export const SettingsApplicationNameDescriptionTable = ({ diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationTableRow.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationTableRow.tsx index 1784e192a6..9cc37c8b98 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationTableRow.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationTableRow.tsx @@ -1,9 +1,10 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type ApplicationWithoutRelation } from '~/pages/settings/applications/types/applicationWithoutRelation'; export type SettingsApplicationTableRowProps = { @@ -17,15 +18,15 @@ export const StyledApplicationTableRow = styled(TableRow)` `; const StyledNameTableCell = styled(TableCell)` - color: ${({ theme }) => theme.font.color.secondary}; - gap: ${({ theme }) => theme.spacing(2)}; + color: ${themeCssVariables.font.color.secondary}; + gap: ${themeCssVariables.spacing[2]}; min-width: 0; overflow: hidden; `; const StyledActionTableCell = styled(TableCell)` justify-content: flex-end; - padding-right: ${({ theme }) => theme.spacing(2)}; + padding-right: ${themeCssVariables.spacing[2]}; `; export const SettingsApplicationTableRow = ({ diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationsTable.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationsTable.tsx index 09c6a106d7..850f5c5d07 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationsTable.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsApplicationsTable.tsx @@ -4,27 +4,28 @@ import { getSettingsPath } from 'twenty-shared/utils'; import { SettingsPath } from 'twenty-shared/types'; import { useLingui } from '@lingui/react/macro'; import { Table } from '@/ui/layout/table/components/Table'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { SettingsApplicationTableRow, StyledApplicationTableRow, } from '~/pages/settings/applications/components/SettingsApplicationTableRow'; -import { useTheme } from '@emotion/react'; +import { useContext, useMemo, useState } from 'react'; import { type ApplicationWithoutRelation } from '~/pages/settings/applications/types/applicationWithoutRelation'; import { Section } from 'twenty-ui/layout'; import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; -import { useMemo, useState } from 'react'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledTable = styled(Table)` - margin-top: ${({ theme }) => theme.spacing(3)}; + margin-top: ${themeCssVariables.spacing[3]}; `; const StyledTableHeaderRow = styled(StyledApplicationTableRow)` - margin-bottom: ${({ theme }) => theme.spacing(2)}; + margin-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSearchInput = styled(SettingsTextInput)` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; width: 100%; `; @@ -35,7 +36,7 @@ export const SettingsApplicationsTable = ({ }) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const [searchTerm, setSearchTerm] = useState(''); diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsAvailableApplicationCard.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsAvailableApplicationCard.tsx index 1d2afae07d..120882c517 100644 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsAvailableApplicationCard.tsx +++ b/packages/twenty-front/src/pages/settings/applications/components/SettingsAvailableApplicationCard.tsx @@ -4,7 +4,7 @@ import { StyledSettingsCardThirdLine, StyledSettingsCardTitle, } from '@/settings/components/SettingsOptions/SettingsCardContentBase'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; import { Link } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationCustomTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationCustomTab.tsx index 26d121c413..122b30dce8 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationCustomTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationCustomTab.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Suspense, lazy } from 'react'; const FrontComponentRenderer = lazy(() => diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationDetailEnvironmentVariablesTable.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationDetailEnvironmentVariablesTable.tsx index 9d522b2131..91b63ebb53 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationDetailEnvironmentVariablesTable.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationDetailEnvironmentVariablesTable.tsx @@ -5,12 +5,13 @@ import { Section } from 'twenty-ui/layout'; import { TextInput } from '@/ui/input/components/TextInput'; import { useDebouncedCallback } from 'use-debounce'; import { useState } from 'react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; +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]}; `; export const SettingsApplicationDetailEnvironmentVariablesTable = ({ diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx index e91d43d8bc..7b79a7c68b 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx @@ -1,18 +1,19 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useMemo, useState } from 'react'; import { SearchInput } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { SettingsAvailableApplicationCard } from '~/pages/settings/applications/components/SettingsAvailableApplicationCard'; import { useMarketplaceApps } from '~/pages/settings/applications/hooks/useMarketplaceApps'; const StyledSearchInputContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledCardsGrid = styled.div` display: grid; - gap: ${({ theme }) => theme.spacing(3)}; + gap: ${themeCssVariables.spacing[3]}; grid-template-columns: repeat(2, minmax(0, 1fr)); @media (max-width: 800px) { @@ -21,8 +22,8 @@ const StyledCardsGrid = styled.div` `; const StyledEmptyState = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - padding: ${({ theme }) => theme.spacing(4)}; + color: ${themeCssVariables.font.color.tertiary}; + padding: ${themeCssVariables.spacing[4]}; text-align: center; `; diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx index 4d031443fc..38d299b9f7 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx @@ -3,10 +3,10 @@ import { FIND_MANY_APPLICATION_REGISTRATIONS } from '@/settings/application-regi import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; -import { useTheme } from '@emotion/react'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { useQuery } from '@apollo/client'; +import { useContext } from 'react'; import { useNavigate } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; @@ -20,10 +20,12 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; const StyledButtonContainer = styled.div` - margin: ${({ theme }) => theme.spacing(2)} 0; + margin: ${themeCssVariables.spacing[2]} 0; `; type ApplicationRegistration = { @@ -35,7 +37,7 @@ type ApplicationRegistration = { export const SettingsApplicationsDeveloperTab = () => { const { t } = useLingui(); const navigate = useNavigate(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); const { copyToClipboard } = useCopyToClipboard(); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx index 34c310f9e2..9f78114d83 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; @@ -12,13 +12,12 @@ import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/st import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useTheme } from '@emotion/react'; import { useLingui } from '@lingui/react/macro'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { @@ -30,6 +29,7 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { UndecoratedLink } from 'twenty-ui/navigation'; +import { ThemeContext } from 'twenty-ui/theme'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { useNavigateApp } from '~/hooks/useNavigateApp'; import { SETTINGS_OBJECT_DETAIL_TABS } from '~/pages/settings/data-model/constants/SettingsObjectDetailTabs'; @@ -44,7 +44,7 @@ const StyledContentContainer = styled.div` export const SettingsObjectDetailPage = () => { const navigateApp = useNavigateApp(); const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const { objectNamePlural = '' } = useParams(); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index 1e6ab59331..bae2a6ed88 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -28,7 +28,7 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; import { shouldNavigateBackToMemorizedUrlOnSaveState } from '@/ui/navigation/states/shouldNavigateBackToMemorizedUrlOnSaveState'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { AppPath, SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; @@ -40,6 +40,7 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; @@ -54,7 +55,7 @@ export type SettingsDataModelFieldEditFormValues = z.infer< const DELETE_FIELD_MODAL_ID = 'delete-field-confirmation-modal'; const StyledDangerButtons = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const SettingsObjectFieldEdit = () => { diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx index 504d1a709e..0930f58391 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx @@ -16,7 +16,7 @@ import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { type TableMetadata } from '@/ui/layout/table/types/TableMetadata'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; @@ -31,14 +31,15 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { MenuItemToggle } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useMapFieldMetadataItemToSettingsObjectDetailTableItem } from '~/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem'; import { type SettingsObjectDetailTableItem } from '~/pages/settings/data-model/types/SettingsObjectDetailTableItem'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; const StyledSearchAndFilterContainer = styled.div` display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - padding-bottom: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; + padding-bottom: ${themeCssVariables.spacing[2]}; width: 100%; `; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx index 2becd17199..e0b063119e 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectIndexTable.tsx @@ -8,7 +8,7 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { type TableMetadata } from '@/ui/layout/table/types/TableMetadata'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react/macro'; import { isNonEmptyArray } from '@sniptt/guards'; @@ -16,6 +16,7 @@ import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAto import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState'; import { useEffect, useMemo, useState } from 'react'; import { IconSearch, IconSquareKey } from 'twenty-ui/display'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type SettingsObjectIndexesTableItem } from '~/pages/settings/data-model/types/SettingsObjectIndexesTableItem'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; @@ -24,7 +25,7 @@ export const StyledObjectIndexTableRow = styled(TableRow)` `; const StyledSearchInput = styled(SettingsTextInput)` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; width: 100%; `; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx index 84cffd3251..24dde8b9b9 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx @@ -17,25 +17,26 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; 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 { useLingui } from '@lingui/react/macro'; -import { type ReactNode, useMemo, useState } from 'react'; +import { type ReactNode, useContext, useMemo, useState } from 'react'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { IconArchive, IconChevronRight, IconSettings } from 'twenty-ui/display'; import { SearchInput } from 'twenty-ui/input'; import { MenuItemToggle } from 'twenty-ui/navigation'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { GET_SETTINGS_OBJECT_TABLE_METADATA } from '~/pages/settings/data-model/constants/SettingsObjectTableMetadata'; import type { SettingsObjectTableItem } from '~/pages/settings/data-model/types/SettingsObjectTableItem'; import { normalizeSearchText } from '~/utils/normalizeSearchText'; const StyledIconChevronRight = styled(IconChevronRight)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; const StyledSearchInputContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; export const SettingsObjectTable = ({ @@ -47,7 +48,7 @@ export const SettingsObjectTable = ({ }) => { const { t } = useLingui(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const isAdvancedModeEnabled = useAtomStateValue(isAdvancedModeEnabledState); diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsApiKeys.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsApiKeys.tsx index 289ae392af..c5575ed5d1 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsApiKeys.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsApiKeys.tsx @@ -3,7 +3,7 @@ import { SettingsApiKeysTable } from '@/settings/developers/components/SettingsA import { PlaygroundSetupForm } from '@/settings/playground/components/PlaygroundSetupForm'; import { StyledSettingsApiPlaygroundCoverImage } from '@/settings/playground/components/SettingsPlaygroundCoverImage'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; @@ -11,13 +11,14 @@ import { H2Title, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledButtonContainer = styled.div` display: flex; justify-content: flex-end; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; @media (max-width: ${MOBILE_VIEWPORT}px) { - padding-top: ${({ theme }) => theme.spacing(5)}; + padding-top: ${themeCssVariables.spacing[5]}; } `; @@ -25,7 +26,7 @@ const StyledContainer = styled.div` display: flex; flex-direction: column; overflow: visible; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const SettingsApiKeys = () => { diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index 19e93a2bb0..1e720c14f2 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { isNonEmptyString } from '@sniptt/guards'; import { useStore } from 'jotai'; import { useCallback, useState } from 'react'; @@ -24,6 +24,7 @@ import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { H2Title, IconRepeat, IconTrash } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useAssignRoleToApiKeyMutation, useCreateApiKeyMutation, @@ -35,16 +36,16 @@ import { import { useNavigateSettings } from '~/hooks/useNavigateSettings'; const StyledInfo = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + color: ${themeCssVariables.font.color.light}; + font-size: ${themeCssVariables.font.size.sm}; + font-weight: ${themeCssVariables.font.weight.regular}; `; const StyledInputContainer = styled.div` align-items: center; display: flex; flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; width: 100%; `; diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx index 0e26047bf0..f911714ee9 100644 --- a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsWebhooks.tsx @@ -2,7 +2,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { SettingsWebhooksTable } from '@/settings/developers/components/SettingsWebhooksTable'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; @@ -10,13 +10,14 @@ import { H2Title, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledButtonContainer = styled.div` display: flex; justify-content: flex-end; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-top: ${themeCssVariables.spacing[2]}; @media (max-width: ${MOBILE_VIEWPORT}px) { - padding-top: ${({ theme }) => theme.spacing(5)}; + padding-top: ${themeCssVariables.spacing[5]}; } `; @@ -24,7 +25,7 @@ const StyledContainer = styled.div<{ isMobile: boolean }>` display: flex; flex-direction: column; overflow: hidden; - gap: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[2]}; `; export const SettingsWebhooks = () => { diff --git a/packages/twenty-front/src/pages/settings/domains/SettingsDomains.tsx b/packages/twenty-front/src/pages/settings/domains/SettingsDomains.tsx index 3b45116bfb..80dd0a4818 100644 --- a/packages/twenty-front/src/pages/settings/domains/SettingsDomains.tsx +++ b/packages/twenty-front/src/pages/settings/domains/SettingsDomains.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; @@ -12,13 +12,14 @@ import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { H2Title } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { SettingsEmailingDomains } from '~/pages/settings/emailing-domains/SettingsEmailingDomains'; const StyledMainContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(10)}; + gap: ${themeCssVariables.spacing[10]}; min-height: 200px; `; diff --git a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx index edfb786ac0..e708fa8681 100644 --- a/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx +++ b/packages/twenty-front/src/pages/settings/emailing-domains/SettingsEmailingDomains.tsx @@ -6,7 +6,7 @@ import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { SettingsEmailingDomainRowDropdownMenu } from '@/settings/emailing-domains/components/SettingsEmailingDomainRowDropdownMenu'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx index 1bc12b2bbf..f714001636 100644 --- a/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx +++ b/packages/twenty-front/src/pages/settings/members/SettingsWorkspaceMembers.tsx @@ -1,8 +1,7 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { isNonEmptyArray } from '@sniptt/guards'; -import { useMemo, useState } from 'react'; +import { useContext, useMemo, useState } from 'react'; import { useInView } from 'react-intersection-observer'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useDebounce } from 'use-debounce'; @@ -42,6 +41,8 @@ import { } from 'twenty-ui/display'; import { IconButton } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; +import { ThemeContext } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useGetWorkspaceInvitationsQuery } from '~/generated-metadata/graphql'; import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect'; @@ -59,8 +60,8 @@ const StyledButtonContainer = styled.div` display: flex; flex-direction: row; flex-shrink: 0; - gap: ${({ theme }) => theme.spacing(1)}; - margin-left: ${({ theme }) => theme.spacing(2)}; + gap: ${themeCssVariables.spacing[1]}; + margin-left: ${themeCssVariables.spacing[2]}; `; const StyledExpiresInHeader = styled.span` @@ -68,14 +69,14 @@ const StyledExpiresInHeader = styled.span` `; const StyledTable = styled(Table)<{ hasMoreRows?: boolean }>` - border-bottom: ${({ hasMoreRows, theme }) => - hasMoreRows ? 'none' : `1px solid ${theme.border.color.light}`}; + border-bottom: ${({ hasMoreRows }) => + hasMoreRows ? 'none' : `1px solid ${themeCssVariables.border.color.light}`}; `; const StyledIconWrapper = styled.div` display: flex; align-items: center; - margin-right: ${({ theme }) => theme.spacing(2)}; + margin-right: ${themeCssVariables.spacing[2]}; `; const StyledTextContainerWithEllipsis = styled.div` @@ -90,19 +91,19 @@ const StyledInvitationTableCell = styled(TableCell)` `; const StyledSearchContainer = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; `; const StyledSearchInput = styled(SettingsTextInput)` input { - background: ${({ theme }) => theme.background.transparent.lighter}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; + background: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.medium}; } `; const StyledTableRows = styled.div` - padding-bottom: ${({ theme }) => theme.spacing(2)}; - padding-top: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[2]}; `; const StyledClickableTableRow = styled(TableRow)` @@ -111,20 +112,20 @@ const StyledClickableTableRow = styled(TableRow)` const StyledChevronWrapper = styled.div` align-items: center; - color: ${({ theme }) => theme.font.color.secondary}; + color: ${themeCssVariables.font.color.secondary}; display: flex; justify-content: flex-end; width: 100%; `; const StyledNoMembers = styled(TableCell)` - color: ${({ theme }) => theme.font.color.tertiary}; + color: ${themeCssVariables.font.color.tertiary}; `; export const SettingsWorkspaceMembers = () => { const { t } = useLingui(); const { enqueueErrorSnackBar } = useSnackBar(); - const theme = useTheme(); + const { theme } = useContext(ThemeContext); const navigateSettings = useNavigateSettings(); const [isFetchingMore, setIsFetchingMore] = useState(false); const [searchFilter, setSearchFilter] = useState(''); diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx index 9ad187896b..5f9d600c97 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; @@ -15,13 +15,14 @@ import { enUS } from 'date-fns/locale'; import { APP_LOCALES } from 'twenty-shared/translations'; import { isDefined } from 'twenty-shared/utils'; import { dateLocaleState } from '~/localization/states/dateLocaleState'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { dynamicActivate } from '~/utils/i18n/dynamicActivate'; import { logError } from '~/utils/logError'; const StyledContainer = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(4)}; + gap: ${themeCssVariables.spacing[4]}; `; export const LocalePicker = () => { diff --git a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx b/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx index 599806d751..dc8b05e156 100644 --- a/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx +++ b/packages/twenty-front/src/pages/settings/security/SettingsSecurity.tsx @@ -1,5 +1,4 @@ -import isPropValid from '@emotion/is-prop-valid'; -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { Link } from 'react-router-dom'; import { useDebouncedCallback } from 'use-debounce'; @@ -38,6 +37,7 @@ import { } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Card, Section } from 'twenty-ui/layout'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useUpdateWorkspaceMutation } from '~/generated-metadata/graphql'; const StyledContainer = styled.div` @@ -47,7 +47,7 @@ const StyledContainer = styled.div` const StyledMainContent = styled.div` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(10)}; + gap: ${themeCssVariables.spacing[10]}; min-height: 200px; `; @@ -55,11 +55,12 @@ const StyledSection = styled(Section)` flex-shrink: 0; `; -const StyledLink = styled(Link, { - shouldForwardProp: (prop) => isPropValid(prop) && prop !== 'isDisabled', -})<{ isDisabled: boolean }>` - pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')}; +const StyledLink = styled(Link)` text-decoration: none; + + &[data-disabled='true'] { + pointer-events: none; + } `; export const SettingsSecurity = () => { @@ -258,7 +259,7 @@ export const SettingsSecurity = () => { Button={