feat(data-table): enhance mobile card view handling and improve layout logic
This commit is contained in:
+1
-1
@@ -64,4 +64,4 @@ export const DISABLED_ROW_DESKTOP =
|
||||
'[--data-table-card-bg:var(--table-disabled)] hover:[--data-table-card-bg:var(--table-disabled-hover)] [background-color:var(--table-disabled)] hover:[background-color:var(--table-disabled-hover)] [&>td:first-child]:[border-left-color:var(--table-disabled-border)] [&>td:first-child]:border-l-4 [&>td:first-child]:pl-1'
|
||||
|
||||
export const DISABLED_ROW_MOBILE =
|
||||
'[--data-table-card-bg:var(--table-disabled)] [background-color:var(--table-disabled)] border-l-4 [border-left-color:var(--table-disabled-border)]'
|
||||
'[--data-table-card-bg:var(--table-disabled)] [background-color:var(--table-disabled)]'
|
||||
|
||||
@@ -133,17 +133,6 @@ export type DataTablePageProps<TData> = {
|
||||
*/
|
||||
hideMobile?: boolean
|
||||
|
||||
/**
|
||||
* Render the card view on mobile instead of the default {@link MobileCardList}.
|
||||
* When enabled, the mobile layout reuses the same {@link DataTableCardGrid}
|
||||
* (and therefore `renderCard` / `cardGridClassName`) as the desktop card view,
|
||||
* stacked in a single column. Falls back to the generic card content when no
|
||||
* `renderCard` is provided. Ignored when a custom `mobile` slot is supplied.
|
||||
*
|
||||
* Defaults to `false`, so existing pages keep the list-style mobile layout.
|
||||
*/
|
||||
mobileCardView?: boolean
|
||||
|
||||
/**
|
||||
* Row className resolver — applied to both desktop `TableRow` and mobile card.
|
||||
* Composes with the default `data-state="selected"` styling on desktop.
|
||||
@@ -235,9 +224,8 @@ export type DataTablePageProps<TData> = {
|
||||
* pages render the table only and behave exactly as before. When enabled, a
|
||||
* {@link DataTableViewModeToggle} is injected into the default toolbar
|
||||
* (requires `toolbarProps`; ignored when a fully custom `toolbar` is used)
|
||||
* and the desktop view switches between the table and a card grid.
|
||||
*
|
||||
* The mobile layout is unaffected — it always renders the mobile list.
|
||||
* and the view switches between the table and a card grid on desktop and
|
||||
* mobile. Mobile card mode reuses the same card renderer in a single column.
|
||||
*/
|
||||
enableCardView?: boolean
|
||||
|
||||
@@ -323,7 +311,7 @@ export function DataTablePage<TData>(props: DataTablePageProps<TData>) {
|
||||
) : undefined
|
||||
|
||||
const toolbarNode = renderToolbar(props, viewToggle)
|
||||
const mobileNode = renderMobile(props, showMobile)
|
||||
const mobileNode = renderMobile(props, showMobile, cardViewActive, viewMode)
|
||||
const desktopNode = renderDesktop(props, showMobile, cardViewActive, viewMode)
|
||||
const paginationNode = renderPagination(props)
|
||||
|
||||
@@ -393,12 +381,15 @@ function renderPagination<TData>(
|
||||
|
||||
function renderMobile<TData>(
|
||||
props: DataTablePageProps<TData>,
|
||||
showMobile: boolean
|
||||
showMobile: boolean,
|
||||
cardViewActive: boolean,
|
||||
viewMode: DataTableViewMode
|
||||
): React.ReactNode {
|
||||
if (!showMobile) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isFetchingOnly = props.isFetching && !props.isLoading
|
||||
const ownGetRowClassName = props.getRowClassName
|
||||
const mobileGetRowClassName =
|
||||
props.mobileProps?.getRowClassName ??
|
||||
@@ -408,29 +399,61 @@ function renderMobile<TData>(
|
||||
|
||||
let mobileContent = props.mobile
|
||||
if (mobileContent === undefined) {
|
||||
mobileContent = props.mobileCardView ? (
|
||||
<DataTableCardGrid
|
||||
table={props.table}
|
||||
isLoading={props.isLoading}
|
||||
emptyTitle={props.emptyTitle}
|
||||
emptyDescription={props.emptyDescription}
|
||||
emptyIcon={props.emptyIcon}
|
||||
renderCard={props.renderCard}
|
||||
gridClassName={props.cardGridClassName ?? 'grid grid-cols-1 gap-3'}
|
||||
skeletonKeyPrefix={props.skeletonKeyPrefix}
|
||||
getRowKey={props.mobileProps?.getRowKey}
|
||||
getRowClassName={mobileGetRowClassName}
|
||||
/>
|
||||
) : (
|
||||
<MobileCardList
|
||||
table={props.table}
|
||||
isLoading={props.isLoading}
|
||||
emptyTitle={props.emptyTitle}
|
||||
emptyDescription={props.emptyDescription}
|
||||
getRowKey={props.mobileProps?.getRowKey}
|
||||
getRowClassName={mobileGetRowClassName}
|
||||
/>
|
||||
)
|
||||
if (cardViewActive && viewMode === DATA_TABLE_VIEW_MODES.TABLE) {
|
||||
mobileContent = (
|
||||
<DataTableView
|
||||
table={props.table}
|
||||
isLoading={props.isLoading}
|
||||
emptyTitle={props.emptyTitle}
|
||||
emptyDescription={props.emptyDescription}
|
||||
emptyIcon={props.emptyIcon}
|
||||
emptyAction={props.emptyAction}
|
||||
skeletonKeyPrefix={props.skeletonKeyPrefix}
|
||||
renderRow={props.renderRow}
|
||||
applyHeaderSize={props.applyHeaderSize}
|
||||
tableHeaderClassName={cn(
|
||||
'[background-color:var(--table-header)]',
|
||||
props.tableHeaderClassName
|
||||
)}
|
||||
getColumnClassName={props.getColumnClassName}
|
||||
pinnedColumns={props.pinnedColumns}
|
||||
containerClassName={cn(
|
||||
'transition-opacity duration-150',
|
||||
isFetchingOnly && 'pointer-events-none opacity-60',
|
||||
props.tableClassName
|
||||
)}
|
||||
getRowClassName={(row) =>
|
||||
props.getRowClassName?.(row, { isMobile: false })
|
||||
}
|
||||
/>
|
||||
)
|
||||
} else if (cardViewActive) {
|
||||
mobileContent = (
|
||||
<DataTableCardGrid
|
||||
table={props.table}
|
||||
isLoading={props.isLoading}
|
||||
emptyTitle={props.emptyTitle}
|
||||
emptyDescription={props.emptyDescription}
|
||||
emptyIcon={props.emptyIcon}
|
||||
renderCard={props.renderCard}
|
||||
gridClassName={props.cardGridClassName ?? 'grid grid-cols-1 gap-3'}
|
||||
skeletonKeyPrefix={props.skeletonKeyPrefix}
|
||||
getRowKey={props.mobileProps?.getRowKey}
|
||||
getRowClassName={mobileGetRowClassName}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
mobileContent = (
|
||||
<MobileCardList
|
||||
table={props.table}
|
||||
isLoading={props.isLoading}
|
||||
emptyTitle={props.emptyTitle}
|
||||
emptyDescription={props.emptyDescription}
|
||||
getRowKey={props.mobileProps?.getRowKey}
|
||||
getRowClassName={mobileGetRowClassName}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return <div className='min-h-0 flex-1 overflow-y-auto'>{mobileContent}</div>
|
||||
|
||||
@@ -361,7 +361,6 @@ export function ChannelsTable() {
|
||||
viewModeStorageKey={CHANNELS_VIEW_MODE_STORAGE_KEY}
|
||||
renderCard={(row) => <ChannelCard row={row} />}
|
||||
cardGridClassName='grid grid-cols-1 gap-3 sm:gap-4 lg:grid-cols-2 2xl:grid-cols-3'
|
||||
mobileCardView
|
||||
applyHeaderSize
|
||||
toolbarProps={{
|
||||
searchPlaceholder: t('Filter by name, ID, or key...'),
|
||||
|
||||
Reference in New Issue
Block a user