diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/ChipFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/ChipFieldDisplay.tsx index 4b921623d1..f681a6731d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/ChipFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/ChipFieldDisplay.tsx @@ -1,8 +1,9 @@ import { RecordChip } from '@/object-record/components/RecordChip'; import { useChipFieldDisplay } from '@/object-record/record-field/ui/meta-types/hooks/useChipFieldDisplay'; +import { shouldCompactRecordIndexLabelIdentifierComponentState } from '@/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { isDefined } from 'twenty-shared/utils'; import { ChipSize } from 'twenty-ui/components'; -import { useIsMobile } from 'twenty-ui/utilities'; export const ChipFieldDisplay = () => { const { @@ -15,10 +16,11 @@ export const ChipFieldDisplay = () => { onRecordChipClick, } = useChipFieldDisplay(); - const isMobile = useIsMobile(); + const shouldCompactRecordIndexLabelIdentifier = useRecoilComponentValue( + shouldCompactRecordIndexLabelIdentifierComponentState, + ); - // TODO: reimplement scrolled horizontally here. - const isLabelIdentifierCompact = isMobile; + const isLabelIdentifierCompact = shouldCompactRecordIndexLabelIdentifier; if (!isDefined(recordValue)) { return null; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx index 3a13d453ec..990c159556 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx @@ -8,6 +8,7 @@ import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { ComponentDecorator } from 'twenty-ui/testing'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; @@ -16,6 +17,7 @@ import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockO const meta: Meta = { title: 'UI/Data/Field/Display/ChipFieldDisplay', decorators: [ + ContextStoreDecorator, (Story) => { const instanceId = 'child-field-display-scope'; diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts new file mode 100644 index 0000000000..795895336d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState.ts @@ -0,0 +1,9 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const shouldCompactRecordIndexLabelIdentifierComponentState = + createComponentState({ + key: 'shouldCompactRecordIndexLabelIdentifierComponentState', + componentInstanceContext: ContextStoreComponentInstanceContext, + defaultValue: false, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx index 78798ad02d..e0065981b9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableColumnWidthEffect.tsx @@ -1,11 +1,21 @@ +import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidth'; +import { RECORD_TABLE_COLUMN_CHECKBOX_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnCheckboxWidth'; +import { RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnDragAndDropWidth'; import { RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnLastEmptyColumnWidthVariableName'; +import { RECORD_TABLE_COLUMN_MIN_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnMinWidth'; import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthVariableName'; +import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-record/record-table/constants/RecordTableLabelIdentifierColumnWidthOnMobile'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecordTableLastColumnWidthToFill } from '@/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill'; +import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; +import { computeLastRecordTableColumnWidth } from '@/object-record/record-table/utils/computeLastRecordTableColumnWidth'; +import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable'; import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName'; import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable'; +import { RECORD_TABLE_VIRTUALIZATION_BODY_PLACEHOLDER_WIDTH_CSS_VARIABLE_NAME } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -15,15 +25,47 @@ export const RecordTableColumnWidthEffect = () => { resizedFieldMetadataIdComponentState, ); - const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); - const { visibleRecordFields } = useRecordTableContextOrThrow(); + const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + shouldCompactRecordTableFirstColumnComponentState, + ); + + const recordTableWidth = useRecoilComponentValue( + recordTableWidthComponentState, + ); + useEffect(() => { if (isDefined(resizedFieldMetadataItemId)) { return; } + const { lastColumnWidth } = computeLastRecordTableColumnWidth({ + recordFields: visibleRecordFields, + shouldCompactFirstColumn: shouldCompactRecordTableFirstColumn, + tableWidth: recordTableWidth, + }); + + const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable( + { + shouldCompactFirstColumn: shouldCompactRecordTableFirstColumn, + visibleRecordFields, + }, + ); + + const totalTableBodyWidth = + visibleRecordFieldsWidth + + RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH + + RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH + + lastColumnWidth + + visibleRecordFields.length; + + updateRecordTableCSSVariable( + RECORD_TABLE_VIRTUALIZATION_BODY_PLACEHOLDER_WIDTH_CSS_VARIABLE_NAME, + `${totalTableBodyWidth}px`, + ); + updateRecordTableCSSVariable( RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME, `${lastColumnWidth}px`, @@ -40,7 +82,27 @@ export const RecordTableColumnWidthEffect = () => { `${recordField.size}px`, ); } - }, [lastColumnWidth, resizedFieldMetadataItemId, visibleRecordFields]); + + if (shouldCompactRecordTableFirstColumn) { + updateRecordTableCSSVariable( + getRecordTableColumnFieldWidthCSSVariableName(0), + `${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px`, + ); + } else { + const firstColumnWidth = + visibleRecordFields[0]?.size ?? RECORD_TABLE_COLUMN_MIN_WIDTH; + + updateRecordTableCSSVariable( + getRecordTableColumnFieldWidthCSSVariableName(0), + `${firstColumnWidth}px`, + ); + } + }, [ + resizedFieldMetadataItemId, + visibleRecordFields, + recordTableWidth, + shouldCompactRecordTableFirstColumn, + ]); return null; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx index 965fa5ee6e..cca2c04d4e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx @@ -4,7 +4,6 @@ import { RecordTableStyleWrapper } from '@/object-record/record-table/components import { RecordTableWidthEffect } from '@/object-record/record-table/components/RecordTableWidthEffect'; import { RECORD_TABLE_HTML_ID } from '@/object-record/record-table/constants/RecordTableHtmlId'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecordTableLastColumnWidthToFill } from '@/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill'; import { RecordTableNoRecordGroupBody } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody'; import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody'; import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader'; @@ -72,8 +71,6 @@ export const RecordTableContent = ({ const { visibleRecordFields } = useRecordTableContextOrThrow(); - const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); - const setRecordTableHoverPosition = useSetRecoilComponentState( recordTableHoverPositionComponentState, ); @@ -103,7 +100,6 @@ export const RecordTableContent = ({ ref={tableBodyRef} isDragging={isDragging} visibleRecordFields={visibleRecordFields} - lastColumnWidth={lastColumnWidth} id={RECORD_TABLE_HTML_ID} onMouseLeave={handleMouseLeave} hasRecordGroups={hasRecordGroups} diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx index 06358b144d..eb221d98d0 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx @@ -8,17 +8,16 @@ import { RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH } from '@/object-record/record- import { RECORD_TABLE_HTML_ID } from '@/object-record/record-table/constants/RecordTableHtmlId'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState'; -import { useRecordTableLastColumnWidthToFill } from '@/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill'; import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader'; import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { resizeFieldOffsetComponentState } from '@/object-record/record-table/states/resizeFieldOffsetComponentState'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable'; import { RecordTableVirtualizedDataChangedEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDataChangedEffect'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared/utils'; -import { useIsMobile } from 'twenty-ui/utilities'; const StyledEmptyStateContainer = styled.div<{ width: number }>` height: 100%; @@ -47,7 +46,9 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { const isResizing = isDefined(resizedFieldMetadataId); - const isMobile = useIsMobile(); + const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + shouldCompactRecordTableFirstColumnComponentState, + ); const resizeOffsetToAddOnlyIfItMakesTableContainerGrow = isResizing ? resizeFieldOffset > 0 @@ -58,12 +59,10 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { const totalColumnsBorderWidth = visibleRecordFields.length; const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable({ - isMobile, + shouldCompactFirstColumn: shouldCompactRecordTableFirstColumn, visibleRecordFields, }); - const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); - const emptyTableContainerComputedWidth = visibleRecordFieldsWidth + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH + @@ -86,7 +85,6 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx index ec6df71956..462d5962c1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableScrollAndZIndexEffect.tsx @@ -1,23 +1,35 @@ +import { shouldCompactRecordIndexLabelIdentifierComponentState } from '@/object-record/record-index/states/shouldCompactRecordIndexLabelIdentifierComponentState'; import { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableHorizontalScrollShadowVisibilityCssVariableName'; import { RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableVerticalScrollShadowVisibilityCssVariableName'; import { isRecordTableScrolledHorizontallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState'; import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable'; import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useEffect } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { useIsMobile } from 'twenty-ui/utilities'; export const RecordTableScrollAndZIndexEffect = () => { const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement(); - + const isMobile = useIsMobile(); const [ isRecordTableScrolledHorizontally, setIsRecordTableScrolledHorizontally, ] = useRecoilComponentState(isRecordTableScrolledHorizontallyComponentState); + const setShouldCompactRecordTableFirstColumn = useSetRecoilComponentState( + shouldCompactRecordTableFirstColumnComponentState, + ); + + const setShouldCompactRecordIndexLabelIdentifier = useSetRecoilComponentState( + shouldCompactRecordIndexLabelIdentifierComponentState, + ); + const [isRecordTableScrolledVertically, setIsRecordTableScrolledVertically] = useRecoilComponentState(isRecordTableScrolledVerticallyComponentState); @@ -57,6 +69,16 @@ export const RecordTableScrollAndZIndexEffect = () => { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME, newVisibilityOfShadows, ); + + if (isMobile) { + if (newIsScrolledHorizontally) { + setShouldCompactRecordTableFirstColumn(true); + setShouldCompactRecordIndexLabelIdentifier(true); + } else { + setShouldCompactRecordTableFirstColumn(false); + setShouldCompactRecordIndexLabelIdentifier(false); + } + } } }; @@ -71,6 +93,9 @@ export const RecordTableScrollAndZIndexEffect = () => { isRecordTableScrolledHorizontally, setIsRecordTableScrolledVertically, setIsRecordTableScrolledHorizontally, + isMobile, + setShouldCompactRecordTableFirstColumn, + setShouldCompactRecordIndexLabelIdentifier, ]); return <>; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx index b8027d34fd..1507f7b569 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx @@ -10,7 +10,6 @@ import { RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/obj import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_CLASS_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthClassName'; import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthVariableName'; import { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableHorizontalScrollShadowVisibilityCssVariableName'; -import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-record/record-table/constants/RecordTableLabelIdentifierColumnWidthOnMobile'; import { RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableVerticalScrollShadowVisibilityCssVariableName'; import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex'; @@ -18,7 +17,6 @@ import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record- import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName'; import { css, type Theme } from '@emotion/react'; import styled from '@emotion/styled'; -import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; export const VerticalScrollBoxShadowCSS = ({ theme }: { theme: Theme }) => css` &::before { @@ -64,7 +62,6 @@ export const HorizontalScrollBoxShadowCSS = ({ const StyledTable = styled.div<{ isDragging?: boolean; visibleRecordFields: RecordField[]; - lastColumnWidth: number; hasRecordGroups: boolean; }>` & > * { @@ -128,12 +125,6 @@ const StyledTable = styled.div<{ : TABLE_Z_INDEX.headerColumns.withoutGroups.headerColumnsSticky}; ${HorizontalScrollBoxShadowCSS} - - @media (max-width: ${MOBILE_VIEWPORT}px) { - width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - max-width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - min-width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - } } div.table-cell:nth-of-type(1) { @@ -192,7 +183,7 @@ const StyledTable = styled.div<{ max-width: ${RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH}px; } - ${({ visibleRecordFields, lastColumnWidth }) => { + ${({ visibleRecordFields }) => { let returnedCSS = ''; for (let i = 0; i < visibleRecordFields.length; i++) { @@ -200,28 +191,13 @@ const StyledTable = styled.div<{ } for (let i = 0; i < visibleRecordFields.length; i++) { - returnedCSS += `div.${getRecordTableColumnFieldWidthClassName(i)} { - width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); - min-width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); - max-width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); + returnedCSS += `div.${getRecordTableColumnFieldWidthClassName(i)} { + width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); + min-width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); + max-width: var(${getRecordTableColumnFieldWidthCSSVariableName(i)}); } \n`; - - const isLabelIdentifierColumn = i === 0; - - if (isLabelIdentifierColumn) { - returnedCSS += `div.${getRecordTableColumnFieldWidthClassName(i)} { - @media (max-width: ${MOBILE_VIEWPORT}px) { - width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - max-width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - min-width: ${RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE}px; - } - } \n`; - } } - returnedCSS += `${RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME}: ${lastColumnWidth}px;`; - returnedCSS += `${RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME}: ${lastColumnWidth}px;`; - return returnedCSS; }}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts index 40262ef2dc..bab0e5c406 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts @@ -1,8 +1,8 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; import { computeLastRecordTableColumnWidth } from '@/object-record/record-table/utils/computeLastRecordTableColumnWidth'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { useIsMobile } from 'twenty-ui/utilities'; export const useRecordTableLastColumnWidthToFill = () => { const { visibleRecordFields } = useRecordTableContextOrThrow(); @@ -11,12 +11,14 @@ export const useRecordTableLastColumnWidthToFill = () => { recordTableWidthComponentState, ); - const isMobile = useIsMobile(); + const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + shouldCompactRecordTableFirstColumnComponentState, + ); const { lastColumnWidth } = computeLastRecordTableColumnWidth({ recordFields: visibleRecordFields, tableWidth: recordTableWidth, - isMobile, + shouldCompactFirstColumn: shouldCompactRecordTableFirstColumn, }); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx index c6b6f0aa69..893304502c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHead.tsx @@ -4,6 +4,8 @@ import styled from '@emotion/styled'; import { fieldMetadataItemByIdSelector } from '@/object-metadata/states/fieldMetadataItemByIdSelector'; import { isFieldMetadataItemLabelIdentifierSelector } from '@/object-metadata/states/isFieldMetadataItemLabelIdentifierSelector'; import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useRecoilValue } from 'recoil'; import { useIcons } from 'twenty-ui/display'; import { MOBILE_VIEWPORT } from 'twenty-ui/theme'; @@ -69,10 +71,15 @@ export const RecordTableColumnHead = ({ }), ); - // TODO: fix previous behavior with isRecordTableScrolledHorizontally + const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + shouldCompactRecordTableFirstColumnComponentState, + ); + + const shouldHideTitle = + shouldCompactRecordTableFirstColumn && isLabelIdentifier; return ( - + diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts index b6822feb7a..9fbf61d0a1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts @@ -5,10 +5,12 @@ import { RECORD_TABLE_COLUMN_MIN_WIDTH } from '@/object-record/record-table/cons import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthVariableName'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection'; -import { useRecordTableLastColumnWidthToFill } from '@/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill'; +import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { resizeFieldOffsetComponentState } from '@/object-record/record-table/states/resizeFieldOffsetComponentState'; +import { shouldCompactRecordTableFirstColumnComponentState } from '@/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState'; +import { computeLastRecordTableColumnWidth } from '@/object-record/record-table/utils/computeLastRecordTableColumnWidth'; import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName'; import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; @@ -16,6 +18,7 @@ import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPoin import { type PointerEventListener } from '@/ui/utilities/pointer-event/types/PointerEventListener'; import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { useSaveRecordFields } from '@/views/hooks/useSaveRecordFields'; @@ -55,7 +58,13 @@ export const useResizeTableHeader = () => { const { updateRecordField } = useUpdateRecordField(); - const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); + const recordTableWidth = useRecoilComponentValue( + recordTableWidthComponentState, + ); + + const shouldCompactRecordTableFirstColumn = useRecoilComponentValue( + shouldCompactRecordTableFirstColumnComponentState, + ); const handleResizeHandlerStart = useCallback( ({ x }) => { @@ -90,6 +99,12 @@ export const useResizeTableHeader = () => { `${newWidth}px`, ); + const { lastColumnWidth } = computeLastRecordTableColumnWidth({ + recordFields: visibleRecordFields, + shouldCompactFirstColumn: shouldCompactRecordTableFirstColumn, + tableWidth: recordTableWidth, + }); + const newLastColumnWidth = lastColumnWidth - newResizeOffset; updateRecordTableCSSVariable( @@ -110,11 +125,12 @@ export const useResizeTableHeader = () => { setResizeFieldOffset(x - initialPointerPositionX); }, [ - setResizeFieldOffset, initialPointerPositionX, recordField, - lastColumnWidth, visibleRecordFields, + shouldCompactRecordTableFirstColumn, + recordTableWidth, + setResizeFieldOffset, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts new file mode 100644 index 0000000000..8d22de113c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/shouldCompactRecordTableFirstColumnComponentState.ts @@ -0,0 +1,9 @@ +import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const shouldCompactRecordTableFirstColumnComponentState = + createComponentState({ + key: 'shouldCompactRecordTableFirstColumnComponentState', + componentInstanceContext: RecordTableComponentInstanceContext, + defaultValue: false, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/utils/computeLastRecordTableColumnWidth.ts b/packages/twenty-front/src/modules/object-record/record-table/utils/computeLastRecordTableColumnWidth.ts index 3f43acdbd9..f738fce9e6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/utils/computeLastRecordTableColumnWidth.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/utils/computeLastRecordTableColumnWidth.ts @@ -7,14 +7,14 @@ import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-t export const computeLastRecordTableColumnWidth = ({ recordFields, tableWidth, - isMobile, + shouldCompactFirstColumn, }: { recordFields: Pick[]; tableWidth: number; - isMobile: boolean; + shouldCompactFirstColumn: boolean; }) => { const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable({ - isMobile, + shouldCompactFirstColumn, visibleRecordFields: recordFields, }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts b/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts index 935917bb76..401fec846e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts @@ -3,10 +3,10 @@ import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-r import { sumByProperty } from 'twenty-shared/utils'; export const computeVisibleRecordFieldsWidthOnTable = ({ - isMobile, + shouldCompactFirstColumn, visibleRecordFields, }: { - isMobile: boolean; + shouldCompactFirstColumn: boolean; visibleRecordFields: Pick[]; }) => { const visibleRecordFieldsWithoutFirst = visibleRecordFields.slice(1); @@ -18,12 +18,14 @@ export const computeVisibleRecordFieldsWidthOnTable = ({ const sumWithAllFields = visibleRecordFields.reduce(sumByProperty('size'), 0); - const sumForMobile = + const sumForCompactedFirstColumn = RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE + sumWithoutFirstField; - const sumForNonMobile = sumWithAllFields; + const sumForNoCompactColumn = sumWithAllFields; - const visibleRecordFieldsWidth = isMobile ? sumForMobile : sumForNonMobile; + const visibleRecordFieldsWidth = shouldCompactFirstColumn + ? sumForCompactedFirstColumn + : sumForNoCompactColumn; return { visibleRecordFieldsWidth, diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx index 553b397def..97ce5112c9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedBodyPlaceholder.tsx @@ -1,54 +1,30 @@ -import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidth'; -import { RECORD_TABLE_COLUMN_CHECKBOX_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnCheckboxWidth'; -import { RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnDragAndDropWidth'; import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; -import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecordTableLastColumnWidthToFill } from '@/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill'; -import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable'; import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; -import { useIsMobile } from 'twenty-ui/utilities'; + +export const RECORD_TABLE_VIRTUALIZATION_BODY_PLACEHOLDER_WIDTH_CSS_VARIABLE_NAME = + '--record-table-virtualization-body-placeholder-width'; const StyledVirtualizationContainer = styled.div<{ - width: number; height: number; }>` height: ${({ height }) => height}px; - width: ${({ width }) => width}px; + width: var( + ${RECORD_TABLE_VIRTUALIZATION_BODY_PLACEHOLDER_WIDTH_CSS_VARIABLE_NAME} + ); `; export const RecordTableVirtualizedBodyPlaceholder = () => { - const { visibleRecordFields } = useRecordTableContextOrThrow(); - - const isMobile = useIsMobile(); - - const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable({ - isMobile, - visibleRecordFields, - }); - const totalNumberOfRecordsToVirtualize = useRecoilComponentValue( totalNumberOfRecordsToVirtualizeComponentState, ); - const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); - - const totalWidth = - visibleRecordFieldsWidth + - RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + - RECORD_TABLE_COLUMN_CHECKBOX_WIDTH + - RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH + - lastColumnWidth + - visibleRecordFields.length; - const totalHeight = isDefined(totalNumberOfRecordsToVirtualize) ? totalNumberOfRecordsToVirtualize * (RECORD_TABLE_ROW_HEIGHT + 1) : 0; - return ( - - ); + return ; };