From ef5b5013c5cd689638c34bdb03fc6cdab27b60dd Mon Sep 17 00:00:00 2001 From: Aleka Cheung Date: Fri, 12 Jan 2024 15:37:08 -0500 Subject: [PATCH] add collapsible table --- src/components/CollapsibleTable.tsx | 91 +++++++++++++++++++++++++++++ src/components/ContentSection.tsx | 1 - src/components/Table.tsx | 27 +++++++-- src/views/tables/FillsTable.tsx | 2 - 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 src/components/CollapsibleTable.tsx diff --git a/src/components/CollapsibleTable.tsx b/src/components/CollapsibleTable.tsx new file mode 100644 index 0000000..295f5e6 --- /dev/null +++ b/src/components/CollapsibleTable.tsx @@ -0,0 +1,91 @@ +import { Key, useState } from 'react'; +import styled, { type AnyStyledComponent, css } from 'styled-components'; + +import { STRING_KEYS } from '@/constants/localization'; + +import { useStringGetter } from '@/hooks'; +import { CaretIcon } from '@/icons'; + +import { Button } from './Button'; + +import { + Table, + type ElementProps as TableElementProps, + type StyleProps as TableStyleProps, +} from './Table'; + +type CollapsibleTableAdditionalProps = { + initialNumRowsToShow: number; +}; + +type CollapsibleTableProps< + TableRowData extends object, + TableRowKey extends Key +> = TableElementProps & + TableStyleProps & + CollapsibleTableAdditionalProps; + +export const CollapsibleTable = ({ + data = [], + initialNumRowsToShow, + + className, + ...tableProps +}: CollapsibleTableProps) => { + const [numRowsToShow, setNumRowsToShow] = useState(initialNumRowsToShow); + const stringGetter = useStringGetter(); + const showViewMoreButton = numRowsToShow !== undefined && numRowsToShow < data.length; + + return ( + + + {showViewMoreButton && ( + setNumRowsToShow(data.length)} + slotRight={} + > + {stringGetter({ key: STRING_KEYS.VIEW_MORE })} + + )} + + ); +}; + +const Styled: Record = {}; + +Styled.Container = styled.div` + display: grid; + grid-template-areas: 'table' 'viewmore'; + grid-template-rows: auto 1fr; +`; + +Styled.Table = styled(Table)<{ showViewMoreButton?: boolean }>` + grid-area: table; + + ${({ showViewMoreButton }) => + showViewMoreButton && + css` + table tbody tr:last-of-type { + box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color); + } + `} +`; + +Styled.ViewMoreButton = styled(Button)` + --button-backgroundColor: var(--color-layer-2); + --button-textColor: var(--color-text-1); + + width: 100%; + grid-area: viewmore; + + svg { + width: 0.675rem; + margin-left: 0.5ch; + } +`; diff --git a/src/components/ContentSection.tsx b/src/components/ContentSection.tsx index 3723841..7aa265f 100644 --- a/src/components/ContentSection.tsx +++ b/src/components/ContentSection.tsx @@ -11,6 +11,5 @@ export const DetachedScrollableSection = styled.section` export const AttachedExpandingSection = styled.section` ${layoutMixins.contentSectionAttached} - ${layoutMixins.expandingColumnWithHeader} gap: var(--border-width); `; diff --git a/src/components/Table.tsx b/src/components/Table.tsx index d82a94a..9573ccc 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -36,8 +36,6 @@ import { useAsyncList } from 'react-stately'; import { useBreakpoints } from '@/hooks'; import { MediaQueryKeys } from '@/hooks/useBreakpoints'; -import { Checkbox } from '@/components/Checkbox'; - import { breakpoints } from '@/styles'; import { layoutMixins } from '@/styles/layoutMixins'; @@ -80,7 +78,7 @@ export type ColumnDef = { width?: ColumnSize; }; -type ElementProps = { +export type ElementProps = { label?: string; columns: ColumnDef[]; data: TableRowData[]; @@ -92,11 +90,12 @@ type ElementProps void; slotEmpty?: React.ReactNode; + numRowsToShow?: number; // collection: TableCollection; // children: React.ReactNode; }; -type StyleProps = { +export type StyleProps = { hideHeader?: boolean; withGradientCardRows?: boolean; withFocusStickyRows?: boolean; @@ -121,6 +120,7 @@ export const Table = ({ selectionMode = 'single', selectionBehavior = 'toggle', slotEmpty, + numRowsToShow = data.length, // shouldRowRender, // collection, @@ -233,7 +233,7 @@ export const Table = ({ )} - + {(item) => ( {(columnKey) => ( @@ -337,6 +337,7 @@ const TableRoot = {/* {Array.from(collection.getChildren!(collection.body.key), (row) => */} {[...collection.body.childNodes].map((row) => @@ -415,6 +416,7 @@ const TableBodyRowGroup = ({ children, withGradientCardRows, withInnerBorders, + withOuterBorder, }: { children: React.ReactNode } & StyleProps) => { const { rowGroupProps } = useTableRowGroup(); @@ -423,6 +425,7 @@ const TableBodyRowGroup = ({ {...rowGroupProps} withGradientCardRows={withGradientCardRows} withInnerBorders={withInnerBorders} + withOuterBorder={withOuterBorder} > {children} @@ -660,7 +663,7 @@ Styled.Empty = styled.div<{ withOuterBorder: boolean }>` justify-items: center; align-content: center; - padding: 2rem; + padding: 4rem; gap: 0.75em; color: var(--color-text-0); @@ -868,6 +871,18 @@ Styled.Tbody = styled.tbody` --stickyArea2-paddingLeft: var(--border-width); --stickyArea2-paddingRight: var(--border-width); + tr:first-of-type { + box-shadow: 0 calc(var(--border-width)) 0 0 var(--border-color); + } + `} + + ${({ withOuterBorder }) => + withOuterBorder && + css` + tr:last-of-type:not(:only-of-type) { + box-shadow: 0 calc(-1 * var(--border-width)) 0 0 var(--border-color); + } + tr:first-of-type { box-shadow: none; } diff --git a/src/views/tables/FillsTable.tsx b/src/views/tables/FillsTable.tsx index 084d5d9..4a32c1c 100644 --- a/src/views/tables/FillsTable.tsx +++ b/src/views/tables/FillsTable.tsx @@ -36,8 +36,6 @@ import { openDialog } from '@/state/dialogs'; import { MustBigNumber } from '@/lib/numbers'; import { getHydratedTradingData } from '@/lib/orders'; -import { tableMixins } from '@/styles/tableMixins'; -import { breakpoints } from '@/styles'; const MOBILE_FILLS_PER_PAGE = 50;