From 77c84815ef74001c888ceafee282b61bb7d72b04 Mon Sep 17 00:00:00 2001 From: "Abdullah." <125115953+mabdullahabaid@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:41:34 +0500 Subject: [PATCH] feat(website): rework the product-stepper Layout visual (#22249) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What Reworks the **"Layout" step** visual of the product-page stepper (the floating record-layout-editor scene) to match the Figma references and read as a premium, layered composition. Data is unchanged — this is purely the look. ## Figma alignment - **Fields editor** — the inline-edit field row now keeps the field icon + a bordered input + blue **Done** + the eye / ⋮ (instead of a floating box); **"New fields"** renders as a uniform field row; section headers get an overflow menu; field types read `Boolean` / `Date & Time`. Dropped the redundant "Fields widget" header label. - **"General" widget** — header chevron, the real `anonymousFelix` avatar on Account Owner (reusing the shared asset the other product-feature visuals use), a **Revenue** row, and a money-bag icon for the currency field. ## Premium composition - The nav, record, and Fields editor read as one elevated **z-stack** (back → front): the nav is pushed right so its edge tucks under the record (lowest z-index), the record sits above it, and the editor stays in front — each casting a progressively stronger shadow so the depth ordering is unmistakable. - The **"New record / Enrich / Edit actions"** bar is centered over the nav–record seam (`translateX(-50%)`) to tie the layered stack together at the top. ## Testing - typecheck · oxfmt · oxlint · check-conventions — green. - Verified visually with headless Playwright on `/product` (Layout step). image --- .../LayoutVisual/LayoutVisual.tsx | 146 +++++++++++------- .../LayoutVisual/components/LayoutIcons.tsx | 21 ++- .../LayoutVisual/components/layout-chrome.ts | 104 ++++++------- .../LayoutVisual/data/layout-data.ts | 4 +- .../feature-scenes/product-stepper-scene.ts | 4 + 5 files changed, 161 insertions(+), 118 deletions(-) diff --git a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/LayoutVisual.tsx b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/LayoutVisual.tsx index 966a6b0e46..34956aaf5d 100644 --- a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/LayoutVisual.tsx +++ b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/LayoutVisual.tsx @@ -8,6 +8,7 @@ import { type PointerEvent as ReactPointerEvent, } from 'react'; +import { sharedAssetUrls } from '@/app-preview/data/shared-asset-urls'; import { getElementScale } from '@/platform/motion'; import { PRODUCT_STEPPER_SCENE } from '@/tokens/feature-scenes/product-stepper-scene'; @@ -17,6 +18,7 @@ import { LAYOUT_CHROME } from './components/layout-chrome'; import { LAYOUT_EDITOR_CONTENT } from './data/layout-data'; const { + ChevronDown: ChevronDownGlyph, ChevronLeft: ChevronLeftGlyph, Dots: DotsGlyph, Eye: EyeGlyph, @@ -24,8 +26,8 @@ const { Grip: GripGlyph, List: ListGlyph, Nav: NavGlyph, + NewFields: NewFieldsGlyph, NewSection: NewSectionGlyph, - Plus: PlusGlyph, Spark: SparkGlyph, } = LAYOUT_GLYPHS; @@ -36,8 +38,8 @@ const { AddSectionRow, AddText, DoneButton, - EditableRow, - EditableText, + EditField, + EditGroup, FieldDot, FieldIconBox, FieldLabels, @@ -51,10 +53,6 @@ const { NavPanel, NavSectionLabel, NavSubItem, - NewFieldsColumn, - NewFieldsDescription, - NewFieldsRow, - NewFieldsTitle, PanelActionButton, PanelBackButton, PanelFields, @@ -64,10 +62,10 @@ const { PanelSubLabel, PanelTitleBold, PanelTitleGroup, - PanelTitleSub, RightPanel, SectionName, SectionRow, + WidgetAvatar, WidgetChip, WidgetIcon, WidgetInner, @@ -158,7 +156,10 @@ export function LayoutVisual({ active }: { active: boolean }) { > - {i18n._(msg`General`)} + + {i18n._(msg`General`)} + + @@ -171,7 +172,14 @@ export function LayoutVisual({ active }: { active: boolean }) { {i18n._(msg`Account Owner`)} - Félix Malfait + + + Félix Malfait + @@ -187,6 +195,13 @@ export function LayoutVisual({ active }: { active: boolean }) { {i18n._(msg`ICP`)} ✓ True + + + + + {i18n._(msg`Revenue`)} + $500,000 + @@ -253,7 +268,6 @@ export function LayoutVisual({ active }: { active: boolean }) { {i18n._(msg`Fields`)} - {i18n._(msg`Fields widget`)} @@ -275,46 +289,59 @@ export function LayoutVisual({ active }: { active: boolean }) { {i18n._(LAYOUT_EDITOR_CONTENT.sectionLabels[section])} + + + - {sectionNumber === 0 ? ( - - {i18n._(msg`Industry`)} - {i18n._(msg`Done`)} - - ) : null} - {fields .filter((field) => field.section === section) - .map((field) => ( - - handleDragStart(field.id, event) - } - > - - - - - {i18n._(field.label)} - · - {i18n._(field.type)} - - { - event.stopPropagation(); - toggleVisibility(field.id); - }} + .map((field, fieldNumber) => { + const isEditing = + sectionNumber === 0 && fieldNumber === 0; + + return ( + handleDragStart(field.id, event) + } > - - - - - - - ))} + + + + {isEditing ? ( + + {i18n._(msg`General`)} + {i18n._(msg`Done`)} + + ) : ( + + {i18n._(field.label)} + · + {i18n._(field.type)} + + )} + { + event.stopPropagation(); + toggleVisibility(field.id); + }} + > + + + + + + + ); + })} {sectionNumber > 0 && sectionNumber < sections.length - 1 ? ( @@ -327,17 +354,24 @@ export function LayoutVisual({ active }: { active: boolean }) { ))} - - - - - - {i18n._(msg`New fields`)} - + + + + + + {i18n._(msg`New fields`)} + · + {i18n._(msg`Default position/visibility for field…`)} - - - + + + + + + + + + diff --git a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/LayoutIcons.tsx b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/LayoutIcons.tsx index 3c4976d69a..f5a7aa7612 100644 --- a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/LayoutIcons.tsx +++ b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/LayoutIcons.tsx @@ -2,8 +2,8 @@ import { IconBuildingSkyscraper, IconCalendar, IconCheckbox, + IconChevronDown, IconChevronLeft, - IconCurrencyDollar, IconDotsVertical, IconEye, IconEyeOff, @@ -13,8 +13,10 @@ import { IconLink, IconList, IconMapPin, + IconMoneybag, + IconNewSection, IconNotes, - IconPlus, + IconRowInsertBottom, IconSettingsAutomation, IconSparkles, IconTargetArrow, @@ -35,7 +37,7 @@ const FIELD_ICONS: Record = { calendar: IconCalendar, link: IconLink, map: IconMapPin, - money: IconCurrencyDollar, + money: IconMoneybag, target: IconTargetArrow, user: IconUserCircle, users: IconUsers, @@ -71,6 +73,10 @@ function EyeGlyph({ visible }: { visible: boolean }) { ); } +function ChevronDownGlyph() { + return ; +} + function ChevronLeftGlyph() { return ; } @@ -92,14 +98,15 @@ function SparkGlyph() { } function NewSectionGlyph() { - return ; + return ; } -function PlusGlyph() { - return ; +function NewFieldsGlyph() { + return ; } export const LAYOUT_GLYPHS = { + ChevronDown: ChevronDownGlyph, ChevronLeft: ChevronLeftGlyph, Dots: DotsGlyph, Eye: EyeGlyph, @@ -107,7 +114,7 @@ export const LAYOUT_GLYPHS = { Grip: GripGlyph, List: ListGlyph, Nav: NavGlyph, + NewFields: NewFieldsGlyph, NewSection: NewSectionGlyph, - Plus: PlusGlyph, Spark: SparkGlyph, }; diff --git a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/layout-chrome.ts b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/layout-chrome.ts index 46774a4bdd..0b6a3f2066 100644 --- a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/layout-chrome.ts +++ b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/components/layout-chrome.ts @@ -7,18 +7,26 @@ const layout = PRODUCT_STEPPER_SCENE.layout; const PANEL_RADIUS = '3px'; +const PANEL_SHADOW = layout.panelShadow; + +const PANEL_SHADOW_MEDIUM = layout.panelShadowMedium; + +const PANEL_SHADOW_ELEVATED = layout.panelShadowElevated; + const WidgetPanel = styled.div` backdrop-filter: blur(5px); background: ${shell.cardBackground}; border: 0.8px solid ${layout.accent}; border-radius: ${PANEL_RADIUS}; - left: 48%; + box-shadow: ${PANEL_SHADOW_MEDIUM}; + left: 42%; max-height: 36%; overflow: hidden; padding: 6px; position: absolute; top: 13%; width: 38%; + z-index: 2; `; const WidgetInner = styled.div` @@ -28,9 +36,12 @@ const WidgetInner = styled.div` `; const WidgetSectionLabel = styled.div` + align-items: center; color: ${shell.textTertiary}; + display: flex; font-size: 7px; font-weight: 600; + justify-content: space-between; padding: 0 3px; `; @@ -72,6 +83,15 @@ const WidgetValue = styled.span` white-space: nowrap; `; +const WidgetAvatar = styled.img` + border-radius: 50%; + height: 12px; + margin-right: 4px; + object-fit: cover; + vertical-align: middle; + width: 12px; +`; + const WidgetChip = styled.span` background: ${layout.chipWash}; border: 0.5px solid ${shell.borderStrong}; @@ -86,13 +106,15 @@ const NavPanel = styled.div` background: ${shell.cardBackground}; border: 0.8px solid ${layout.accent}; border-radius: ${PANEL_RADIUS}; - left: 8%; + box-shadow: ${PANEL_SHADOW}; + left: 14%; max-height: 68%; overflow-y: auto; padding: 8px; position: absolute; top: 13%; width: 30%; + z-index: 1; `; const NavSectionLabel = styled.div` @@ -163,12 +185,14 @@ const ActionsBar = styled.div` background: ${shell.cardBackground}; border: 0.8px solid ${layout.accent}; border-radius: ${PANEL_RADIUS}; + box-shadow: ${PANEL_SHADOW}; display: flex; gap: 5px; - left: 46%; + left: 44%; padding: 5px 6px; position: absolute; top: 6%; + transform: translateX(-50%); z-index: 3; `; @@ -187,12 +211,13 @@ const RightPanel = styled.div` border: 0.8px solid ${layout.panelAccent}; border-radius: ${PANEL_RADIUS}; bottom: 3%; + box-shadow: ${PANEL_SHADOW_ELEVATED}; display: flex; flex-direction: column; left: 42%; overflow: hidden; position: absolute; - top: 36%; + top: 38%; width: 54%; z-index: 4; `; @@ -240,14 +265,6 @@ const PanelTitleBold = styled.span` font-weight: 600; `; -const PanelTitleSub = styled.span` - color: ${shell.textTertiary}; - font-size: 8px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - const PanelSubBar = styled.div` align-items: center; border-bottom: 0.8px solid ${shell.borderLight}; @@ -285,21 +302,25 @@ const SectionName = styled.span` font-weight: 600; `; -const EditableRow = styled.div` +const EditGroup = styled.span` align-items: center; + display: flex; + gap: 4px; + margin-right: auto; + min-width: 0; +`; + +const EditField = styled.span` background: white; border: 1px solid ${layout.accent}; border-radius: ${PANEL_RADIUS}; - display: flex; - gap: 4px; - margin: 2px 0 4px; - padding: 4px 6px; -`; - -const EditableText = styled.span` color: ${shell.text}; - flex: 1; - font-size: 9px; + font-size: 8px; + overflow: hidden; + padding: 3px 6px; + text-overflow: ellipsis; + white-space: nowrap; + width: 120px; `; const DoneButton = styled.span` @@ -329,6 +350,11 @@ const FieldRow = styled.div` &:active { cursor: grabbing; } + + &[data-editing], + &[data-static] { + cursor: default; + } `; const FieldIconBox = styled.span` @@ -396,30 +422,6 @@ const AddText = styled.span` font-size: 8px; `; -const NewFieldsRow = styled.div` - align-items: center; - border-top: 0.8px solid ${shell.borderMedium}; - display: flex; - gap: 5px; - margin-top: 4px; - padding: 6px 3px 3px; -`; - -const NewFieldsColumn = styled.div` - display: flex; - flex-direction: column; -`; - -const NewFieldsTitle = styled.span` - color: ${shell.textSecondary}; - font-size: 8px; -`; - -const NewFieldsDescription = styled.span` - color: ${shell.textTertiary}; - font-size: 7px; -`; - export const LAYOUT_CHROME = { ActionButton, ActionsBar, @@ -427,8 +429,8 @@ export const LAYOUT_CHROME = { AddSectionRow, AddText, DoneButton, - EditableRow, - EditableText, + EditField, + EditGroup, FieldDot, FieldIconBox, FieldLabels, @@ -442,10 +444,6 @@ export const LAYOUT_CHROME = { NavPanel, NavSectionLabel, NavSubItem, - NewFieldsColumn, - NewFieldsDescription, - NewFieldsRow, - NewFieldsTitle, PanelActionButton, PanelBackButton, PanelFields, @@ -455,10 +453,10 @@ export const LAYOUT_CHROME = { PanelSubLabel, PanelTitleBold, PanelTitleGroup, - PanelTitleSub, RightPanel, SectionName, SectionRow, + WidgetAvatar, WidgetChip, WidgetIcon, WidgetInner, diff --git a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/data/layout-data.ts b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/data/layout-data.ts index b81df635f6..2d2377e810 100644 --- a/packages/twenty-website/src/sections/product-stepper/LayoutVisual/data/layout-data.ts +++ b/packages/twenty-website/src/sections/product-stepper/LayoutVisual/data/layout-data.ts @@ -38,7 +38,7 @@ export const LAYOUT_EDITOR_CONTENT: { id: 'icp', icon: 'target', label: msg`ICP`, - type: msg`True/False`, + type: msg`Boolean`, section: 'Additional', visible: false, }, @@ -62,7 +62,7 @@ export const LAYOUT_EDITOR_CONTENT: { id: 'creation-date', icon: 'calendar', label: msg`Creation date`, - type: msg`Date and Time`, + type: msg`Date & Time`, section: 'Other', visible: true, }, diff --git a/packages/twenty-website/src/tokens/feature-scenes/product-stepper-scene.ts b/packages/twenty-website/src/tokens/feature-scenes/product-stepper-scene.ts index 895b315430..107eeb5710 100644 --- a/packages/twenty-website/src/tokens/feature-scenes/product-stepper-scene.ts +++ b/packages/twenty-website/src/tokens/feature-scenes/product-stepper-scene.ts @@ -63,6 +63,10 @@ export const PRODUCT_STEPPER_SCENE = { fieldInk: FICTION_PALETTE.inkMuted, eyeInk: FICTION_PALETTE.inkFaint, eyeHiddenInk: FICTION_PALETTE.inkDisabled, + panelShadow: '0 4px 16px rgba(0, 0, 0, 0.32)', + panelShadowMedium: '0 8px 28px rgba(0, 0, 0, 0.42)', + panelShadowElevated: + '0 12px 44px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3)', }, cardShadow: '0 0 2px rgba(0, 0, 0, 0.08), 0 2px 2px rgba(0, 0, 0, 0.04)', nodeShadow: '0 0 2px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04)',