From 720fe32809d20acfe7cdc6afb8677d81232c63a3 Mon Sep 17 00:00:00 2001 From: Mohamed Dilshad <136896255+dilshad-knk@users.noreply.github.com> Date: Wed, 16 Oct 2024 18:03:54 +0530 Subject: [PATCH] Fixes #7105: Fixed column header on Kanban boards (#7263) Issue Reference: Fixes #7105 Description: This pull request introduces adjustments to the styling of the RecordBoardColumnHeader component. The modifications enhance the layout and visual consistency of the Kanban board headers. Changes Made: Margin Adjustment: Increased the bottom margin from theme.spacing(2) to theme.spacing(6) for better spacing below the header. Header Container Enhancements: Added a background color sourced from the theme (theme.background.primary) to the header container for improved visibility and aesthetics. Set a fixed height of 40px for the header to ensure a consistent size across different screens. Applied a fixed position to the header container to keep it visible at the top during scrolling. Added padding at the top using theme.spacing(2) for better alignment of content within the header. Before : https://github.com/user-attachments/assets/fd1c2d65-5e50-489a-a388-c0c4e1bd015b Now : [now.webm](https://github.com/user-attachments/assets/bd4cfb86-fc14-4902-b84c-99d27b07859e) --------- Co-authored-by: Lucas Bordeau Co-authored-by: Charles Bochet --- .../record-board/components/RecordBoard.tsx | 78 ++++++------ .../components/RecordBoardHeader.tsx | 34 ++++++ .../RecordBoardStickyHeaderEffect.tsx | 22 ++++ .../contexts/RecordBoardContext.ts | 1 + .../components/RecordBoardColumn.tsx | 9 +- .../components/RecordBoardColumnHeader.tsx | 33 +++-- .../RecordBoardColumnHeaderWrapper.tsx | 48 ++++++++ .../contexts/RecordBoardColumnContext.ts | 2 + .../record-board/scopes/RecordBoardScope.tsx | 1 + .../components/RecordIndexBoardContainer.tsx | 3 +- .../components/RecordIndexContainer.tsx | 113 ++++++++---------- .../RecordIndexTableContainerEffect.tsx | 21 ++-- .../contexts/RecordIndexRootPropsContext.ts | 2 + .../components/RecordTableBodyEffect.tsx | 7 +- .../components/RecordTableHeader.tsx | 5 +- .../components/RecordTableHeaderCell.tsx | 1 - .../RecordTableHeaderCheckboxColumn.tsx | 1 - .../RecordTableHeaderLastColumn.tsx | 1 - .../isRecordTableScrolledTopComponentState.ts | 9 -- .../ui/layout/tab/components/TabList.tsx | 2 +- .../src/modules/ui/layout/top-bar/TopBar.tsx | 14 ++- .../scroll/components/ScrollWrapper.tsx | 12 +- .../src/modules/views/components/ViewBar.tsx | 1 - .../pages/object-record/RecordIndexPage.tsx | 1 + 24 files changed, 258 insertions(+), 163 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx create mode 100644 packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx create mode 100644 packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index ff408eb40..e9487ea6e 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -4,6 +4,8 @@ import { useContext, useRef } from 'react'; import { useRecoilCallback, useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; +import { RecordBoardHeader } from '@/object-record/record-board/components/RecordBoardHeader'; +import { RecordBoardStickyHeaderEffect } from '@/object-record/record-board/components/RecordBoardStickyHeaderEffect'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection'; @@ -19,31 +21,26 @@ import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/get import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useScrollRestoration } from '~/hooks/useScrollRestoration'; -export type RecordBoardProps = { - recordBoardId: string; -}; - const StyledContainer = styled.div` - border-top: 1px solid ${({ theme }) => theme.border.color.light}; - overflow: auto; display: flex; flex: 1; flex-direction: row; min-height: calc(100% - 1px); + height: 100%; `; -const StyledWrapper = styled.div` +const StyledColumnContainer = styled.div` + display: flex; +`; + +const StyledContainerContainer = styled.div` display: flex; flex-direction: column; - height: 100%; - overflow: hidden; - position: relative; - width: 100%; `; -const StyledBoardHeader = styled.div` - position: relative; - z-index: 1; +const StyledBoardContentContainer = styled.div` + display: flex; + flex-direction: column; `; const RecordBoardScrollRestoreEffect = () => { @@ -51,8 +48,8 @@ const RecordBoardScrollRestoreEffect = () => { return null; }; -export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => { - const { updateOneRecord, selectFieldMetadataItem } = +export const RecordBoard = () => { + const { updateOneRecord, selectFieldMetadataItem, recordBoardId } = useContext(RecordBoardContext); const boardRef = useRef(null); @@ -75,7 +72,7 @@ export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => { useScopedHotkeys([Key.Escape], resetRecordSelection, TableHotkeyScope.Table); - const onDragEnd: OnDragEndResponder = useRecoilCallback( + const handleDragEnd: OnDragEndResponder = useRecoilCallback( ({ snapshot }) => (result) => { if (!result.destination) return; @@ -146,27 +143,32 @@ export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => { onColumnsChange={() => {}} onFieldsChange={() => {}} > - - - - - - {columnIds.map((columnId) => ( - - ))} - - - - - - + + + + + + + + + {columnIds.map((columnId) => ( + + ))} + + + + + + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx new file mode 100644 index 000000000..59e1acf47 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardHeader.tsx @@ -0,0 +1,34 @@ +import { useRecoilValue } from 'recoil'; + +import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; +import { RecordBoardColumnHeaderWrapper } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper'; +import styled from '@emotion/styled'; + +const StyledHeaderContainer = styled.div` + display: flex; + flex-direction: row; + height: 40px; + z-index: 10; + + overflow: visible; + width: 100%; + + &.header-sticky { + position: sticky; + top: 0; + } +`; + +export const RecordBoardHeader = () => { + const { columnIdsState } = useRecordBoardStates(); + + const columnIds = useRecoilValue(columnIdsState); + + return ( + + {columnIds.map((columnId) => ( + + ))} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx new file mode 100644 index 000000000..5544a7801 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx @@ -0,0 +1,22 @@ +import { useEffect } from 'react'; + +import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue'; + +export const RecordBoardStickyHeaderEffect = () => { + const scrollTop = useScrollTopValue('recordBoard'); + + // TODO: move this outside because it might cause way too many re-renders for other hooks + useEffect(() => { + if (scrollTop > 0) { + document + .getElementById('record-board-header') + ?.classList.add('header-sticky'); + } else { + document + .getElementById('record-board-header') + ?.classList.remove('header-sticky'); + } + }, [scrollTop]); + + return <>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardContext.ts b/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardContext.ts index d8d7f1490..266e1a445 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/contexts/RecordBoardContext.ts @@ -16,6 +16,7 @@ type RecordBoardContextProps = { updateOneRecordInput: Partial>; }) => void; deleteOneRecord: (idToDelete: string) => Promise; + recordBoardId: string; }; export const RecordBoardContext = createContext( diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx index 70660329b..8fe978244 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumn.tsx @@ -4,7 +4,6 @@ import { useRecoilValue } from 'recoil'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer'; -import { RecordBoardColumnHeader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeader'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; const StyledColumn = styled.div<{ isFirstColumn: boolean }>` @@ -18,7 +17,12 @@ const StyledColumn = styled.div<{ isFirstColumn: boolean }>` min-width: 200px; padding: ${({ theme }) => theme.spacing(2)}; + + padding-top: 0px; + position: relative; + + min-height: 100%; `; type RecordBoardColumnProps = { @@ -61,12 +65,13 @@ export const RecordBoardColumn = ({ isFirstColumn: isFirstColumn, isLastColumn: isLastColumn, recordCount: recordIds.length, + columnId: recordBoardColumnId, + recordIds, }} > {(droppableProvided) => ( - theme.spacing(2)}; width: 100%; `; @@ -45,6 +44,7 @@ const StyledHeaderActions = styled.div` margin-left: auto; `; const StyledHeaderContainer = styled.div` + background: ${({ theme }) => theme.background.primary}; display: flex; justify-content: space-between; width: 100%; @@ -59,13 +59,29 @@ const StyledRightContainer = styled.div` display: flex; `; +const StyledColumn = styled.div<{ isFirstColumn: boolean }>` + background-color: ${({ theme }) => theme.background.primary}; + border-left: 1px solid + ${({ theme, isFirstColumn }) => + isFirstColumn ? 'none' : theme.border.color.light}; + display: flex; + flex-direction: column; + max-width: 200px; + min-width: 200px; + + padding: ${({ theme }) => theme.spacing(2)}; + + position: relative; +`; + export const RecordBoardColumnHeader = () => { - const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] = useState(false); - const [isHeaderHovered, setIsHeaderHovered] = useState(false); - const { objectMetadataItem } = useContext(RecordBoardContext); - const { columnDefinition, recordCount } = useContext( + const { columnDefinition, isFirstColumn, recordCount } = useContext( RecordBoardColumnContext, ); + const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] = useState(false); + const [isHeaderHovered, setIsHeaderHovered] = useState(false); + + const { objectMetadataItem } = useContext(RecordBoardContext); const { setHotkeyScopeAndMemorizePreviousScope, @@ -94,7 +110,8 @@ export const RecordBoardColumnHeader = () => { handleNewButtonClick, handleCreateSuccess, handleEntitySelect, - } = useColumnNewCardActions(columnDefinition.id); + } = useColumnNewCardActions(columnDefinition?.id ?? ''); + const { isOpportunitiesCompanyFieldDisabled } = useIsOpportunitiesCompanyFieldDisabled(); @@ -103,7 +120,7 @@ export const RecordBoardColumnHeader = () => { !isOpportunitiesCompanyFieldDisabled; return ( - <> + setIsHeaderHovered(true)} onMouseLeave={() => setIsHeaderHovered(false)} @@ -181,6 +198,6 @@ export const RecordBoardColumnHeader = () => { position="first" /> ))} - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx new file mode 100644 index 000000000..63f25794b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper.tsx @@ -0,0 +1,48 @@ +import { isDefined } from 'twenty-ui'; + +import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; +import { RecordBoardColumnHeader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeader'; +import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; +import { useRecoilValue } from 'recoil'; + +type RecordBoardColumnHeaderWrapperProps = { + columnId: string; +}; + +export const RecordBoardColumnHeaderWrapper = ({ + columnId, +}: RecordBoardColumnHeaderWrapperProps) => { + const { + isFirstColumnFamilyState, + isLastColumnFamilyState, + columnsFamilySelector, + recordIdsByColumnIdFamilyState, + } = useRecordBoardStates(); + + const columnDefinition = useRecoilValue(columnsFamilySelector(columnId)); + + const isFirstColumn = useRecoilValue(isFirstColumnFamilyState(columnId)); + + const isLastColumn = useRecoilValue(isLastColumnFamilyState(columnId)); + + const recordIds = useRecoilValue(recordIdsByColumnIdFamilyState(columnId)); + + if (!isDefined(columnDefinition)) { + return null; + } + + return ( + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext.ts index 8a9ced3eb..f37c5c5cb 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext.ts @@ -7,6 +7,8 @@ type RecordBoardColumnContextProps = { isFirstColumn: boolean; isLastColumn: boolean; recordCount: number; + columnId: string; + recordIds: string[]; }; export const RecordBoardColumnContext = diff --git a/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx b/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx index 0de4d6025..37c605185 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/scopes/RecordBoardScope.tsx @@ -12,6 +12,7 @@ type RecordBoardScopeProps = { onColumnsChange: (column: RecordBoardColumnDefinition[]) => void; }; +/** @deprecated */ export const RecordBoardScope = ({ children, recordBoardScopeId, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx index b34fc8b7a..73c2f372e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx @@ -46,9 +46,10 @@ export const RecordIndexBoardContainer = ({ createOneRecord, updateOneRecord, deleteOneRecord, + recordBoardId, }} > - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index 50ce4ed69..9aecee3e6 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -2,8 +2,6 @@ import styled from '@emotion/styled'; import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer'; import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader'; import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect'; @@ -45,12 +43,13 @@ const StyledContainer = styled.div` flex-direction: column; height: 100%; width: 100%; - overflow: auto; + + overflow: hidden; `; -const StyledContainerWithPadding = styled.div<{ fullHeight?: boolean }>` - height: ${({ fullHeight }) => (fullHeight ? '100%' : 'auto')}; - padding-left: ${({ theme }) => theme.table.horizontalCellPadding}; +const StyledContainerWithPadding = styled.div` + height: calc(100% - 40px); + width: 100%; `; export const RecordIndexContainer = () => { @@ -58,17 +57,12 @@ export const RecordIndexContainer = () => { recordIndexViewTypeState, ); - const { objectNamePlural, recordIndexId } = useContext( - RecordIndexRootPropsContext, - ); - - const { objectNameSingular } = useObjectNameSingularFromPlural({ + const { objectNamePlural, - }); - - const { objectMetadataItem } = useObjectMetadataItem({ + recordIndexId, + objectMetadataItem, objectNameSingular, - }); + } = useContext(RecordIndexRootPropsContext); const { columnDefinitions, filterDefinitions, sortDefinitions } = useColumnDefinitionsFromFieldMetadata(objectMetadataItem); @@ -120,69 +114,56 @@ export const RecordIndexContainer = () => { > - - + + } + onCurrentViewChange={(view) => { + if (!view) { + return; } - onCurrentViewChange={(view) => { - if (!view) { - return; - } - onViewFieldsChange(view.viewFields); - setTableFilters( - mapViewFiltersToFilters( - view.viewFilters, - filterDefinitions, - ), - ); - setRecordIndexFilters( - mapViewFiltersToFilters( - view.viewFilters, - filterDefinitions, - ), - ); - setTableSorts( - mapViewSortsToSorts(view.viewSorts, sortDefinitions), - ); - setRecordIndexSorts( - mapViewSortsToSorts(view.viewSorts, sortDefinitions), - ); - setRecordIndexViewType(view.type); - setRecordIndexViewKanbanFieldMetadataIdState( - view.kanbanFieldMetadataId, - ); - setRecordIndexIsCompactModeActive(view.isCompact); - }} - /> - - + onViewFieldsChange(view.viewFields); + setTableFilters( + mapViewFiltersToFilters(view.viewFilters, filterDefinitions), + ); + setRecordIndexFilters( + mapViewFiltersToFilters(view.viewFilters, filterDefinitions), + ); + setTableSorts( + mapViewSortsToSorts(view.viewSorts, sortDefinitions), + ); + setRecordIndexSorts( + mapViewSortsToSorts(view.viewSorts, sortDefinitions), + ); + setRecordIndexViewType(view.type); + setRecordIndexViewKanbanFieldMetadataIdState( + view.kanbanFieldMetadataId, + ); + setRecordIndexIsCompactModeActive(view.isCompact); + }} + /> + - {recordIndexViewType === ViewType.Table && ( <> - + )} {recordIndexViewType === ViewType.Kanban && ( - + { + const { recordIndexId, objectNameSingular } = useContext( + RecordIndexRootPropsContext, + ); + + const viewBarId = recordIndexId; -export const RecordIndexTableContainerEffect = ({ - objectNameSingular, - recordTableId, - viewBarId, -}: RecordIndexTableContainerEffectProps) => { const { setAvailableTableColumns, setOnEntityCountChange, @@ -28,7 +25,7 @@ export const RecordIndexTableContainerEffect = ({ setOnToggleColumnFilter, setOnToggleColumnSort, } = useRecordTable({ - recordTableId, + recordTableId: recordIndexId, }); const setContextStoreTargetedRecordIds = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexRootPropsContext.ts b/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexRootPropsContext.ts index 6de7cd552..1546fd30a 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexRootPropsContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/contexts/RecordIndexRootPropsContext.ts @@ -1,3 +1,4 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { createRootPropsContext } from '~/utils/createRootPropsContext'; export type RecordIndexRootPropsContextProps = { @@ -6,6 +7,7 @@ export type RecordIndexRootPropsContextProps = { onCreateRecord: () => void; objectNamePlural: string; objectNameSingular: string; + objectMetadataItem: ObjectMetadataItem; recordIndexId: string; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx index 9550dac39..506b186e7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx @@ -9,7 +9,6 @@ import { RecordTableContext } from '@/object-record/record-table/contexts/Record import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2'; import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; -import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { useScrollLeftValue } from '@/ui/utilities/scroll/hooks/useScrollLeftValue'; import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue'; @@ -41,16 +40,12 @@ export const RecordTableBodyEffect = () => { const tableLastRowVisible = useRecoilValue(tableLastRowVisibleState); const scrollTop = useScrollTopValue('recordTableWithWrappers'); - const setIsRecordTableScrolledTop = useSetRecoilComponentState( - isRecordTableScrolledTopComponentState, - ); const setHasRecordTableFetchedAllRecordsComponents = useSetRecoilComponentState(hasRecordTableFetchedAllRecordsComponentStateV2); // TODO: move this outside because it might cause way too many re-renders for other hooks useEffect(() => { - setIsRecordTableScrolledTop(scrollTop === 0); if (scrollTop > 0) { document .getElementById('record-table-header') @@ -60,7 +55,7 @@ export const RecordTableBodyEffect = () => { .getElementById('record-table-header') ?.classList.remove('header-sticky'); } - }, [scrollTop, setIsRecordTableScrolledTop]); + }, [scrollTop]); const scrollLeft = useScrollLeftValue('recordTableWithWrappers'); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx index 556e1e984..b17b50a23 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx @@ -8,10 +8,7 @@ import { RecordTableHeaderCheckboxColumn } from '@/object-record/record-table/re import { RecordTableHeaderDragDropColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderDragDropColumn'; import { RecordTableHeaderLastColumn } from '@/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn'; -const StyledTableHead = styled.thead<{ - isScrolledTop?: boolean; - isScrolledLeft?: boolean; -}>` +const StyledTableHead = styled.thead` cursor: pointer; th:nth-of-type(1) { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx index ff3fc9858..66cbddd5e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCell.tsx @@ -26,7 +26,6 @@ const StyledColumnHeaderCell = styled.th<{ isResizing?: boolean; }>` border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; color: ${({ theme }) => theme.font.color.tertiary}; padding: 0; text-align: left; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx index 942e8865b..5bcfd65d6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderCheckboxColumn.tsx @@ -17,7 +17,6 @@ const StyledColumnHeaderCell = styled.th` background-color: ${({ theme }) => theme.background.primary}; border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; border-right: transparent; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; max-width: 30px; min-width: 30px; width: 30px; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx index 8a87fd63c..9cf9df75c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLastColumn.tsx @@ -22,7 +22,6 @@ const StyledPlusIconHeaderCell = styled.th<{ `; }}; border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - border-top: 1px solid ${({ theme }) => theme.border.color.light}; background-color: ${({ theme }) => theme.background.primary}; border-left: none !important; color: ${({ theme }) => theme.font.color.tertiary}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts deleted file mode 100644 index 5a206e88b..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/states/isRecordTableScrolledTopComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext'; -import { createComponentStateV2_alpha } from '@/ui/utilities/state/component-state/utils/createComponentStateV2_alpha'; - -export const isRecordTableScrolledTopComponentState = - createComponentStateV2_alpha({ - key: 'isRecordTableScrolledTopComponentState', - componentContext: RecordTableScopeInternalContext, - defaultValue: true, - }); diff --git a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx index 349c9cfe3..c66767a09 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx @@ -53,7 +53,7 @@ export const TabList = ({ return ( - + {tabs .filter((tab) => !tab.hide) diff --git a/packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx b/packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx index f19e3efaf..87bee383c 100644 --- a/packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx +++ b/packages/twenty-front/src/modules/ui/layout/top-bar/TopBar.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from 'react'; import styled from '@emotion/styled'; +import { ReactNode } from 'react'; type TopBarProps = { className?: string; @@ -10,14 +10,15 @@ type TopBarProps = { }; const StyledContainer = styled.div` + border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`}; display: flex; + flex-direction: column; `; -const StyledTopBar = styled.div<{ displayBottomBorder: boolean }>` +const StyledTopBar = styled.div` align-items: center; - border-bottom: ${({ displayBottomBorder, theme }) => - displayBottomBorder ? `1px solid ${theme.border.color.light}` : 'none'}; + box-sizing: border-box; color: ${({ theme }) => theme.font.color.secondary}; display: flex; @@ -26,6 +27,8 @@ const StyledTopBar = styled.div<{ displayBottomBorder: boolean }>` height: 39px; justify-content: space-between; padding-right: ${({ theme }) => theme.spacing(2)}; + padding-left: ${({ theme }) => theme.spacing(2)}; + z-index: 7; `; @@ -44,10 +47,9 @@ export const TopBar = ({ leftComponent, rightComponent, bottomComponent, - displayBottomBorder = true, }: TopBarProps) => ( - + {leftComponent} {rightComponent} diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx index d4e5c2e79..97d456069 100644 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx @@ -26,16 +26,16 @@ const StyledScrollWrapper = styled.div` export type ScrollWrapperProps = { children: React.ReactNode; className?: string; - hideY?: boolean; - hideX?: boolean; + enableXScroll?: boolean; + enableYScroll?: boolean; contextProviderName: ContextProviderName; }; export const ScrollWrapper = ({ children, className, - hideX, - hideY, + enableXScroll = true, + enableYScroll = true, contextProviderName, }: ScrollWrapperProps) => { const scrollableRef = useRef(null); @@ -58,8 +58,8 @@ export const ScrollWrapper = ({ options: { scrollbars: { autoHide: 'scroll' }, overflow: { - y: hideY ? 'hidden' : undefined, - x: hideX ? 'hidden' : undefined, + x: enableXScroll ? undefined : 'hidden', + y: enableYScroll ? undefined : 'hidden', }, }, events: { diff --git a/packages/twenty-front/src/modules/views/components/ViewBar.tsx b/packages/twenty-front/src/modules/views/components/ViewBar.tsx index 724b80e46..186f54b69 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBar.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBar.tsx @@ -60,7 +60,6 @@ export const ViewBar = ({ leftComponent={ loading ? : } - displayBottomBorder={false} rightComponent={ <> { recordIndexId, objectNamePlural, objectNameSingular, + objectMetadataItem, onIndexRecordsLoaded: handleIndexRecordsLoaded, onIndexIdentifierClick: handleIndexIdentifierClick, onCreateRecord: handleCreateRecord,