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
@@ -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>
);
};
@@ -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>
);
};
@@ -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 <></>;
};
@@ -16,6 +16,7 @@ type RecordBoardContextProps = {
updateOneRecordInput: Partial<Omit<ObjectRecord, 'id'>>;
}) => void;
deleteOneRecord: (idToDelete: string) => Promise<unknown>;
recordBoardId: string;
};
export const RecordBoardContext = createContext<RecordBoardContextProps>(
@@ -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}
@@ -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>
);
};
@@ -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>
);
};
@@ -7,6 +7,8 @@ type RecordBoardColumnContextProps = {
isFirstColumn: boolean;
isLastColumn: boolean;
recordCount: number;
columnId: string;
recordIds: string[];
};
export const RecordBoardColumnContext =
@@ -12,6 +12,7 @@ type RecordBoardScopeProps = {
onColumnsChange: (column: RecordBoardColumnDefinition[]) => void;
};
/** @deprecated */
export const RecordBoardScope = ({
children,
recordBoardScopeId,
@@ -46,9 +46,10 @@ export const RecordIndexBoardContainer = ({
createOneRecord,
updateOneRecord,
deleteOneRecord,
recordBoardId,
}}
>
<RecordBoard recordBoardId={recordBoardId} />
<RecordBoard />
</RecordBoardContext.Provider>
);
};
@@ -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}
@@ -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(
@@ -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;
};
@@ -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');
@@ -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) {
@@ -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;
@@ -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;
@@ -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};
@@ -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,
});
@@ -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)
@@ -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>
@@ -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: {
@@ -60,7 +60,6 @@ export const ViewBar = ({
leftComponent={
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
}
displayBottomBorder={false}
rightComponent={
<>
<ObjectFilterDropdownButton
@@ -61,6 +61,7 @@ export const RecordIndexPage = () => {
recordIndexId,
objectNamePlural,
objectNameSingular,
objectMetadataItem,
onIndexRecordsLoaded: handleIndexRecordsLoaded,
onIndexIdentifierClick: handleIndexIdentifierClick,
onCreateRecord: handleCreateRecord,