chore(twenty-front): migrate command-menu, workflow, page-layout and UI modules from Emotion to Linaria (PR 4-6/10) (#18342)
## Summary
Continues the Emotion → Linaria migration (PR 4-6 from the [migration
plan](docs/emotion-to-linaria-migration-plan.md)). Migrates **311
files** across four module groups:
| Module | Files |
|---|---|
| command-menu | 53 |
| workflow | 84 |
| page-layout | 84 |
| UI (partial - first ~80 files) | ~80 |
| twenty-ui (TEXT_INPUT_STYLE) | 1 |
| misc (hooks, keyboard-shortcut-menu, file-upload) | ~9 |
### Migration patterns applied
- `import styled from '@emotion/styled'` → `import { styled } from
'@linaria/react'`
- `import { useTheme } from '@emotion/react'` → `import { useContext }
from 'react'` + `import { ThemeContext } from 'twenty-ui/theme'`
- `${({ theme }) => theme.X.Y.Z}` → `${themeCssVariables.X.Y.Z}` (static
CSS variables)
- `theme.spacing(N)` → `themeCssVariables.spacing[N]`
- `styled(motion.div)` → `motion.create(StyledBase)` (11 components)
- `styled(Component)<TypeParams>` → wrapper div approach for non-HTML
elements
- Multi-declaration interpolations split into one CSS property per
interpolation
- Interpolation return types fixed (`&&` → ternary `? : ''`)
- `TEXT_INPUT_STYLE` converted from function to static string constant
(backward compatible)
- Emotion `<Global>` replaced with `useEffect` style injection
- Complex runtime-dependent styles use CSS custom properties via
`style={}` prop
### After this PR
- **Remaining files**: ~400 (object-record: ~160, settings: ~200, UI:
~44)
- **No breaking changes**: CSS variables resolve identically to the
previous Emotion theme values
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledCanvasContainer = styled.div`
|
||||
|
||||
@@ -26,8 +26,7 @@ import { WidgetPlaceholder } from '@/page-layout/widgets/components/WidgetPlaceh
|
||||
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import {
|
||||
Responsive,
|
||||
@@ -37,20 +36,36 @@ import {
|
||||
type ResponsiveProps,
|
||||
} from 'react-grid-layout';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { css } from '@linaria/core';
|
||||
|
||||
const StyledGridContainer = styled.div<{ $disableTransitions: boolean }>`
|
||||
const disabledTransitionsClass = css`
|
||||
.react-grid-layout {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.react-grid-item {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.react-grid-item.cssTransforms {
|
||||
transition-property: none !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledGridContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${themeCssVariables.spacing[2]};
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
|
||||
.react-grid-placeholder {
|
||||
background: ${({ theme }) => theme.color.blue7} !important;
|
||||
background: ${themeCssVariables.color.blue7} !important;
|
||||
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
border-radius: ${themeCssVariables.border.radius.md};
|
||||
}
|
||||
|
||||
.react-grid-item:not(.react-draggable-dragging) {
|
||||
@@ -68,22 +83,6 @@ const StyledGridContainer = styled.div<{ $disableTransitions: boolean }>`
|
||||
.react-grid-item:hover .widget-card-resize-handle {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
${({ $disableTransitions }) =>
|
||||
$disableTransitions &&
|
||||
css`
|
||||
.react-grid-layout {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.react-grid-item {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.react-grid-item.cssTransforms {
|
||||
transition-property: none !important;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
type ExtendedResponsiveProps = ResponsiveProps & {
|
||||
@@ -172,7 +171,9 @@ export const PageLayoutGridLayout = ({ tabId }: PageLayoutGridLayoutProps) => {
|
||||
return (
|
||||
<StyledGridContainer
|
||||
ref={gridContainerRef}
|
||||
$disableTransitions={shouldDisableTransitions}
|
||||
className={
|
||||
shouldDisableTransitions ? disabledTransitionsClass : undefined
|
||||
}
|
||||
>
|
||||
{isPageLayoutInEditMode && (
|
||||
<>
|
||||
|
||||
+16
-13
@@ -9,41 +9,44 @@ import { calculateTotalGridRows } from '@/page-layout/utils/calculateTotalGridRo
|
||||
import { generateCellId } from '@/page-layout/utils/generateCellId';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useMemo } from 'react';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledGridOverlay = styled.div<{
|
||||
isDragSelecting?: boolean;
|
||||
breakpoint: PageLayoutBreakpoint;
|
||||
}>`
|
||||
position: absolute;
|
||||
top: ${({ theme }) => theme.spacing(2)};
|
||||
left: ${({ theme }) => theme.spacing(2)};
|
||||
right: ${({ theme }) => theme.spacing(2)};
|
||||
bottom: ${({ theme }) => theme.spacing(2)};
|
||||
top: ${themeCssVariables.spacing[2]};
|
||||
left: ${themeCssVariables.spacing[2]};
|
||||
right: ${themeCssVariables.spacing[2]};
|
||||
bottom: ${themeCssVariables.spacing[2]};
|
||||
display: grid;
|
||||
grid-template-columns: ${({ breakpoint }) =>
|
||||
breakpoint === 'mobile' ? '1fr' : 'repeat(12, 1fr)'};
|
||||
grid-auto-rows: 55px;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
pointer-events: ${({ isDragSelecting }) =>
|
||||
isDragSelecting ? 'auto' : 'none'};
|
||||
z-index: ${PAGE_LAYOUT_GRID_OVERLAY_Z_INDEX};
|
||||
`;
|
||||
|
||||
const StyledGridCell = styled.div<{ isSelected?: boolean }>`
|
||||
background: ${({ isSelected, theme }) =>
|
||||
isSelected ? theme.color.blue3 : 'transparent'};
|
||||
background: ${({ isSelected }) =>
|
||||
isSelected ? themeCssVariables.color.blue3 : 'transparent'};
|
||||
border: 1px solid
|
||||
${({ theme, isSelected }) =>
|
||||
isSelected ? theme.color.blue7 : theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
${({ isSelected }) =>
|
||||
isSelected
|
||||
? themeCssVariables.color.blue7
|
||||
: themeCssVariables.border.color.light};
|
||||
border-radius: ${themeCssVariables.border.radius.md};
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.background.transparent.lighter};
|
||||
border-color: ${({ theme }) => theme.border.color.medium};
|
||||
background: ${themeCssVariables.background.transparent.lighter};
|
||||
border-color: ${themeCssVariables.border.color.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
+72
-81
@@ -1,12 +1,13 @@
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { forwardRef } from 'react';
|
||||
import { styled } from '@linaria/react';
|
||||
import { forwardRef, useContext } from 'react';
|
||||
import {
|
||||
IconRadiusBottomLeft,
|
||||
IconRadiusBottomRight,
|
||||
IconRadiusTopLeft,
|
||||
IconRadiusTopRight,
|
||||
} from 'twenty-ui/display';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { ThemeContext } from 'twenty-ui/theme';
|
||||
|
||||
type WidgetHandleAxis = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
||||
type WidgetHorizontalHandleAxis = 'n' | 's';
|
||||
@@ -29,60 +30,61 @@ const StyledCornerIconWrapper = styled.div<{
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: ${({ cursor }) => cursor};
|
||||
width: ${({ theme }) => theme.spacing(4)};
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
width: ${themeCssVariables.spacing[4]};
|
||||
height: ${themeCssVariables.spacing[4]};
|
||||
|
||||
& svg {
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
pointer-events: none;
|
||||
transform: ${({ position, theme }) => {
|
||||
transform: ${({ position }) => {
|
||||
if (position === 'se') {
|
||||
return `translate(-${theme.spacing(2)}, -${theme.spacing(2)})`;
|
||||
return `translate(-${themeCssVariables.spacing[2]}, -${themeCssVariables.spacing[2]})`;
|
||||
}
|
||||
if (position === 'sw') {
|
||||
return `translate(${theme.spacing(2)}, -${theme.spacing(2)})`;
|
||||
return `translate(${themeCssVariables.spacing[2]}, -${themeCssVariables.spacing[2]})`;
|
||||
}
|
||||
if (position === 'ne') {
|
||||
return `translate(-${theme.spacing(2)}, ${theme.spacing(2)})`;
|
||||
return `translate(-${themeCssVariables.spacing[2]}, ${themeCssVariables.spacing[2]})`;
|
||||
}
|
||||
if (position === 'nw') {
|
||||
return `translate(${theme.spacing(2)}, ${theme.spacing(2)})`;
|
||||
return `translate(${themeCssVariables.spacing[2]}, ${themeCssVariables.spacing[2]})`;
|
||||
}
|
||||
return '';
|
||||
}};
|
||||
}
|
||||
|
||||
:hover {
|
||||
svg {
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledVerticalHandle = styled.div`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
height: ${({ theme }) => theme.spacing(5)};
|
||||
width: ${({ theme }) => theme.icon.stroke.lg}px;
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
height: ${themeCssVariables.spacing[5]};
|
||||
width: ${themeCssVariables.icon.stroke.lg}px;
|
||||
`;
|
||||
|
||||
const StyledHorizontalHandle = styled.div`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
height: ${({ theme }) => theme.icon.stroke.lg}px;
|
||||
width: ${({ theme }) => theme.spacing(5)};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
height: ${themeCssVariables.icon.stroke.lg}px;
|
||||
width: ${themeCssVariables.spacing[5]};
|
||||
`;
|
||||
|
||||
const StyledHorizontalHandleWrapper = styled.div<{
|
||||
widgetHandleAxis: WidgetHorizontalHandleAxis;
|
||||
}>`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
cursor: row-resize;
|
||||
transform: ${({ widgetHandleAxis }) =>
|
||||
widgetHandleAxis === 'n' ? 'translateY(-50%)' : 'translateY(50%)'};
|
||||
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]};
|
||||
|
||||
:hover {
|
||||
& > div {
|
||||
background-color: ${({ theme }) => theme.font.color.tertiary};
|
||||
background-color: ${themeCssVariables.font.color.tertiary};
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -91,14 +93,14 @@ const StyledVerticalHandleWrapper = styled.div<{
|
||||
widgetHandleAxis: WidgetVerticalHandleAxis;
|
||||
}>`
|
||||
cursor: col-resize;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
transform: ${({ widgetHandleAxis }) =>
|
||||
widgetHandleAxis === 'w' ? 'translateX(-50%)' : 'translateX(50%)'};
|
||||
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]};
|
||||
|
||||
:hover {
|
||||
& > div {
|
||||
background-color: ${({ theme }) => theme.font.color.tertiary};
|
||||
background-color: ${themeCssVariables.font.color.tertiary};
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -107,64 +109,53 @@ const StyledResizeHandleWrapper = styled.div<{
|
||||
widgetHandleAxis?: WidgetHandleAxis;
|
||||
}>`
|
||||
position: absolute;
|
||||
${({ theme, widgetHandleAxis }) => {
|
||||
if (widgetHandleAxis === 'w') {
|
||||
return css`
|
||||
left: ${theme.spacing(1.5)};
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
`;
|
||||
|
||||
top: ${({ widgetHandleAxis }) => {
|
||||
if (widgetHandleAxis === 'w' || widgetHandleAxis === 'e') return '50%';
|
||||
if (widgetHandleAxis === 'n') return themeCssVariables.spacing[1.5];
|
||||
if (widgetHandleAxis === 'ne' || widgetHandleAxis === 'nw') return '0';
|
||||
return 'auto';
|
||||
}};
|
||||
|
||||
bottom: ${({ widgetHandleAxis }) => {
|
||||
if (widgetHandleAxis === 's') return themeCssVariables.spacing[1.5];
|
||||
if (widgetHandleAxis === 'se' || widgetHandleAxis === 'sw') return '0';
|
||||
return 'auto';
|
||||
}};
|
||||
|
||||
left: ${({ widgetHandleAxis }) => {
|
||||
if (widgetHandleAxis === 'w') return themeCssVariables.spacing[1.5];
|
||||
if (widgetHandleAxis === 'n' || widgetHandleAxis === 's') return '50%';
|
||||
if (widgetHandleAxis === 'sw' || widgetHandleAxis === 'nw') return '0';
|
||||
return 'auto';
|
||||
}};
|
||||
|
||||
right: ${({ widgetHandleAxis }) => {
|
||||
if (widgetHandleAxis === 'e') return themeCssVariables.spacing[1.5];
|
||||
if (widgetHandleAxis === 'se' || widgetHandleAxis === 'ne') return '0';
|
||||
return 'auto';
|
||||
}};
|
||||
|
||||
transform: ${({ widgetHandleAxis }) => {
|
||||
switch (widgetHandleAxis) {
|
||||
case 'w':
|
||||
case 'e':
|
||||
return 'translateY(-50%)';
|
||||
case 'n':
|
||||
case 's':
|
||||
return 'translateX(-50%)';
|
||||
case 'se':
|
||||
return `translate(${themeCssVariables.spacing[1]}, ${themeCssVariables.spacing[1]})`;
|
||||
case 'sw':
|
||||
return `translate(-${themeCssVariables.spacing[1]}, ${themeCssVariables.spacing[1]})`;
|
||||
case 'ne':
|
||||
return `translate(${themeCssVariables.spacing[1]}, -${themeCssVariables.spacing[1]})`;
|
||||
case 'nw':
|
||||
return `translate(-${themeCssVariables.spacing[1]}, -${themeCssVariables.spacing[1]})`;
|
||||
default:
|
||||
return 'none';
|
||||
}
|
||||
if (widgetHandleAxis === 'e') {
|
||||
return css`
|
||||
right: ${theme.spacing(1.5)};
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 'n') {
|
||||
return css`
|
||||
top: ${theme.spacing(1.5)};
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 's') {
|
||||
return css`
|
||||
bottom: ${theme.spacing(1.5)};
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 'se') {
|
||||
return css`
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
transform: translate(${theme.spacing(1)}, ${theme.spacing(1)});
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 'sw') {
|
||||
return css`
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translate(-${theme.spacing(1)}, ${theme.spacing(1)});
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 'ne') {
|
||||
return css`
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translate(${theme.spacing(1)}, -${theme.spacing(1)});
|
||||
`;
|
||||
}
|
||||
if (widgetHandleAxis === 'nw') {
|
||||
return css`
|
||||
left: 0;
|
||||
top: 0;
|
||||
transform: translate(-${theme.spacing(1)}, -${theme.spacing(1)});
|
||||
`;
|
||||
}
|
||||
}}
|
||||
}};
|
||||
`;
|
||||
|
||||
const isVerticalHandle = (
|
||||
@@ -192,7 +183,7 @@ export const PageLayoutGridResizeHandle = forwardRef<
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const theme = useTheme();
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<StyledResizeHandleWrapper
|
||||
|
||||
@@ -7,13 +7,14 @@ import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { PageLayoutType } from '~/generated-metadata/graphql';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
background: ${themeCssVariables.background.secondary};
|
||||
border-bottom-left-radius: 8px;
|
||||
border-right: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
||||
border-right: 1px solid ${themeCssVariables.border.color.medium};
|
||||
border-top-left-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
|
||||
+3
-2
@@ -20,11 +20,12 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledContainer = styled.div<{ hasPinnedTab: boolean }>`
|
||||
display: grid;
|
||||
@@ -42,7 +43,7 @@ const StyledTabsAndDashboardContainer = styled.div`
|
||||
`;
|
||||
|
||||
const StyledPageLayoutTabList = styled(PageLayoutTabList)`
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
padding-left: ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledScrollWrapper = styled(ScrollWrapper)`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
DragDropContext,
|
||||
type DropResult,
|
||||
@@ -47,17 +47,18 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type PageLayoutType } from '~/generated-metadata/graphql';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(10)};
|
||||
height: ${themeCssVariables.spacing[10]};
|
||||
position: relative;
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
|
||||
&::after {
|
||||
background-color: ${({ theme }) => theme.border.color.light};
|
||||
background-color: ${themeCssVariables.border.color.light};
|
||||
bottom: 0;
|
||||
content: '';
|
||||
height: 1px;
|
||||
@@ -70,7 +71,7 @@ const StyledContainer = styled.div`
|
||||
const StyledAddButton = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: ${({ theme }) => theme.spacing(10)};
|
||||
height: ${themeCssVariables.spacing[10]};
|
||||
margin-left: ${TAB_LIST_GAP}px;
|
||||
`;
|
||||
|
||||
|
||||
+15
-12
@@ -1,21 +1,23 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { Droppable } from '@hello-pangea/dnd';
|
||||
|
||||
import { PAGE_LAYOUT_TAB_LIST_DROPPABLE_IDS } from '@/page-layout/components/PageLayoutTabListDroppableIds';
|
||||
import { TabMoreButton } from '@/ui/layout/tab-list/components/TabMoreButton';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
type PageLayoutTabListDroppableMoreButtonProps = {
|
||||
hiddenTabsCount: number;
|
||||
isActiveTabHidden: boolean;
|
||||
};
|
||||
|
||||
const StyledTabMoreButton = styled(TabMoreButton)<{ isDraggingOver: boolean }>`
|
||||
${({ isDraggingOver, theme }) =>
|
||||
isDraggingOver &&
|
||||
`
|
||||
background-color: ${theme.background.transparent.blue};
|
||||
const StyledTabMoreButtonWrapper = styled.div<{ isDraggingOver: boolean }>`
|
||||
${({ isDraggingOver }) =>
|
||||
isDraggingOver
|
||||
? `
|
||||
background-color: ${themeCssVariables.background.transparent.blue};
|
||||
pointer-events: none;
|
||||
`}
|
||||
`
|
||||
: ''}
|
||||
`;
|
||||
|
||||
export const PageLayoutTabListDroppableMoreButton = ({
|
||||
@@ -30,11 +32,12 @@ export const PageLayoutTabListDroppableMoreButton = ({
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
<StyledTabMoreButton
|
||||
hiddenTabsCount={hiddenTabsCount}
|
||||
active={isActiveTabHidden}
|
||||
isDraggingOver={snapshot.isDraggingOver}
|
||||
/>
|
||||
<StyledTabMoreButtonWrapper isDraggingOver={snapshot.isDraggingOver}>
|
||||
<TabMoreButton
|
||||
hiddenTabsCount={hiddenTabsCount}
|
||||
active={isActiveTabHidden}
|
||||
/>
|
||||
</StyledTabMoreButtonWrapper>
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
|
||||
+3
-3
@@ -1,5 +1,4 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
Draggable,
|
||||
type DraggableProvided,
|
||||
@@ -30,6 +29,7 @@ import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSe
|
||||
import { useContext } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { type PageLayoutType } from '~/generated-metadata/graphql';
|
||||
import { ThemeContext } from 'twenty-ui/theme';
|
||||
|
||||
const StyledOverflowDropdownListDraggableWrapper = styled.div`
|
||||
display: flex;
|
||||
@@ -65,7 +65,7 @@ export const PageLayoutTabListReorderableOverflowDropdown = ({
|
||||
onClose,
|
||||
pageLayoutType,
|
||||
}: PageLayoutTabListReorderableOverflowDropdownProps) => {
|
||||
const theme = useTheme();
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const context = useContext(TabListComponentInstanceContext);
|
||||
const instanceId = context?.instanceId;
|
||||
|
||||
|
||||
+16
-14
@@ -3,8 +3,9 @@ import { Draggable } from '@hello-pangea/dnd';
|
||||
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
|
||||
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { StyledTabContainer, TabContent } from 'twenty-ui/input';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
type PageLayoutTabListReorderableTabProps = {
|
||||
tab: SingleTabProps;
|
||||
@@ -14,9 +15,9 @@ type PageLayoutTabListReorderableTabProps = {
|
||||
onSelect: () => void;
|
||||
};
|
||||
|
||||
const StyledTabContent = styled(TabContent)<{ isBeingEdited: boolean }>`
|
||||
outline: ${({ isBeingEdited, theme }) =>
|
||||
isBeingEdited ? `1px solid ${theme.color.blue}` : 'none'};
|
||||
const StyledTabContentWrapper = styled.div<{ isBeingEdited: boolean }>`
|
||||
outline: ${({ isBeingEdited }) =>
|
||||
isBeingEdited ? `1px solid ${themeCssVariables.color.blue}` : 'none'};
|
||||
outline-offset: -1px;
|
||||
`;
|
||||
|
||||
@@ -49,16 +50,17 @@ export const PageLayoutTabListReorderableTab = ({
|
||||
cursor: draggableSnapshot.isDragging ? 'grabbing' : 'pointer',
|
||||
}}
|
||||
>
|
||||
<StyledTabContent
|
||||
id={tab.id}
|
||||
active={isActive}
|
||||
disabled={disabled}
|
||||
LeftIcon={tab.Icon}
|
||||
title={tab.title}
|
||||
logo={tab.logo}
|
||||
pill={tab.pill}
|
||||
isBeingEdited={isSettingsOpenForThisTab}
|
||||
/>
|
||||
<StyledTabContentWrapper isBeingEdited={isSettingsOpenForThisTab}>
|
||||
<TabContent
|
||||
id={tab.id}
|
||||
active={isActive}
|
||||
disabled={disabled}
|
||||
LeftIcon={tab.Icon}
|
||||
title={tab.title}
|
||||
logo={tab.logo}
|
||||
pill={tab.pill}
|
||||
/>
|
||||
</StyledTabContentWrapper>
|
||||
</StyledTabContainer>
|
||||
)}
|
||||
</Draggable>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
type DraggableProvided,
|
||||
type DraggableRubric,
|
||||
|
||||
+7
-6
@@ -1,6 +1,5 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { type MouseEvent, useState } from 'react';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type MouseEvent, useContext, useState } from 'react';
|
||||
|
||||
import { TabAvatar } from '@/ui/layout/tab-list/components/TabAvatar';
|
||||
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
|
||||
@@ -12,12 +11,14 @@ import {
|
||||
StyledMenuItemLabel,
|
||||
StyledMenuItemLeftContent,
|
||||
} from 'twenty-ui/navigation';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { ThemeContext } from 'twenty-ui/theme';
|
||||
|
||||
const StyledTextContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 0 0;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
max-width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
@@ -26,7 +27,7 @@ const StyledTextContainer = styled.div`
|
||||
const StyledRightContent = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
`;
|
||||
|
||||
type PageLayoutTabMenuItemSelectAvatarProps = {
|
||||
@@ -48,7 +49,7 @@ export const PageLayoutTabMenuItemSelectAvatar = ({
|
||||
onEditClick,
|
||||
testId,
|
||||
}: PageLayoutTabMenuItemSelectAvatarProps) => {
|
||||
const theme = useTheme();
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
return (
|
||||
|
||||
+4
-3
@@ -4,11 +4,12 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene
|
||||
import { TabAvatar } from '@/ui/layout/tab-list/components/TabAvatar';
|
||||
import { type SingleTabProps } from '@/ui/layout/tab-list/types/SingleTabProps';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type DraggableProvided } from '@hello-pangea/dnd';
|
||||
import { StyledTabContainer, TabContent } from 'twenty-ui/input';
|
||||
import { MenuItemSelectAvatar } from 'twenty-ui/navigation';
|
||||
import { useContext } from 'react';
|
||||
import { ThemeContext } from 'twenty-ui/theme';
|
||||
|
||||
const StyledDraggableWrapper = styled.div`
|
||||
display: flex;
|
||||
@@ -28,7 +29,7 @@ export const PageLayoutTabRenderClone = ({
|
||||
provided: DraggableProvided;
|
||||
activeTabId: string | null;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
const pageLayoutTabListCurrentDragDroppableId = useAtomComponentStateValue(
|
||||
pageLayoutTabListCurrentDragDroppableIdComponentState,
|
||||
|
||||
+15
-10
@@ -6,7 +6,7 @@ import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer'
|
||||
import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
DragDropContext,
|
||||
Draggable,
|
||||
@@ -15,26 +15,31 @@ import {
|
||||
} from '@hello-pangea/dnd';
|
||||
import { useId } from 'react';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledVerticalListContainer = styled.div<{
|
||||
variant: PageLayoutVerticalListViewerVariant;
|
||||
shouldUseWhiteBackground: boolean;
|
||||
}>`
|
||||
background: ${({ theme, shouldUseWhiteBackground }) =>
|
||||
background: ${({ shouldUseWhiteBackground }) =>
|
||||
shouldUseWhiteBackground
|
||||
? theme.background.primary
|
||||
: theme.background.secondary};
|
||||
? themeCssVariables.background.primary
|
||||
: themeCssVariables.background.secondary};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
padding: ${({ theme, variant }) =>
|
||||
variant === 'side-column' ? theme.spacing(1) : theme.spacing(2)};
|
||||
gap: ${themeCssVariables.spacing[4]};
|
||||
padding: ${({ variant }) =>
|
||||
variant === 'side-column'
|
||||
? themeCssVariables.spacing[1]
|
||||
: themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledDraggableWrapper = styled.div<{ isDragging: boolean }>`
|
||||
background: ${({ theme, isDragging }) =>
|
||||
isDragging ? theme.background.transparent.light : 'transparent'};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
background: ${({ isDragging }) =>
|
||||
isDragging
|
||||
? themeCssVariables.background.transparent.light
|
||||
: 'transparent'};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
transition: background 0.1s ease;
|
||||
`;
|
||||
|
||||
|
||||
+9
-8
@@ -1,4 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
|
||||
import { getPageLayoutVerticalListViewerVariant } from '@/page-layout/components/utils/getPageLayoutVerticalListViewerVariant';
|
||||
@@ -7,21 +7,22 @@ import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget';
|
||||
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
|
||||
import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledVerticalListContainer = styled.div<{
|
||||
variant: PageLayoutVerticalListViewerVariant;
|
||||
shouldUseWhiteBackground: boolean;
|
||||
}>`
|
||||
background: ${({ theme, shouldUseWhiteBackground }) =>
|
||||
background: ${({ shouldUseWhiteBackground }) =>
|
||||
shouldUseWhiteBackground
|
||||
? theme.background.primary
|
||||
: theme.background.secondary};
|
||||
? themeCssVariables.background.primary
|
||||
: themeCssVariables.background.secondary};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme, variant }) =>
|
||||
variant === 'side-column' ? 0 : theme.spacing(2)};
|
||||
padding: ${({ theme, variant }) =>
|
||||
variant === 'side-column' ? 0 : theme.spacing(2)};
|
||||
gap: ${({ variant }) =>
|
||||
variant === 'side-column' ? 0 : themeCssVariables.spacing[2]};
|
||||
padding: ${({ variant }) =>
|
||||
variant === 'side-column' ? 0 : themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
type PageLayoutVerticalListViewerProps = {
|
||||
|
||||
+4
-3
@@ -1,4 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type DropResult, type ResponderProvided } from '@hello-pangea/dnd';
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { useMemo, useState } from 'react';
|
||||
@@ -11,10 +11,11 @@ import { PageLayoutComponentInstanceContext } from '@/page-layout/states/context
|
||||
import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
|
||||
import { calculateNewPosition } from '@/ui/layout/draggable-list/utils/calculateNewPosition';
|
||||
import { PageLayoutType } from '~/generated-metadata/graphql';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
border: 1px solid ${({ theme }) => theme.border.color.strong};
|
||||
padding: ${({ theme }) => theme.spacing(4)};
|
||||
border: 1px solid ${themeCssVariables.border.color.strong};
|
||||
padding: ${themeCssVariables.spacing[4]};
|
||||
width: 720px;
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user