diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx index f6d461c319f4..a1cb0f14d326 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx @@ -50,18 +50,16 @@ const StyledStepNodeType = styled.div<{ margin-left: ${({ theme }) => theme.spacing(2)}; padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; - .selectable.selected &, - .selectable:focus &, - .selectable:focus-visible & { + .selectable:is(.selected, :focus, :focus-visible) & { ${({ nodeVariant, theme }) => { switch (nodeVariant) { case 'empty': - case 'default': { + case 'default': + case 'not-executed': return css` background-color: ${theme.color.blue}; color: ${theme.font.color.inverted}; `; - } } }} } @@ -70,7 +68,7 @@ const StyledStepNodeType = styled.div<{ const StyledStepNodeInnerContainer = styled.div<{ variant: WorkflowDiagramNodeVariant; }>` - background-color: ${({ theme }) => theme.background.secondary}; + background: ${({ theme }) => theme.background.secondary}; border-color: ${({ theme }) => theme.border.color.medium}; border-radius: ${({ theme }) => theme.border.radius.md}; @@ -84,26 +82,41 @@ const StyledStepNodeInnerContainer = styled.div<{ position: relative; - .selectable.selected &, - .selectable:focus &, - .selectable:focus-visible & { + transition: background ${({ theme }) => theme.animation.duration.fast} ease; + + .workflow-node-container:hover & { + ${({ theme }) => { + return css` + background: linear-gradient( + 0deg, + ${theme.background.transparent.lighter} 0%, + ${theme.background.transparent.lighter} 100% + ), + ${theme.background.secondary}; + `; + }} + } + + .selectable:is(.selected, :focus, :focus-visible) + :is(.workflow-node-container, .workflow-node-container:hover) + & { ${({ theme, variant }) => { switch (variant) { case 'success': { return css` - background-color: ${theme.adaptiveColors.turquoise1}; + background: ${theme.adaptiveColors.turquoise1}; border-color: ${theme.adaptiveColors.turquoise4}; `; } case 'failure': { return css` - background-color: ${theme.background.danger}; + background: ${theme.background.danger}; border-color: ${theme.color.red}; `; } default: { return css` - background-color: ${theme.accent.quaternary}; + background: ${theme.adaptiveColors.blue1}; border-color: ${theme.color.blue}; `; } @@ -120,11 +133,20 @@ const StyledStepNodeLabel = styled.div<{ font-size: 13px; font-weight: ${({ theme }) => theme.font.weight.medium}; column-gap: ${({ theme }) => theme.spacing(2)}; - color: ${({ variant, theme }) => - variant === 'empty' - ? theme.font.color.extraLight - : theme.font.color.primary}; + color: ${({ variant, theme }) => { + switch (variant) { + case 'empty': + case 'not-executed': + return theme.font.color.light; + default: + return theme.font.color.primary; + } + }}; max-width: 200px; + + .selectable:is(.selected, :focus, :focus-visible) & { + color: ${({ theme }) => theme.font.color.primary}; + } `; export const StyledHandle = styled(Handle)` @@ -168,7 +190,7 @@ export const WorkflowDiagramBaseStepNode = ({ RightFloatingElement?: React.ReactNode; }) => { return ( - + {nodeType !== 'trigger' ? ( ) : null} diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx index 31e57d0491a5..4da876924f76 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx @@ -1,21 +1,33 @@ import { Meta, StoryObj } from '@storybook/react'; import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; +import { WorkflowDiagramNodeVariant } from '@/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant'; import { fn } from '@storybook/test'; import '@xyflow/react/dist/style.css'; +import { ComponentProps } from 'react'; import { CatalogDecorator, CatalogStory } from 'twenty-ui'; import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { WorkflowDiagramStepNodeEditableContent } from '../WorkflowDiagramStepNodeEditableContent'; -const meta: Meta = { +type ComponentState = 'default' | 'hover' | 'selected'; + +type WrapperProps = ComponentProps< + typeof WorkflowDiagramStepNodeEditableContent +> & { state: ComponentState }; + +const Wrapper = (_props: WrapperProps) => { + return
; +}; + +const meta: Meta = { title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent', component: WorkflowDiagramStepNodeEditableContent, }; export default meta; -type Story = StoryObj; +type Story = StoryObj; const ALL_STEPS = [ { @@ -47,17 +59,13 @@ const ALL_STEPS = [ { nodeType: 'action', actionType: 'CODE', name: 'Code' }, ] satisfies WorkflowDiagramStepNodeData[]; -export const All: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { +export const Catalog: CatalogStory = { args: { onDelete: fn(), - variant: 'default', - selected: false, }, parameters: { msw: graphqlMocks, + pseudo: { hover: ['.hover'] }, catalog: { options: { elementContainer: { @@ -71,159 +79,36 @@ export const All: CatalogStory< values: ALL_STEPS, props: (data: WorkflowDiagramStepNodeData) => ({ data }), }, - ], - }, - }, - decorators: [CatalogDecorator, ReactflowDecorator], -}; - -export const AllSelected: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { - args: { - onDelete: fn(), - variant: 'default', - selected: true, - }, - parameters: { - msw: graphqlMocks, - catalog: { - options: { - elementContainer: { - width: 250, - style: { position: 'relative' }, - className: 'selectable selected', - }, - }, - dimensions: [ { - name: 'step type', - values: ALL_STEPS, - props: (data: WorkflowDiagramStepNodeData) => ({ data }), + name: 'variant', + values: [ + 'empty', + 'default', + 'success', + 'failure', + 'not-executed', + ] satisfies WorkflowDiagramNodeVariant[], + props: (variant: WorkflowDiagramNodeVariant) => ({ variant }), }, - ], - }, - }, - decorators: [CatalogDecorator, ReactflowDecorator], -}; - -export const AllSuccess: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { - args: { - onDelete: fn(), - variant: 'success', - }, - parameters: { - msw: graphqlMocks, - catalog: { - options: { - elementContainer: { - width: 250, - style: { position: 'relative' }, - }, - }, - dimensions: [ { - name: 'step type', - values: ALL_STEPS, - props: (data: WorkflowDiagramStepNodeData) => ({ data }), + name: 'state', + values: ['default', 'hover', 'selected'] satisfies ComponentState[], + props: (state: ComponentState) => ({ state }), }, ], }, }, - decorators: [CatalogDecorator, ReactflowDecorator], -}; - -export const AllSuccessSelected: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { - args: { - onDelete: fn(), - variant: 'success', - selected: true, - }, - parameters: { - msw: graphqlMocks, - catalog: { - options: { - elementContainer: { - width: 250, - style: { position: 'relative' }, - className: 'selectable selected', - }, - }, - dimensions: [ - { - name: 'step type', - values: ALL_STEPS, - props: (data: WorkflowDiagramStepNodeData) => ({ data }), - }, - ], - }, - }, - decorators: [CatalogDecorator, ReactflowDecorator], -}; - -export const AllFailure: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { - args: { - onDelete: fn(), - variant: 'failure', - }, - parameters: { - msw: graphqlMocks, - catalog: { - options: { - elementContainer: { - width: 250, - style: { position: 'relative' }, - }, - }, - dimensions: [ - { - name: 'step type', - values: ALL_STEPS, - props: (data: WorkflowDiagramStepNodeData) => ({ data }), - }, - ], - }, - }, - decorators: [CatalogDecorator, ReactflowDecorator], -}; - -export const AllFailureSelected: CatalogStory< - Story, - typeof WorkflowDiagramStepNodeEditableContent -> = { - args: { - onDelete: fn(), - variant: 'failure', - selected: true, - }, - parameters: { - msw: graphqlMocks, - catalog: { - options: { - elementContainer: { - width: 250, - style: { position: 'relative' }, - className: 'selectable selected', - }, - }, - dimensions: [ - { - name: 'step type', - values: ALL_STEPS, - props: (data: WorkflowDiagramStepNodeData) => ({ data }), - }, - ], + decorators: [ + (Story, { args }) => { + return ( +
+ +
+ ); }, - }, - decorators: [CatalogDecorator, ReactflowDecorator], + CatalogDecorator, + ReactflowDecorator, + ], }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant.ts index 6a7a5ff92131..508bfdf942e7 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant.ts @@ -2,4 +2,5 @@ export type WorkflowDiagramNodeVariant = | 'default' | 'success' | 'failure' - | 'empty'; + | 'empty' + | 'not-executed'; diff --git a/packages/twenty-ui/src/theme/constants/AdaptiveColorsDark.ts b/packages/twenty-ui/src/theme/constants/AdaptiveColorsDark.ts index c021d12015a2..2f8827dc99cd 100644 --- a/packages/twenty-ui/src/theme/constants/AdaptiveColorsDark.ts +++ b/packages/twenty-ui/src/theme/constants/AdaptiveColorsDark.ts @@ -5,4 +5,8 @@ export const ADAPTIVE_COLORS_DARK = { turquoise2: THEME_COMMON.color.turquoise70, turquoise3: THEME_COMMON.color.turquoise60, turquoise4: THEME_COMMON.color.turquoise50, + blue1: THEME_COMMON.color.blue80, + blue2: THEME_COMMON.color.blue70, + blue3: THEME_COMMON.color.blue60, + blue4: THEME_COMMON.color.blue50, }; diff --git a/packages/twenty-ui/src/theme/constants/AdaptiveColorsLight.ts b/packages/twenty-ui/src/theme/constants/AdaptiveColorsLight.ts index 69c9e15939c6..c19fec595a38 100644 --- a/packages/twenty-ui/src/theme/constants/AdaptiveColorsLight.ts +++ b/packages/twenty-ui/src/theme/constants/AdaptiveColorsLight.ts @@ -5,4 +5,8 @@ export const ADAPTIVE_COLORS_LIGHT = { turquoise2: THEME_COMMON.color.turquoise20, turquoise3: THEME_COMMON.color.turquoise30, turquoise4: THEME_COMMON.color.turquoise40, + blue1: THEME_COMMON.color.blue10, + blue2: THEME_COMMON.color.blue20, + blue3: THEME_COMMON.color.blue30, + blue4: THEME_COMMON.color.blue40, };