Mobile optimization pass for responsive layouts

- TabsList: Add responsive grid columns (grid-cols-2/3 on mobile)
- Headers: Stack vertically on mobile with responsive text sizes
- Dialogs: Use viewport-relative heights (70-80vh on mobile)
- Grids: Add sm: breakpoints for single-column mobile layouts
- Tables: Add overflow-x-auto for horizontal scrolling
- Buttons: Full-width on mobile with flex-1 sm:flex-none
- Select triggers: Full-width on mobile

Files updated: 21 component and page files across admin,
staff, dashboards, and hub sections.
This commit is contained in:
Claude 2026-01-26 22:46:26 +00:00
parent 88e364f4c5
commit b640b0d2ad
No known key found for this signature in database
21 changed files with 44 additions and 44 deletions

View file

@ -196,7 +196,7 @@ export function ProfileEditor({
return ( return (
<Tabs defaultValue="basic" className="w-full"> <Tabs defaultValue="basic" className="w-full">
<TabsList className="grid w-full grid-cols-5"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-3 md:grid-cols-5">
<TabsTrigger value="basic">Basic</TabsTrigger> <TabsTrigger value="basic">Basic</TabsTrigger>
<TabsTrigger value="social">Social</TabsTrigger> <TabsTrigger value="social">Social</TabsTrigger>
<TabsTrigger value="skills">Skills</TabsTrigger> <TabsTrigger value="skills">Skills</TabsTrigger>

View file

@ -80,7 +80,7 @@ export default function AdminStaffAdmin() {
</div> </div>
<Tabs value={adminTab} onValueChange={setAdminTab} className="space-y-4"> <Tabs value={adminTab} onValueChange={setAdminTab} className="space-y-4">
<TabsList className="grid w-full grid-cols-3 lg:grid-cols-6"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-3 lg:grid-cols-6">
<TabsTrigger value="users" className="flex items-center gap-2"> <TabsTrigger value="users" className="flex items-center gap-2">
<Users className="w-4 h-4" /> <Users className="w-4 h-4" />
<span className="hidden sm:inline">Users</span> <span className="hidden sm:inline">Users</span>

View file

@ -209,7 +209,7 @@ export const AIChat: React.FC<AIChatProps> = ({
animate={{ opacity: 1, y: 0, scale: 1 }} animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 20, scale: 0.95 }} exit={{ opacity: 0, y: 20, scale: 0.95 }}
transition={{ type: 'spring', damping: 25, stiffness: 300 }} transition={{ type: 'spring', damping: 25, stiffness: 300 }}
className="fixed bottom-4 right-4 md:bottom-6 md:right-6 w-[calc(100vw-2rem)] md:w-[450px] h-[600px] max-h-[80vh] bg-background border border-border rounded-2xl shadow-2xl z-50 flex flex-col overflow-hidden" className="fixed bottom-4 right-4 md:bottom-6 md:right-6 w-[calc(100vw-2rem)] md:w-[450px] h-[70vh] sm:h-[600px] max-h-[80vh] bg-background border border-border rounded-2xl shadow-2xl z-50 flex flex-col overflow-hidden"
> >
<div className={`flex items-center justify-between p-4 border-b border-border bg-gradient-to-r ${currentPersona.theme.gradient} bg-opacity-10`}> <div className={`flex items-center justify-between p-4 border-b border-border bg-gradient-to-r ${currentPersona.theme.gradient} bg-opacity-10`}>
<PersonaSelector <PersonaSelector

View file

@ -205,7 +205,7 @@ export default function CommentsModal({
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[500px] flex flex-col h-[600px]"> <DialogContent className="sm:max-w-[500px] flex flex-col h-[80vh] sm:h-[600px] max-h-[600px]">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex items-center gap-2"> <DialogTitle className="flex items-center gap-2">
<MessageCircle className="h-5 w-5" /> <MessageCircle className="h-5 w-5" />

View file

@ -347,7 +347,7 @@ export default function BotPanel() {
</div> </div>
)} )}
<Separator className="bg-gray-700" /> <Separator className="bg-gray-700" />
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div> <div>
<p className="text-sm text-gray-400">Commands</p> <p className="text-sm text-gray-400">Commands</p>
<p className="text-lg font-semibold text-white"> <p className="text-lg font-semibold text-white">
@ -379,7 +379,7 @@ export default function BotPanel() {
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="text-center p-4 bg-gray-700/30 rounded-lg"> <div className="text-center p-4 bg-gray-700/30 rounded-lg">
<p className="text-2xl font-bold text-white">{feedStats?.totalPosts || 0}</p> <p className="text-2xl font-bold text-white">{feedStats?.totalPosts || 0}</p>
<p className="text-sm text-gray-400">Total Posts</p> <p className="text-sm text-gray-400">Total Posts</p>

View file

@ -393,7 +393,7 @@ export default function Dashboard() {
onValueChange={setActiveTab} onValueChange={setActiveTab}
className="w-full" className="w-full"
> >
<TabsList className="grid w-full grid-cols-4 lg:grid-cols-4 bg-purple-950/30 border border-purple-500/20 p-1"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-4 bg-purple-950/30 border border-purple-500/20 p-1">
<TabsTrigger value="realms" className="text-sm md:text-base"> <TabsTrigger value="realms" className="text-sm md:text-base">
<span className="hidden sm:inline">Realms</span> <span className="hidden sm:inline">Realms</span>
<span className="sm:hidden">Arms</span> <span className="sm:hidden">Arms</span>

View file

@ -108,7 +108,7 @@ export default function MaintenancePage() {
<div className="h-px bg-border" /> <div className="h-px bg-border" />
<div className="grid grid-cols-3 gap-4 text-center text-xs"> <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-center text-xs">
<div className="space-y-1"> <div className="space-y-1">
<div className="text-muted-foreground">STATUS</div> <div className="text-muted-foreground">STATUS</div>
<div className="text-blue-400 font-semibold flex items-center justify-center gap-1"> <div className="text-blue-400 font-semibold flex items-center justify-center gap-1">

View file

@ -158,7 +158,7 @@ export default function ProjectsAdmin() {
value={draft.title} value={draft.title}
onChange={(e) => setDraft({ ...draft, title: e.target.value })} onChange={(e) => setDraft({ ...draft, title: e.target.value })}
/> />
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<select <select
className="rounded border border-border/40 bg-background/70 px-3 py-2" className="rounded border border-border/40 bg-background/70 px-3 py-2"
value={draft.org_unit} value={draft.org_unit}

View file

@ -74,7 +74,7 @@ export default function StaffAdmin() {
<Card className="bg-slate-900/50 border-purple-500/20"> <Card className="bg-slate-900/50 border-purple-500/20">
<CardContent className="pt-6"> <CardContent className="pt-6">
<Tabs value={activeTab} onValueChange={setActiveTab}> <Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="grid w-full grid-cols-5 bg-slate-800/50"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-3 md:grid-cols-5 bg-slate-800/50">
<TabsTrigger value="users" className="gap-2"> <TabsTrigger value="users" className="gap-2">
<Users className="w-4 h-4" /> <Users className="w-4 h-4" />
<span className="hidden sm:inline">Users</span> <span className="hidden sm:inline">Users</span>

View file

@ -71,7 +71,7 @@ export default function StaffChat() {
</Button> </Button>
</div> </div>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 h-[600px]"> <div className="grid grid-cols-1 lg:grid-cols-4 gap-6 h-[calc(100vh-200px)] sm:h-[600px] min-h-[400px]">
{/* Channels Sidebar */} {/* Channels Sidebar */}
<Card className="bg-slate-900/50 border-purple-500/20 lg:col-span-1"> <Card className="bg-slate-900/50 border-purple-500/20 lg:col-span-1">
<CardHeader> <CardHeader>

View file

@ -155,7 +155,7 @@ export default function StaffDashboard() {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Tabs value={activeTab} onValueChange={setActiveTab}> <Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="grid w-full grid-cols-4 bg-slate-800/50"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-4 bg-slate-800/50">
<TabsTrigger value="overview" className="gap-2"> <TabsTrigger value="overview" className="gap-2">
<BarChart3 className="w-4 h-4" /> <BarChart3 className="w-4 h-4" />
<span className="hidden sm:inline">Overview</span> <span className="hidden sm:inline">Overview</span>

View file

@ -27,7 +27,7 @@ export default function WixCaseStudies() {
<CardDescription>{c.summary}</CardDescription> <CardDescription>{c.summary}</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid grid-cols-3 gap-3 text-sm"> <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm">
{c.metrics.map((m, i) => ( {c.metrics.map((m, i) => (
<div <div
key={i} key={i}

View file

@ -132,18 +132,18 @@ export default function AdminAnalytics() {
<div className="relative z-10"> <div className="relative z-10">
<div className="container mx-auto max-w-7xl px-4 py-16"> <div className="container mx-auto max-w-7xl px-4 py-16">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-8"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-8">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 rounded-lg bg-cyan-500/20 border border-cyan-500/30"> <div className="p-3 rounded-lg bg-cyan-500/20 border border-cyan-500/30">
<BarChart3 className="h-6 w-6 text-cyan-400" /> <BarChart3 className="h-6 w-6 text-cyan-400" />
</div> </div>
<div> <div>
<h1 className="text-4xl font-bold text-cyan-100">Analytics</h1> <h1 className="text-2xl sm:text-4xl font-bold text-cyan-100">Analytics</h1>
<p className="text-cyan-200/70">Platform insights and metrics</p> <p className="text-cyan-200/70 text-sm sm:text-base">Platform insights and metrics</p>
</div> </div>
</div> </div>
<Select value={period} onValueChange={setPeriod}> <Select value={period} onValueChange={setPeriod}>
<SelectTrigger className="w-40 bg-slate-800 border-slate-700 text-slate-100"> <SelectTrigger className="w-full sm:w-40 bg-slate-800 border-slate-700 text-slate-100">
<SelectValue placeholder="Period" /> <SelectValue placeholder="Period" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>

View file

@ -264,18 +264,18 @@ export default function AdminModeration() {
<div className="relative z-10"> <div className="relative z-10">
<div className="container mx-auto max-w-7xl px-4 py-16"> <div className="container mx-auto max-w-7xl px-4 py-16">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-6"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 rounded-lg bg-red-500/20 border border-red-500/30"> <div className="p-3 rounded-lg bg-red-500/20 border border-red-500/30">
<Shield className="h-6 w-6 text-red-400" /> <Shield className="h-6 w-6 text-red-400" />
</div> </div>
<div> <div>
<h1 className="text-4xl font-bold text-red-100">Moderation</h1> <h1 className="text-2xl sm:text-4xl font-bold text-red-100">Moderation</h1>
<p className="text-red-200/70">Content moderation and user management</p> <p className="text-red-200/70 text-sm sm:text-base">Content moderation and user management</p>
</div> </div>
</div> </div>
<Select value={statusFilter} onValueChange={setStatusFilter}> <Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-40 bg-slate-800 border-slate-700 text-slate-100"> <SelectTrigger className="w-full sm:w-40 bg-slate-800 border-slate-700 text-slate-100">
<SelectValue placeholder="Status" /> <SelectValue placeholder="Status" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>

View file

@ -238,7 +238,7 @@ export default function GameForgeDashboard() {
className="w-full" className="w-full"
> >
<TabsList <TabsList
className="grid w-full grid-cols-5 bg-green-950/30 border border-green-500/20 p-1" className="grid w-full grid-cols-2 sm:grid-cols-3 md:grid-cols-5 bg-green-950/30 border border-green-500/20 p-1"
style={{ fontFamily: theme.fontFamily }} style={{ fontFamily: theme.fontFamily }}
> >
<TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="overview">Overview</TabsTrigger>

View file

@ -306,7 +306,7 @@ export default function LabsDashboard() {
className="w-full" className="w-full"
> >
<TabsList <TabsList
className="grid w-full grid-cols-4 bg-amber-950/30 border border-amber-500/20 p-1" className="grid w-full grid-cols-2 sm:grid-cols-4 bg-amber-950/30 border border-amber-500/20 p-1"
style={{ fontFamily: "Monaco, Courier New, monospace" }} style={{ fontFamily: "Monaco, Courier New, monospace" }}
> >
<TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="overview">Overview</TabsTrigger>

View file

@ -421,7 +421,7 @@ export default function NexusDashboard() {
onValueChange={setActiveTab} onValueChange={setActiveTab}
className="w-full" className="w-full"
> >
<TabsList className="grid w-full grid-cols-4 bg-purple-950/30 border border-purple-500/20 p-1"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-4 bg-purple-950/30 border border-purple-500/20 p-1">
<TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="applications">Applications</TabsTrigger> <TabsTrigger value="applications">Applications</TabsTrigger>
<TabsTrigger value="contracts">Contracts</TabsTrigger> <TabsTrigger value="contracts">Contracts</TabsTrigger>
@ -876,7 +876,7 @@ export default function NexusDashboard() {
onValueChange={setActiveTab} onValueChange={setActiveTab}
className="w-full" className="w-full"
> >
<TabsList className="grid w-full grid-cols-4 bg-blue-950/30 border border-blue-500/20 p-1"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-4 bg-blue-950/30 border border-blue-500/20 p-1">
<TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="opportunities">Opportunities</TabsTrigger> <TabsTrigger value="opportunities">Opportunities</TabsTrigger>
<TabsTrigger value="applicants">Applicants</TabsTrigger> <TabsTrigger value="applicants">Applicants</TabsTrigger>

View file

@ -284,8 +284,8 @@ export default function ClientInvoices() {
{selectedInvoice.line_items?.length > 0 && ( {selectedInvoice.line_items?.length > 0 && (
<div className="space-y-3"> <div className="space-y-3">
<h3 className="text-lg font-semibold text-white">Line Items</h3> <h3 className="text-lg font-semibold text-white">Line Items</h3>
<div className="bg-black/30 rounded-lg border border-cyan-500/20 overflow-hidden"> <div className="bg-black/30 rounded-lg border border-cyan-500/20 overflow-x-auto">
<table className="w-full"> <table className="w-full min-w-[500px]">
<thead className="bg-cyan-500/10"> <thead className="bg-cyan-500/10">
<tr className="text-left text-xs text-gray-400 uppercase"> <tr className="text-left text-xs text-gray-400 uppercase">
<th className="p-4">Description</th> <th className="p-4">Description</th>

View file

@ -138,7 +138,7 @@ export default function MyApplications() {
} }
className="mb-8" className="mb-8"
> >
<TabsList className="grid w-full grid-cols-5 bg-slate-800/50 border-slate-700"> <TabsList className="grid w-full grid-cols-2 sm:grid-cols-3 md:grid-cols-5 bg-slate-800/50 border-slate-700">
<TabsTrigger value="all"> <TabsTrigger value="all">
All ({applications.length}) All ({applications.length})
</TabsTrigger> </TabsTrigger>

View file

@ -266,18 +266,18 @@ export default function StaffOKRs() {
<div className="relative z-10"> <div className="relative z-10">
<div className="container mx-auto max-w-6xl px-4 py-16"> <div className="container mx-auto max-w-6xl px-4 py-16">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-6"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 rounded-lg bg-emerald-500/20 border border-emerald-500/30"> <div className="p-3 rounded-lg bg-emerald-500/20 border border-emerald-500/30">
<Target className="h-6 w-6 text-emerald-400" /> <Target className="h-6 w-6 text-emerald-400" />
</div> </div>
<div> <div>
<h1 className="text-4xl font-bold text-emerald-100">OKRs</h1> <h1 className="text-2xl sm:text-4xl font-bold text-emerald-100">OKRs</h1>
<p className="text-emerald-200/70">Objectives and Key Results</p> <p className="text-emerald-200/70 text-sm sm:text-base">Objectives and Key Results</p>
</div> </div>
</div> </div>
<Button <Button
className="bg-emerald-600 hover:bg-emerald-700" className="bg-emerald-600 hover:bg-emerald-700 w-full sm:w-auto"
onClick={() => setCreateOkrDialog(true)} onClick={() => setCreateOkrDialog(true)}
> >
<Plus className="h-4 w-4 mr-2" /> <Plus className="h-4 w-4 mr-2" />
@ -334,9 +334,9 @@ export default function StaffOKRs() {
</div> </div>
{/* Filters */} {/* Filters */}
<div className="flex gap-4 mb-8"> <div className="flex flex-wrap gap-4 mb-8">
<Select value={selectedQuarter} onValueChange={setSelectedQuarter}> <Select value={selectedQuarter} onValueChange={setSelectedQuarter}>
<SelectTrigger className="w-32 bg-slate-800 border-slate-700 text-slate-100"> <SelectTrigger className="w-full sm:w-32 bg-slate-800 border-slate-700 text-slate-100">
<SelectValue placeholder="Quarter" /> <SelectValue placeholder="Quarter" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -348,7 +348,7 @@ export default function StaffOKRs() {
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={selectedYear} onValueChange={setSelectedYear}> <Select value={selectedYear} onValueChange={setSelectedYear}>
<SelectTrigger className="w-32 bg-slate-800 border-slate-700 text-slate-100"> <SelectTrigger className="w-full sm:w-32 bg-slate-800 border-slate-700 text-slate-100">
<SelectValue placeholder="Year" /> <SelectValue placeholder="Year" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -510,7 +510,7 @@ export default function StaffOKRs() {
onChange={(e) => setNewOkr({ ...newOkr, description: e.target.value })} onChange={(e) => setNewOkr({ ...newOkr, description: e.target.value })}
className="bg-slate-700 border-slate-600 text-slate-100" className="bg-slate-700 border-slate-600 text-slate-100"
/> />
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<Select <Select
value={newOkr.quarter.toString()} value={newOkr.quarter.toString()}
onValueChange={(v) => setNewOkr({ ...newOkr, quarter: parseInt(v) })} onValueChange={(v) => setNewOkr({ ...newOkr, quarter: parseInt(v) })}
@ -570,7 +570,7 @@ export default function StaffOKRs() {
onChange={(e) => setNewKr({ ...newKr, description: e.target.value })} onChange={(e) => setNewKr({ ...newKr, description: e.target.value })}
className="bg-slate-700 border-slate-600 text-slate-100" className="bg-slate-700 border-slate-600 text-slate-100"
/> />
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div> <div>
<label className="text-sm text-slate-400 mb-1 block">Target Value</label> <label className="text-sm text-slate-400 mb-1 block">Target Value</label>
<Input <Input

View file

@ -276,20 +276,20 @@ export default function StaffTimeTracking() {
<div className="relative z-10"> <div className="relative z-10">
<div className="container mx-auto max-w-6xl px-4 py-16"> <div className="container mx-auto max-w-6xl px-4 py-16">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-6"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 rounded-lg bg-blue-500/20 border border-blue-500/30"> <div className="p-3 rounded-lg bg-blue-500/20 border border-blue-500/30">
<Clock className="h-6 w-6 text-blue-400" /> <Clock className="h-6 w-6 text-blue-400" />
</div> </div>
<div> <div>
<h1 className="text-4xl font-bold text-blue-100">Time Tracking</h1> <h1 className="text-2xl sm:text-4xl font-bold text-blue-100">Time Tracking</h1>
<p className="text-blue-200/70">Track your work hours and projects</p> <p className="text-blue-200/70 text-sm sm:text-base">Track your work hours and projects</p>
</div> </div>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-wrap gap-2">
{activeTimer ? ( {activeTimer ? (
<Button <Button
className="bg-red-600 hover:bg-red-700" className="bg-red-600 hover:bg-red-700 flex-1 sm:flex-none"
onClick={stopTimer} onClick={stopTimer}
> >
<Square className="h-4 w-4 mr-2" /> <Square className="h-4 w-4 mr-2" />
@ -297,7 +297,7 @@ export default function StaffTimeTracking() {
</Button> </Button>
) : ( ) : (
<Button <Button
className="bg-green-600 hover:bg-green-700" className="bg-green-600 hover:bg-green-700 flex-1 sm:flex-none"
onClick={startTimer} onClick={startTimer}
> >
<Play className="h-4 w-4 mr-2" /> <Play className="h-4 w-4 mr-2" />
@ -305,7 +305,7 @@ export default function StaffTimeTracking() {
</Button> </Button>
)} )}
<Button <Button
className="bg-blue-600 hover:bg-blue-700" className="bg-blue-600 hover:bg-blue-700 flex-1 sm:flex-none"
onClick={() => setCreateDialog(true)} onClick={() => setCreateDialog(true)}
> >
<Plus className="h-4 w-4 mr-2" /> <Plus className="h-4 w-4 mr-2" />