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 <bordeau.lucas@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Mohamed Dilshad
2024-10-16 18:03:54 +05:30
committed by GitHub
parent 082c614013
commit 720fe32809
24 changed files with 258 additions and 163 deletions

View File

@ -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<HTMLDivElement>(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={() => {}}
>
<StyledWrapper>
<StyledBoardHeader />
<ScrollWrapper contextProviderName="recordBoard">
<StyledContainer ref={boardRef}>
<DragDropContext onDragEnd={onDragEnd}>
{columnIds.map((columnId) => (
<RecordBoardColumn
key={columnId}
recordBoardColumnId={columnId}
/>
))}
</DragDropContext>
</StyledContainer>
<RecordBoardScrollRestoreEffect />
</ScrollWrapper>
<DragSelect
dragSelectable={boardRef}
onDragSelectionStart={resetRecordSelection}
onDragSelectionChange={setRecordAsSelected}
/>
</StyledWrapper>
<ScrollWrapper contextProviderName="recordBoard">
<RecordBoardStickyHeaderEffect />
<StyledContainerContainer>
<RecordBoardHeader />
<StyledBoardContentContainer>
<StyledContainer ref={boardRef}>
<DragDropContext onDragEnd={handleDragEnd}>
<StyledColumnContainer>
{columnIds.map((columnId) => (
<RecordBoardColumn
key={columnId}
recordBoardColumnId={columnId}
/>
))}
</StyledColumnContainer>
</DragDropContext>
</StyledContainer>
<RecordBoardScrollRestoreEffect />
<DragSelect
dragSelectable={boardRef}
onDragSelectionStart={resetRecordSelection}
onDragSelectionChange={setRecordAsSelected}
/>
</StyledBoardContentContainer>
</StyledContainerContainer>
</ScrollWrapper>
</RecordBoardScope>
);
};

View File

@ -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 (
<StyledHeaderContainer id="record-board-header">
{columnIds.map((columnId) => (
<RecordBoardColumnHeaderWrapper columnId={columnId} />
))}
</StyledHeaderContainer>
);
};

View File

@ -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 <></>;
};

View File

