Commit 4206d7fd by CaIon

feat(data-table): enhance mobile card view handling and improve layout logic

parent 50b8f2a2
...@@ -64,4 +64,4 @@ export const DISABLED_ROW_DESKTOP = ...@@ -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' '[--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 = 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)]'
...@@ -134,17 +134,6 @@ export type DataTablePageProps<TData> = { ...@@ -134,17 +134,6 @@ export type DataTablePageProps<TData> = {
hideMobile?: boolean 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. * Row className resolver — applied to both desktop `TableRow` and mobile card.
* Composes with the default `data-state="selected"` styling on desktop. * Composes with the default `data-state="selected"` styling on desktop.
* The `ctx.isMobile` flag is provided so consumers can return the * The `ctx.isMobile` flag is provided so consumers can return the
...@@ -235,9 +224,8 @@ export type DataTablePageProps<TData> = { ...@@ -235,9 +224,8 @@ export type DataTablePageProps<TData> = {
* pages render the table only and behave exactly as before. When enabled, a * pages render the table only and behave exactly as before. When enabled, a
* {@link DataTableViewModeToggle} is injected into the default toolbar * {@link DataTableViewModeToggle} is injected into the default toolbar
* (requires `toolbarProps`; ignored when a fully custom `toolbar` is used) * (requires `toolbarProps`; ignored when a fully custom `toolbar` is used)
* and the desktop view switches between the table and a card grid. * 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.
* The mobile layout is unaffected — it always renders the mobile list.
*/ */
enableCardView?: boolean enableCardView?: boolean
...@@ -323,7 +311,7 @@ export function DataTablePage<TData>(props: DataTablePageProps<TData>) { ...@@ -323,7 +311,7 @@ export function DataTablePage<TData>(props: DataTablePageProps<TData>) {
) : undefined ) : undefined
const toolbarNode = renderToolbar(props, viewToggle) 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 desktopNode = renderDesktop(props, showMobile, cardViewActive, viewMode)
const paginationNode = renderPagination(props) const paginationNode = renderPagination(props)
...@@ -393,12 +381,15 @@ function renderPagination<TData>( ...@@ -393,12 +381,15 @@ function renderPagination<TData>(
function renderMobile<TData>( function renderMobile<TData>(
props: DataTablePageProps<TData>, props: DataTablePageProps<TData>,
showMobile: boolean showMobile: boolean,
cardViewActive: boolean,
viewMode: DataTableViewMode
): React.ReactNode { ): React.ReactNode {
if (!showMobile) { if (!showMobile) {
return null return null
} }
const isFetchingOnly = props.isFetching && !props.isLoading
const ownGetRowClassName = props.getRowClassName const ownGetRowClassName = props.getRowClassName
const mobileGetRowClassName = const mobileGetRowClassName =
props.mobileProps?.getRowClassName ?? props.mobileProps?.getRowClassName ??
...@@ -408,29 +399,61 @@ function renderMobile<TData>( ...@@ -408,29 +399,61 @@ function renderMobile<TData>(
let mobileContent = props.mobile let mobileContent = props.mobile
if (mobileContent === undefined) { if (mobileContent === undefined) {
mobileContent = props.mobileCardView ? ( if (cardViewActive && viewMode === DATA_TABLE_VIEW_MODES.TABLE) {
<DataTableCardGrid mobileContent = (
table={props.table} <DataTableView
isLoading={props.isLoading} table={props.table}
emptyTitle={props.emptyTitle} isLoading={props.isLoading}
emptyDescription={props.emptyDescription} emptyTitle={props.emptyTitle}
emptyIcon={props.emptyIcon} emptyDescription={props.emptyDescription}
renderCard={props.renderCard} emptyIcon={props.emptyIcon}
gridClassName={props.cardGridClassName ?? 'grid grid-cols-1 gap-3'} emptyAction={props.emptyAction}
skeletonKeyPrefix={props.skeletonKeyPrefix} skeletonKeyPrefix={props.skeletonKeyPrefix}
getRowKey={props.mobileProps?.getRowKey} renderRow={props.renderRow}
getRowClassName={mobileGetRowClassName} applyHeaderSize={props.applyHeaderSize}
/> tableHeaderClassName={cn(
) : ( '[background-color:var(--table-header)]',
<MobileCardList props.tableHeaderClassName
table={props.table} )}
isLoading={props.isLoading} getColumnClassName={props.getColumnClassName}
emptyTitle={props.emptyTitle} pinnedColumns={props.pinnedColumns}
emptyDescription={props.emptyDescription} containerClassName={cn(
getRowKey={props.mobileProps?.getRowKey} 'transition-opacity duration-150',
getRowClassName={mobileGetRowClassName} 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> return <div className='min-h-0 flex-1 overflow-y-auto'>{mobileContent}</div>
......
...@@ -361,7 +361,6 @@ export function ChannelsTable() { ...@@ -361,7 +361,6 @@ export function ChannelsTable() {
viewModeStorageKey={CHANNELS_VIEW_MODE_STORAGE_KEY} viewModeStorageKey={CHANNELS_VIEW_MODE_STORAGE_KEY}
renderCard={(row) => <ChannelCard row={row} />} renderCard={(row) => <ChannelCard row={row} />}
cardGridClassName='grid grid-cols-1 gap-3 sm:gap-4 lg:grid-cols-2 2xl:grid-cols-3' cardGridClassName='grid grid-cols-1 gap-3 sm:gap-4 lg:grid-cols-2 2xl:grid-cols-3'
mobileCardView
applyHeaderSize applyHeaderSize
toolbarProps={{ toolbarProps={{
searchPlaceholder: t('Filter by name, ID, or key...'), searchPlaceholder: t('Filter by name, ID, or key...'),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment