feat(ui): improve mobile responsive layouts
This commit is contained in:
@@ -62,7 +62,7 @@ function ListSkeleton() {
|
||||
<Skeleton className='h-4 w-32' />
|
||||
<Skeleton className='h-5 w-16 rounded-full' />
|
||||
</div>
|
||||
<div className='mt-1.5 flex items-start gap-4'>
|
||||
<div className='mt-1.5 grid grid-cols-2 gap-2'>
|
||||
<div className='flex-1'>
|
||||
<Skeleton className='mb-1 h-2 w-8' />
|
||||
<Skeleton className='h-4 w-full' />
|
||||
@@ -136,9 +136,9 @@ function CompactRow<TData>({ row }: { row: Row<TData> }) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Row 2: Key fields side by side */}
|
||||
{/* Row 2: Key fields wrap into compact columns instead of squeezing */}
|
||||
{fieldCells.length > 0 && (
|
||||
<div className='mt-1.5 flex items-start gap-4'>
|
||||
<div className='mt-1.5 grid grid-cols-2 gap-x-3 gap-y-1.5'>
|
||||
{fieldCells.map((cell) => {
|
||||
const label = getCellLabel(cell)
|
||||
return (
|
||||
@@ -260,7 +260,7 @@ export function MobileCardList<TData>(props: MobileCardListProps<TData>) {
|
||||
|
||||
if (!rows || rows.length === 0) {
|
||||
return (
|
||||
<div className='rounded-lg border p-8'>
|
||||
<div className='rounded-lg border p-6'>
|
||||
<Empty className='border-none p-0'>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant='icon'>
|
||||
|
||||
+5
-5
@@ -32,12 +32,12 @@ export function DataTablePagination<TData>({
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center justify-between overflow-clip',
|
||||
'@max-2xl/content:flex-col-reverse @max-2xl/content:gap-4'
|
||||
'@max-2xl/content:flex-col-reverse @max-2xl/content:gap-2 sm:@max-2xl/content:gap-4'
|
||||
)}
|
||||
style={{ overflowClipMargin: 1 }}
|
||||
>
|
||||
<div className='flex w-full items-center justify-between'>
|
||||
<div className='flex min-w-[130px] items-center text-sm font-medium whitespace-nowrap @2xl/content:hidden'>
|
||||
<div className='flex w-full items-center justify-between gap-2'>
|
||||
<div className='flex min-w-0 items-center text-xs font-medium whitespace-nowrap sm:min-w-[130px] sm:text-sm @2xl/content:hidden'>
|
||||
{t('Page {{current}} of {{total}}', {
|
||||
current: currentPage,
|
||||
total: totalPages,
|
||||
@@ -50,7 +50,7 @@ export function DataTablePagination<TData>({
|
||||
table.setPageSize(Number(value))
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className='h-8 w-[70px]'>
|
||||
<SelectTrigger className='h-8 w-[64px] sm:w-[70px]'>
|
||||
<SelectValue placeholder={table.getState().pagination.pageSize} />
|
||||
</SelectTrigger>
|
||||
<SelectContent side='top'>
|
||||
@@ -74,7 +74,7 @@ export function DataTablePagination<TData>({
|
||||
total: totalPages,
|
||||
})}
|
||||
</div>
|
||||
<div className='flex items-center space-x-2'>
|
||||
<div className='flex items-center space-x-1.5 sm:space-x-2'>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='size-8 p-0 @max-md/content:hidden'
|
||||
|
||||
+5
-5
@@ -64,14 +64,14 @@ export function DataTableToolbar<TData>({
|
||||
onChange={(event) =>
|
||||
table.getColumn(searchKey)?.setFilterValue(event.target.value)
|
||||
}
|
||||
className='h-8 w-full sm:w-[150px] lg:w-[250px]'
|
||||
className='h-9 w-full sm:h-8 sm:w-[150px] lg:w-[250px]'
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
placeholder={resolvedSearchPlaceholder}
|
||||
value={table.getState().globalFilter ?? ''}
|
||||
onChange={(event) => table.setGlobalFilter(event.target.value)}
|
||||
className='h-8 w-full sm:w-[150px] lg:w-[250px]'
|
||||
className='h-9 w-full sm:h-8 sm:w-[150px] lg:w-[250px]'
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ export function DataTableToolbar<TData>({
|
||||
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='flex items-center gap-1.5 sm:gap-2'>
|
||||
{/* Search input */}
|
||||
{customSearch !== undefined ? customSearch : searchInput}
|
||||
|
||||
@@ -122,7 +122,7 @@ export function DataTableToolbar<TData>({
|
||||
<Button
|
||||
variant='outline'
|
||||
size='sm'
|
||||
className='relative h-8 shrink-0 gap-1 sm:hidden'
|
||||
className='relative h-9 shrink-0 gap-1 px-2 sm:hidden'
|
||||
onClick={() => setMobileFiltersOpen((v) => !v)}
|
||||
>
|
||||
<SlidersHorizontal className='h-3.5 w-3.5' />
|
||||
@@ -142,7 +142,7 @@ export function DataTableToolbar<TData>({
|
||||
|
||||
{/* Mobile: collapsible filter area */}
|
||||
{hasFilterContent && mobileFiltersOpen && (
|
||||
<div className='flex flex-wrap items-center gap-2 sm:hidden'>
|
||||
<div className='bg-muted/30 flex flex-wrap items-center gap-2 rounded-lg border p-2 sm:hidden'>
|
||||
{additionalSearch && <div className='w-full'>{additionalSearch}</div>}
|
||||
{filterChips}
|
||||
{resetButton}
|
||||
|
||||
+2
-2
@@ -25,10 +25,10 @@ export function DataTableViewOptions<TData>({
|
||||
<Button
|
||||
variant='outline'
|
||||
size='sm'
|
||||
className='ms-auto hidden h-8 lg:flex'
|
||||
className='ms-auto h-9 w-9 px-0 sm:h-8 sm:w-auto sm:px-3 lg:flex'
|
||||
>
|
||||
<MixerHorizontalIcon className='size-4' />
|
||||
{t('View')}
|
||||
<span className='hidden sm:inline'>{t('View')}</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align='end' className='w-[150px]'>
|
||||
|
||||
Reference in New Issue
Block a user