@ -16,6 +16,7 @@ type RecordBoardContextProps = {
updateOneRecordInput: Partial<Omit<ObjectRecord, 'id'>>;
}) => void;
deleteOneRecord: (idToDelete: string) => Promise<unknown>;
recordBoardId: string;
};
export const RecordBoardContext = createContext<RecordBoardContextProps>(

View File

@ -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,
}}
>
<Droppable droppableId={recordBoardColumnId}>
{(droppableProvided) => (
<StyledColumn isFirstColumn={isFirstColumn}>
<RecordBoardColumnHeader />
<RecordBoardColumnCardsContainer
droppableProvided={droppableProvided}
recordIds={recordIds}

View File

@ -21,7 +21,6 @@ const StyledHeader = styled.div`
display: flex;
flex-direction: row;
justify-content: left;
margin-bottom: ${({ theme }) => 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 (
<>
<StyledColumn isFirstColumn={isFirstColumn}>
<StyledHeader
onMouseEnter={() => setIsHeaderHovered(true)}
onMouseLeave={() => setIsHeaderHovered(false)}
@ -181,6 +198,6 @@ export const RecordBoardColumnHeader = () => {
position="first"
/>
))}
</>
</StyledColumn>
);
};

View File

@ -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 (
<RecordBoardColumnContext.Provider
value={{
columnId,
columnDefinition: columnDefinition,
isFirstColumn: isFirstColumn,
isLastColumn: isLastColumn,
recordCount: recordIds.length,
recordIds,
}}
>
<RecordBoardColumnHeader />
</RecordBoardColumnContext.Provider>
);
};

View File

@ -7,6 +7,8 @@ type RecordBoardColumnContextProps = {
isFirstColumn: boolean;
isLastColumn: boolean;
recordCount: number;
columnId: string;
recordIds: string[];
};
export const RecordBoardColumnContext =

View File

@ -12,6 +12,7 @@ type RecordBoardScopeProps = {
onColumnsChange: (column: RecordBoardColumnDefinition[]) => void;
};
/** @deprecated */
export const RecordBoardScope = ({
children,
recordBoardScopeId,

View File

@ -46,9 +46,10 @@ export const RecordIndexBoardContainer = ({
createOneRecord,
updateOneRecord,
deleteOneRecord,
recordBoardId,
}}
>
<RecordBoard recordBoardId={recordBoardId} />
<RecordBoard />
</RecordBoardContext.Provider>
);
};

View File

@ -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 = () => {
>
<RecordFieldValueSelectorContextProvider>
<SpreadsheetImportProvider>
<StyledContainerWithPadding>
<ViewBar
viewBarId={recordIndexId}
optionsDropdownButton={
<RecordIndexOptionsDropdown
recordIndexId={recordIndexId}
objectNameSingular={objectNameSingular}
viewType={recordIndexViewType ?? ViewType.Table}
/>
<ViewBar
viewBarId={recordIndexId}
optionsDropdownButton={
<RecordIndexOptionsDropdown
recordIndexId={recordIndexId}
objectNameSingular={objectNameSingular}
viewType={recordIndexViewType ?? ViewType.Table}
/>
}
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);
}}
/>
<RecordIndexViewBarEffect
objectNamePlural={objectNamePlural}
viewBarId={recordIndexId}
/>
</StyledContainerWithPadding>
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);
}}
/>
<RecordIndexViewBarEffect
objectNamePlural={objectNamePlural}
viewBarId={recordIndexId}
/>
</SpreadsheetImportProvider>
{recordIndexViewType === ViewType.Table && (
<>
<RecordIndexTableContainer
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
<RecordIndexTableContainerEffect
objectNameSingular={objectNameSingular}
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
<RecordIndexTableContainerEffect />
</>
)}
{recordIndexViewType === ViewType.Kanban && (
<StyledContainerWithPadding fullHeight>
<StyledContainerWithPadding>
<RecordIndexBoardContainer
recordBoardId={recordIndexId}
viewBarId={recordIndexId}

View File

@ -1,26 +1,23 @@
import { useEffect } from 'react';
import { useContext, useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState';
import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter';
import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView';
type RecordIndexTableContainerEffectProps = {
objectNameSingular: string;
recordTableId: string;
viewBarId: string;
};
export const RecordIndexTableContainerEffect = () => {
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(

View File

@ -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;
};

View File

@ -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');

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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<boolean>({
key: 'isRecordTableScrolledTopComponentState',
componentContext: RecordTableScopeInternalContext,
defaultValue: true,
});

View File

@ -53,7 +53,7 @@ export const TabList = ({
return (
<TabListScope tabListScopeId={tabListId}>
<ScrollWrapper hideY contextProviderName="tabList">
<ScrollWrapper enableYScroll={false} contextProviderName="tabList">
<StyledContainer className={className}>
{tabs
.filter((tab) => !tab.hide)

View File

@ -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) => (
<StyledContainer className={className}>
<StyledTopBar displayBottomBorder={displayBottomBorder}>
<StyledTopBar>
<StyledLeftSection>{leftComponent}</StyledLeftSection>
<StyledRightSection>{rightComponent}</StyledRightSection>
</StyledTopBar>

View File

@ -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<HTMLDivElement>(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: {

View File

@ -60,7 +60,6 @@ export const ViewBar = ({
leftComponent={
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
}
displayBottomBorder={false}
rightComponent={
<>
<ObjectFilterDropdownButton

View File

@ -61,6 +61,7 @@ export const RecordIndexPage = () => {
recordIndexId,
objectNamePlural,
objectNameSingular,
objectMetadataItem,
onIndexRecordsLoaded: handleIndexRecordsLoaded,
onIndexIdentifierClick: handleIndexIdentifierClick,
onCreateRecord: handleCreateRecord,