Skip to content

Commit 8177d5e

Browse files
Copilothotlong
andcommitted
Improve mobile responsiveness across console UI
- AppHeader: Better mobile spacing and layout with flexbox optimization - DashboardView: Responsive padding and header layout for mobile - RecordDetailView: Mobile-optimized padding - ReportView: Mobile-friendly toolbar and button text - System Pages: Responsive layouts for User/Org/Role/Audit/Profile pages - Auth Pages: Add horizontal padding for mobile screens - Dialog: Better mobile sizing with width constraints - AppShell: Responsive header and content padding Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 0933591 commit 8177d5e

14 files changed

Lines changed: 94 additions & 89 deletions

apps/console/src/App.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,14 @@ export function AppContent() {
218218
</ErrorBoundary>
219219

220220
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
221-
<DialogContent className="sm:max-w-xl max-h-[90vh] flex flex-col gap-0 p-0 overflow-hidden">
222-
<DialogHeader className="p-6 pb-4 border-b">
223-
<DialogTitle>{editingRecord ? 'Edit' : 'Create'} {currentObjectDef?.label}</DialogTitle>
224-
<DialogDescription>
221+
<DialogContent className="sm:max-w-xl max-h-[90vh] flex flex-col gap-0 p-0 overflow-hidden w-[calc(100vw-2rem)] sm:w-full">
222+
<DialogHeader className="p-4 sm:p-6 pb-3 sm:pb-4 border-b">
223+
<DialogTitle className="text-lg sm:text-xl">{editingRecord ? 'Edit' : 'Create'} {currentObjectDef?.label}</DialogTitle>
224+
<DialogDescription className="text-sm">
225225
{editingRecord ? `Update details for ${currentObjectDef?.label}` : `Add a new ${currentObjectDef?.label} to your database.`}
226226
</DialogDescription>
227227
</DialogHeader>
228-
<div className="flex-1 overflow-y-auto p-6">
228+
<div className="flex-1 overflow-y-auto p-4 sm:p-6">
229229
{currentObjectDef && (
230230
<ObjectForm
231231
key={editingRecord?.id || 'new'}

apps/console/src/components/AppHeader.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,23 @@ export function AppHeader({ appName, objects, connectionState }: { appName: stri
7676
}
7777

7878
return (
79-
<div className="flex items-center justify-between w-full h-full px-2 md:px-4 gap-2">
80-
<div className="flex items-center gap-2">
79+
<div className="flex items-center justify-between w-full h-full px-2 sm:px-3 md:px-4 gap-1.5 sm:gap-2">
80+
<div className="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-1">
8181
{/* Mobile sidebar trigger */}
82-
<SidebarTrigger className="md:hidden" />
83-
<Separator orientation="vertical" className="h-4 md:hidden" />
82+
<SidebarTrigger className="md:hidden shrink-0" />
83+
<Separator orientation="vertical" className="h-4 md:hidden shrink-0" />
8484

85-
<Breadcrumb className="hidden sm:flex">
85+
<Breadcrumb className="hidden sm:flex min-w-0">
8686
<BreadcrumbList>
8787
{breadcrumbItems.map((item, index) => (
8888
<Fragment key={index}>
8989
{index > 0 && <BreadcrumbSeparator />}
9090
<BreadcrumbItem>
9191
{index === breadcrumbItems.length - 1 || !item.href ? (
92-
<BreadcrumbPage>{item.label}</BreadcrumbPage>
92+
<BreadcrumbPage className="truncate max-w-[200px]">{item.label}</BreadcrumbPage>
9393
) : (
9494
<BreadcrumbLink asChild>
95-
<Link to={item.href}>{item.label}</Link>
95+
<Link to={item.href} className="truncate max-w-[150px]">{item.label}</Link>
9696
</BreadcrumbLink>
9797
)}
9898
</BreadcrumbItem>
@@ -102,12 +102,12 @@ export function AppHeader({ appName, objects, connectionState }: { appName: stri
102102
</Breadcrumb>
103103

104104
{/* Mobile: Just show current page */}
105-
<span className="text-sm font-medium sm:hidden truncate max-w-37.5">
105+
<span className="text-sm font-medium sm:hidden truncate min-w-0">
106106
{breadcrumbItems[breadcrumbItems.length - 1]?.label || appName}
107107
</span>
108108
</div>
109109

110-
<div className="flex items-center gap-1 md:gap-2">
110+
<div className="flex items-center gap-0.5 sm:gap-1 md:gap-2 shrink-0">
111111
{/* Connection Status */}
112112
{connectionState && <ConnectionStatus state={connectionState} />}
113113

@@ -127,24 +127,26 @@ export function AppHeader({ appName, objects, connectionState }: { appName: stri
127127
<Button
128128
variant="ghost"
129129
size="icon"
130-
className="lg:hidden h-8 w-8"
130+
className="lg:hidden h-8 w-8 shrink-0"
131131
onClick={() => document.dispatchEvent(new KeyboardEvent('keydown', { key: 'k', metaKey: true }))}
132132
>
133133
<Search className="h-4 w-4" />
134134
</Button>
135135

136136
{/* Notifications */}
137-
<Button variant="ghost" size="icon" className="h-8 w-8 hidden sm:flex">
137+
<Button variant="ghost" size="icon" className="h-8 w-8 hidden sm:flex shrink-0">
138138
<Bell className="h-4 w-4" />
139139
</Button>
140140

141141
{/* Help */}
142-
<Button variant="ghost" size="icon" className="h-8 w-8 hidden md:flex">
142+
<Button variant="ghost" size="icon" className="h-8 w-8 hidden md:flex shrink-0">
143143
<HelpCircle className="h-4 w-4" />
144144
</Button>
145145

146146
{/* Theme toggle */}
147-
<ModeToggle />
147+
<div className="shrink-0">
148+
<ModeToggle />
149+
</div>
148150
</div>
149151
</div>
150152
);

apps/console/src/components/DashboardView.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,20 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
3030

3131
return (
3232
<div className="flex flex-col h-full overflow-hidden bg-background">
33-
<div className="flex justify-between items-center p-6 border-b shrink-0">
34-
<div>
35-
<h1 className="text-2xl font-bold tracking-tight">{dashboard.label || dashboard.name}</h1>
33+
<div className="flex flex-col sm:flex-row justify-between sm:items-center gap-3 sm:gap-4 p-4 sm:p-6 border-b shrink-0">
34+
<div className="min-w-0 flex-1">
35+
<h1 className="text-xl sm:text-2xl font-bold tracking-tight truncate">{dashboard.label || dashboard.name}</h1>
3636
{dashboard.description && (
37-
<p className="text-muted-foreground mt-1">{dashboard.description}</p>
37+
<p className="text-sm text-muted-foreground mt-1 line-clamp-2">{dashboard.description}</p>
3838
)}
3939
</div>
40-
<MetadataToggle open={showDebug} onToggle={toggleDebug} />
40+
<div className="shrink-0">
41+
<MetadataToggle open={showDebug} onToggle={toggleDebug} />
42+
</div>
4143
</div>
4244

4345
<div className="flex-1 overflow-hidden flex flex-row relative">
44-
<div className="flex-1 overflow-auto p-6">
46+
<div className="flex-1 overflow-auto p-4 sm:p-6">
4547
<DashboardRenderer schema={dashboard} dataSource={dataSource} />
4648
</div>
4749

apps/console/src/components/RecordDetailView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailVi
5656

5757
return (
5858
<div className="h-full bg-background overflow-hidden flex flex-col relative">
59-
<div className="absolute top-4 right-4 z-50">
59+
<div className="absolute top-2 sm:top-4 right-2 sm:right-4 z-50">
6060
<MetadataToggle open={showDebug} onToggle={toggleDebug} />
6161
</div>
6262

6363
<div className="flex-1 overflow-hidden flex flex-row">
64-
<div className="flex-1 overflow-auto p-4 lg:p-6">
64+
<div className="flex-1 overflow-auto p-3 sm:p-4 lg:p-6">
6565
<DetailView
6666
schema={detailSchema}
6767
dataSource={dataSource}

apps/console/src/components/ReportView.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ export function ReportView({ dataSource: _dataSource }: { dataSource?: any }) {
4848
if (isEditing) {
4949
return (
5050
<div className="flex flex-col h-full overflow-hidden bg-background">
51-
<div className="flex items-center p-4 border-b bg-muted/10 gap-2">
52-
<Button variant="ghost" size="sm" onClick={() => setIsEditing(false)}>
51+
<div className="flex items-center p-3 sm:p-4 border-b bg-muted/10 gap-2">
52+
<Button variant="ghost" size="sm" onClick={() => setIsEditing(false)} className="shrink-0">
5353
<ChevronLeft className="h-4 w-4 mr-1" />
54-
Back to View
54+
<span className="hidden sm:inline">Back to View</span>
55+
<span className="sm:hidden">Back</span>
5556
</Button>
56-
<div className="font-medium">Edit Report: {reportData.title}</div>
57+
<div className="font-medium truncate">Edit Report: {reportData.title}</div>
5758
</div>
5859
<div className="flex-1 overflow-auto">
5960
<ReportBuilder
@@ -82,23 +83,23 @@ export function ReportView({ dataSource: _dataSource }: { dataSource?: any }) {
8283

8384
return (
8485
<div className="flex flex-col h-full overflow-hidden bg-background">
85-
<div className="flex justify-between items-center p-6 border-b shrink-0 bg-muted/10">
86-
<div>
86+
<div className="flex flex-col sm:flex-row justify-between sm:items-center gap-3 sm:gap-4 p-4 sm:p-6 border-b shrink-0 bg-muted/10">
87+
<div className="min-w-0">
8788
{/* Header is handled by ReportViewer usually, but we can have a page header too */}
88-
<h1 className="text-lg font-medium text-muted-foreground">{reportData.title || 'Report Viewer'}</h1>
89+
<h1 className="text-base sm:text-lg font-medium text-muted-foreground truncate">{reportData.title || 'Report Viewer'}</h1>
8990
</div>
90-
<div className="flex items-center gap-2">
91-
<Button variant="outline" size="sm" onClick={() => setIsEditing(true)}>
92-
<PenLine className="h-4 w-4 mr-2" />
93-
Edit Report
91+
<div className="flex items-center gap-2 shrink-0">
92+
<Button variant="outline" size="sm" onClick={() => setIsEditing(true)} className="h-8">
93+
<PenLine className="h-4 w-4 sm:mr-2" />
94+
<span className="hidden sm:inline">Edit Report</span>
9495
</Button>
9596
<MetadataToggle open={showDebug} onToggle={toggleDebug} />
9697
</div>
9798
</div>
9899

99100
<div className="flex-1 overflow-hidden flex flex-row relative">
100-
<div className="flex-1 overflow-auto p-8 bg-muted/5">
101-
<div className="max-w-5xl mx-auto shadow-sm border rounded-xl bg-background overflow-hidden min-h-150">
101+
<div className="flex-1 overflow-auto p-4 sm:p-6 lg:p-8 bg-muted/5">
102+
<div className="max-w-5xl mx-auto shadow-sm border rounded-lg sm:rounded-xl bg-background overflow-hidden min-h-150">
102103
<ReportViewer schema={viewerSchema} />
103104
</div>
104105
</div>

apps/console/src/pages/ForgotPasswordPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ForgotPasswordForm } from '@object-ui/auth';
66

77
export function ForgotPasswordPage() {
88
return (
9-
<div className="flex min-h-screen items-center justify-center bg-background">
9+
<div className="flex min-h-screen items-center justify-center bg-background px-4 py-8">
1010
<ForgotPasswordForm loginUrl="/login" />
1111
</div>
1212
);

apps/console/src/pages/LoginPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function LoginPage() {
99
const navigate = useNavigate();
1010

1111
return (
12-
<div className="flex min-h-screen items-center justify-center bg-background">
12+
<div className="flex min-h-screen items-center justify-center bg-background px-4 py-8">
1313
<LoginForm
1414
onSuccess={() => navigate('/')}
1515
registerUrl="/register"

apps/console/src/pages/RegisterPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function RegisterPage() {
99
const navigate = useNavigate();
1010

1111
return (
12-
<div className="flex min-h-screen items-center justify-center bg-background">
12+
<div className="flex min-h-screen items-center justify-center bg-background px-4 py-8">
1313
<RegisterForm
1414
onSuccess={() => navigate('/')}
1515
loginUrl="/login"

apps/console/src/pages/system/AuditLogPage.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ const auditObject = systemObjects.find((o) => o.name === 'sys_audit_log')!;
1111

1212
export function AuditLogPage() {
1313
return (
14-
<div className="flex flex-col gap-6 p-6">
15-
<div>
16-
<h1 className="text-2xl font-bold tracking-tight">Audit Log</h1>
17-
<p className="text-muted-foreground">View system activity and user actions</p>
14+
<div className="flex flex-col gap-4 sm:gap-6 p-4 sm:p-6">
15+
<div className="min-w-0">
16+
<h1 className="text-xl sm:text-2xl font-bold tracking-tight">Audit Log</h1>
17+
<p className="text-sm text-muted-foreground mt-1">View system activity and user actions</p>
1818
</div>
1919

20-
<div className="rounded-md border">
20+
<div className="rounded-md border overflow-x-auto">
2121
<table className="w-full text-sm">
2222
<thead>
2323
<tr className="border-b bg-muted/50">
2424
{auditObject.views[0].columns.map((col) => {
2525
const field = auditObject.fields.find((f) => f.name === col);
2626
return (
27-
<th key={col} className="h-10 px-4 text-left font-medium text-muted-foreground">
27+
<th key={col} className="h-10 px-3 sm:px-4 text-left font-medium text-muted-foreground whitespace-nowrap">
2828
{field?.label ?? col}
2929
</th>
3030
);
@@ -33,7 +33,7 @@ export function AuditLogPage() {
3333
</thead>
3434
<tbody>
3535
<tr className="border-b">
36-
<td className="p-4 text-muted-foreground" colSpan={auditObject.views[0].columns.length}>
36+
<td className="p-3 sm:p-4 text-sm text-muted-foreground" colSpan={auditObject.views[0].columns.length}>
3737
Connect to ObjectStack server to load audit logs. In production, this page uses plugin-grid in read-only mode.
3838
</td>
3939
</tr>

apps/console/src/pages/system/OrgManagementPage.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,30 @@ export function OrgManagementPage() {
1515
const isAdmin = currentUser?.role === 'admin';
1616

1717
return (
18-
<div className="flex flex-col gap-6 p-6">
19-
<div className="flex items-center justify-between">
20-
<div>
21-
<h1 className="text-2xl font-bold tracking-tight">Organization Management</h1>
22-
<p className="text-muted-foreground">Manage organizations and their members</p>
18+
<div className="flex flex-col gap-4 sm:gap-6 p-4 sm:p-6">
19+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
20+
<div className="min-w-0">
21+
<h1 className="text-xl sm:text-2xl font-bold tracking-tight">Organization Management</h1>
22+
<p className="text-sm text-muted-foreground mt-1">Manage organizations and their members</p>
2323
</div>
2424
{isAdmin && (
2525
<button
2626
type="button"
27-
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
27+
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 shrink-0"
2828
>
2929
Add Organization
3030
</button>
3131
)}
3232
</div>
3333

34-
<div className="rounded-md border">
34+
<div className="rounded-md border overflow-x-auto">
3535
<table className="w-full text-sm">
3636
<thead>
3737
<tr className="border-b bg-muted/50">
3838
{orgObject.views[0].columns.map((col) => {
3939
const field = orgObject.fields.find((f) => f.name === col);
4040
return (
41-
<th key={col} className="h-10 px-4 text-left font-medium text-muted-foreground">
41+
<th key={col} className="h-10 px-3 sm:px-4 text-left font-medium text-muted-foreground whitespace-nowrap">
4242
{field?.label ?? col}
4343
</th>
4444
);
@@ -47,7 +47,7 @@ export function OrgManagementPage() {
4747
</thead>
4848
<tbody>
4949
<tr className="border-b">
50-
<td className="p-4 text-muted-foreground" colSpan={orgObject.views[0].columns.length}>
50+
<td className="p-3 sm:p-4 text-sm text-muted-foreground" colSpan={orgObject.views[0].columns.length}>
5151
Connect to ObjectStack server to load organizations. In production, this page uses plugin-grid for full CRUD functionality.
5252
</td>
5353
</tr>

0 commit comments

Comments
 (0)