diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx index 4a2b26f07f9..1ab02e37de5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderAddColumnButton.tsx @@ -5,7 +5,9 @@ import { HIDDEN_TABLE_COLUMN_DROPDOWN_ID } from '@/object-record/record-table/co import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidth'; import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH_CLASS_NAME } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidthClassName'; import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableHeaderPlusButtonContent } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderPlusButtonContent'; +import { RecordTableHeaderResizeHandler } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler'; import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowActiveComponentFamilyState'; import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; @@ -87,6 +89,8 @@ export const RecordTableHeaderAddColumnButton = () => { const shouldDisplayBorderBottom = hasRecordGroups || !isFirstRowActiveOrFocused || isScrolledVertically; + const { visibleRecordFields } = useRecordTableContextOrThrow(); + return ( { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH_CLASS_NAME, )} > + + - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCellContainer.tsx index 20f27d3973c..45cb8174e5f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCellContainer.tsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; const StyledHeaderCell = styled.div<{ zIndex?: number; shouldDisplayBorderBottom: boolean; + isResizing: boolean; }>` color: ${({ theme }) => theme.font.color.tertiary}; padding: 0; @@ -23,7 +24,11 @@ const StyledHeaderCell = styled.div<{ : 'none'}; user-select: none; - ${({ theme }) => { + ${({ theme, isResizing }) => { + if (isResizing) { + return ''; + } + return ` &:hover { background: ${theme.background.secondary}; @@ -34,7 +39,7 @@ const StyledHeaderCell = styled.div<{ `; }}; - cursor: pointer; + cursor: ${({ isResizing }) => (isResizing ? 'col-resize' : 'pointer')}; z-index: ${({ zIndex }) => zIndex ?? 'auto'}; `; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx index 5ef2dbeeff5..67e82ac8e17 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderFirstScrollableCell.tsx @@ -13,11 +13,12 @@ import { isRecordTableRowFocusActiveComponentState } from '@/object-record/recor import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledHorizontallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; +import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { cx } from '@linaria/core'; -import { filterOutByProperty } from 'twenty-shared/utils'; +import { filterOutByProperty, isDefined } from 'twenty-shared/utils'; export const RecordTableHeaderFirstScrollableCell = () => { const { objectMetadataItem, visibleRecordFields } = @@ -94,6 +95,12 @@ export const RecordTableHeaderFirstScrollableCell = () => { const shouldDisplayBorderBottom = hasRecordGroups || !isFirstRowActiveOrFocused || isScrolledVertically; + const resizedFieldMetadataItemId = useRecoilComponentValue( + resizedFieldMetadataIdComponentState, + ); + + const isResizingAnyColumn = isDefined(resizedFieldMetadataItemId); + if (!recordField) { return <>; } @@ -104,12 +111,14 @@ export const RecordTableHeaderFirstScrollableCell = () => { key={recordField.fieldMetadataItemId} shouldDisplayBorderBottom={shouldDisplayBorderBottom} zIndex={zIndex} + isResizing={isResizingAnyColumn} > + - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCell.tsx index ee69094abf5..57511d7a398 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCell.tsx @@ -13,12 +13,13 @@ import { isRecordTableRowActiveComponentFamilyState } from '@/object-record/reco import { isRecordTableRowFocusActiveComponentState } from '@/object-record/record-table/states/isRecordTableRowFocusActiveComponentState'; import { isRecordTableRowFocusedComponentFamilyState } from '@/object-record/record-table/states/isRecordTableRowFocusedComponentFamilyState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; +import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName'; import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { cx } from '@linaria/core'; import { useState } from 'react'; -import { findByProperty } from 'twenty-shared/utils'; +import { findByProperty, isDefined } from 'twenty-shared/utils'; const StyledColumnHeadContainer = styled.div` cursor: pointer; @@ -66,6 +67,12 @@ export const RecordTableHeaderLabelIdentifierCell = () => { hasRecordGroupsComponentSelector, ); + const resizedFieldMetadataItemId = useRecoilComponentValue( + resizedFieldMetadataIdComponentState, + ); + + const isResizingAnyColumn = isDefined(resizedFieldMetadataItemId); + const shouldDisplayBorderBottom = hasRecordGroups || !isFirstRowActiveOrFocused || isScrolledVertically; @@ -80,6 +87,7 @@ export const RecordTableHeaderLabelIdentifierCell = () => { onMouseEnter={() => setIconIsVisible(true)} onMouseLeave={() => setIconIsVisible(false)} shouldDisplayBorderBottom={shouldDisplayBorderBottom} + isResizing={isResizingAnyColumn} > { /> {iconIsVisible && } - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx index 8f585867e80..b3e2d5ef1b5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderResizeHandler.tsx @@ -1,21 +1,24 @@ import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; import styled from '@emotion/styled'; import { useIsMobile } from 'twenty-ui/utilities'; -const StyledResizeHandler = styled.div<{ isResizing: boolean }>` +const StyledResizeHandler = styled.div<{ + isResizing: boolean; + position: 'left' | 'right'; +}>` bottom: 0; cursor: col-resize; - padding: 0 ${({ theme }) => theme.spacing(2)}; position: absolute; - right: -9px; + ${({ position }) => (position === 'left' ? 'left: -1px;' : 'right: -1px;')} top: 0; - width: 3px; + width: 10px; z-index: 1; - ${({ isResizing, theme }) => { + ${({ isResizing, theme, position }) => { if (isResizing === true) { return `&:after { background-color: ${theme.color.blue}; @@ -23,7 +26,8 @@ const StyledResizeHandler = styled.div<{ isResizing: boolean }>` content: ''; display: block; position: absolute; - right: 8px; + ${position === 'left' ? 'left: -1px;' : 'right: -1px;'} + top: 0; width: 2px; }`; @@ -32,10 +36,19 @@ const StyledResizeHandler = styled.div<{ isResizing: boolean }>` `; export const RecordTableHeaderResizeHandler = ({ - recordField, + recordFieldIndex, + position, }: { - recordField: RecordField; + recordFieldIndex: number; + position: 'left' | 'right'; }) => { + const { visibleRecordFields } = useRecordTableContextOrThrow(); + + const recordField: RecordField | undefined = + position === 'left' + ? visibleRecordFields[recordFieldIndex - 1] + : visibleRecordFields[recordFieldIndex]; + const isMobile = useIsMobile(); const columnResizeDisabled = isMobile; @@ -44,13 +57,13 @@ export const RecordTableHeaderResizeHandler = ({ useRecoilComponentState(resizedFieldMetadataIdComponentState); const isResizing = - recordField.fieldMetadataItemId === resizedFieldMetadataItemId; + recordField?.fieldMetadataItemId === resizedFieldMetadataItemId; const { setDragSelectionStartEnabled } = useDragSelect(); const handlePointerDown = () => { setDragSelectionStartEnabled(false); - setResizedFieldMetadataItemId(recordField.fieldMetadataItemId); + setResizedFieldMetadataItemId(recordField?.fieldMetadataItemId); }; return ( @@ -60,6 +73,7 @@ export const RecordTableHeaderResizeHandler = ({ role="separator" onPointerDown={handlePointerDown} isResizing={isResizing} + position={position} /> ) );