mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-06 17:46:23 +00:00
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'
|
'[--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)]'
|
||||||
|
|||||||
@@ -133,17 +133,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.
|
||||||
@@ -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>) {
|
|||||||
) : 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>(
|
|||||||
|
|
||||||
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>(
|
|||||||
|
|
||||||
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() {
|
|||||||
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...'),
|
||||||
|
|||||||
Reference in New Issue
Block a user