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 ff408eb407..e9487ea6eb 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 0000000000..59e1acf479 --- /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 0000000000..5544a7801a --- /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 d8d7f14907..266e1a4454 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 70660329bd..8fe9782442 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 0000000000..63f25794bd --- /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 8a9ced3eb0..f37c5c5cb3 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 0de4d60257..37c6051855 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 b34fc8b7ac..73c2f372e1 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 50ce4ed693..9aecee3e61 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 6de7cd5526..1546fd30a3 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 9550dac39b..506b186e7c 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 556e1e9845..b17b50a237 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 ff3fc98580..66cbddd5ed 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 942e8865b5..5bcfd65d67 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 8a87fd63c5..9cf9df75ce 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 5a206e88b7..0000000000 --- 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 349c9cfe3e..c66767a090 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 f19e3efaf6..87bee383cb 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 d4e5c2e79f..97d4560694 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 724b80e461..186f54b691 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,