Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
4206d7fd
authored
Jun 19, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(data-table): enhance mobile card view handling and improve layout logic
parent
50b8f2a2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
63 additions
and
41 deletions
+63
-41
web/default/src/components/data-table/index.ts
+1
-1
web/default/src/components/data-table/layout/data-table-page.tsx
+62
-39
web/default/src/features/channels/components/channels-table.tsx
+0
-1
No files found.
web/default/src/components/data-table/index.ts
View file @
4206d7fd
...
...
@@ -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)]'
web/default/src/components/data-table/layout/data-table-page.tsx
View file @
4206d7fd
...
...
@@ -134,17 +134,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.
* The `ctx.isMobile` flag is provided so consumers can return the
...
...
@@ -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
>
...
...
web/default/src/features/channels/components/channels-table.tsx
View file @
4206d7fd
...
...
@@ -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...'
),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment