fix(mobile): comprehensive mobile UI redesign for better UX

- Header: icon-only wallet button on mobile, fix hamburger overflow
- Dashboard: responsive tabs with flex-wrap and smaller text
- Citizens: responsive ID card layout, stack NFT badges on mobile
- BeCitizen: stack header buttons vertically on mobile
- GovernanceInterface: add scrollable tabs
- DEXDashboard: responsive admin buttons grid (2 cols on mobile)
- P2PDashboard: responsive header and scrollable tabs
- Dialog: mobile-first sizing with proper padding and max-height
- Tabs UI: base responsive classes for all tab components
- Add xs:480px breakpoint and scrollbar-hide utility
- Fix vite polyfills config to prevent initialization errors
This commit is contained in:
2026-02-11 02:14:32 +03:00
parent 3fc4d685ae
commit 6010ace1b0
13 changed files with 81 additions and 52 deletions
+2 -2
View File
@@ -72,11 +72,11 @@ const AppLayout: React.FC = () => {
</div>
{/* Mobile: Wallet + Hamburger */}
<div className="flex lg:hidden items-center gap-2 w-full justify-end">
<div className="flex lg:hidden items-center gap-2 ml-auto">
<PezkuwiWalletButton />
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="p-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors"
className="p-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-800 transition-colors flex-shrink-0"
>
{mobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</button>
+1 -1
View File
@@ -26,7 +26,7 @@ const GovernanceInterface: React.FC = () => {
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid grid-cols-3 lg:grid-cols-6 gap-2 bg-gray-900/50 p-1 rounded-lg">
<TabsList className="grid grid-cols-3 lg:grid-cols-6 gap-2 bg-gray-900/50 p-1 rounded-lg overflow-x-auto scrollbar-hide">
<TabsTrigger value="overview" className="flex items-center space-x-2">
<TrendingUp className="w-4 h-4" />
<span>Overview</span>
+15 -7
View File
@@ -11,6 +11,7 @@ import {
} from '@/components/ui/dialog';
import { Wallet, Check, ExternalLink, Copy, LogOut } from 'lucide-react';
import { useToast } from '@/hooks/use-toast';
import { useIsMobile } from '@/hooks/use-mobile';
export const PezkuwiWalletButton: React.FC = () => {
const {
@@ -24,6 +25,7 @@ export const PezkuwiWalletButton: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const { toast } = useToast();
const isMobile = useIsMobile();
const handleConnect = async () => {
await connectWallet();
@@ -70,12 +72,17 @@ export const PezkuwiWalletButton: React.FC = () => {
variant="outline"
className="bg-green-500/20 border-green-500/50 text-green-400 hover:bg-green-500/30"
onClick={() => setIsOpen(true)}
size={isMobile ? "icon" : "default"}
>
<Wallet className="w-4 h-4 mr-2" />
{selectedAccount.meta.name || 'Account'}
<Badge className="ml-2 bg-green-500/30 text-green-300 border-0">
{formatAddress(selectedAccount.address)}
</Badge>
<Wallet className={isMobile ? "w-4 h-4" : "w-4 h-4 mr-2"} />
{!isMobile && (
<>
{selectedAccount.meta.name || 'Account'}
<Badge className="ml-2 bg-green-500/30 text-green-300 border-0">
{formatAddress(selectedAccount.address)}
</Badge>
</>
)}
</Button>
<Button
variant="ghost"
@@ -169,9 +176,10 @@ export const PezkuwiWalletButton: React.FC = () => {
<Button
onClick={handleConnect}
className="bg-gradient-to-r from-green-600 to-yellow-400 hover:from-green-700 hover:to-yellow-500 text-white"
size={isMobile ? "icon" : "default"}
>
<Wallet className="w-4 h-4 mr-2" />
Connect Wallet
<Wallet className={isMobile ? "w-4 h-4" : "w-4 h-4 mr-2"} />
{!isMobile && "Connect Wallet"}
</Button>
{error && error.includes('not found') && (
+1 -1
View File
@@ -137,7 +137,7 @@ export const DEXDashboard: React.FC = () => {
<p className="text-gray-400 mb-6">
Mint wrapped tokens for testing and liquidity provision
</p>
<div className="grid grid-cols-2 gap-3">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
<button
onClick={() => setShowInitializeUsdtModal(true)}
className="flex items-center justify-center gap-2 px-4 py-3 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors font-medium"
+14 -14
View File
@@ -82,7 +82,7 @@ export function P2PDashboard() {
return (
<div className="container mx-auto px-4 py-8 max-w-7xl">
<div className="flex items-center justify-between mb-4">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mb-4">
<Button
variant="ghost"
onClick={() => navigate('/')}
@@ -91,7 +91,7 @@ export function P2PDashboard() {
<Home className="w-4 h-4 mr-2" />
Back to Home
</Button>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
<NotificationBell />
<Button
variant="outline"
@@ -168,12 +168,12 @@ export function P2PDashboard() {
</div>
)}
<div className="flex items-center justify-between mb-8">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8">
<div>
<h1 className="text-4xl font-bold text-white">P2P Trading</h1>
<p className="text-gray-400">Buy and sell crypto with your local currency.</p>
<h1 className="text-3xl sm:text-4xl font-bold text-white">P2P Trading</h1>
<p className="text-gray-400 text-sm sm:text-base">Buy and sell crypto with your local currency.</p>
</div>
<Button onClick={() => setShowCreateAd(true)}>
<Button onClick={() => setShowCreateAd(true)} className="w-full sm:w-auto">
<PlusCircle className="w-4 h-4 mr-2" />
Post a New Ad
</Button>
@@ -187,17 +187,17 @@ export function P2PDashboard() {
<QuickFilterBar filters={filters} onFiltersChange={setFilters} />
<Tabs defaultValue="buy">
<TabsList className="grid w-full grid-cols-5">
<TabsTrigger value="express" className="flex items-center gap-1">
<TabsList className="grid w-full grid-cols-5 overflow-x-auto scrollbar-hide">
<TabsTrigger value="express" className="flex items-center gap-1 text-xs sm:text-sm px-1 sm:px-3">
<Zap className="w-3 h-3" />
Express
<span className="hidden xs:inline">Express</span>
</TabsTrigger>
<TabsTrigger value="buy">Buy</TabsTrigger>
<TabsTrigger value="sell">Sell</TabsTrigger>
<TabsTrigger value="my-ads">My Ads</TabsTrigger>
<TabsTrigger value="otc" className="flex items-center gap-1">
<TabsTrigger value="buy" className="text-xs sm:text-sm px-1 sm:px-3">Buy</TabsTrigger>
<TabsTrigger value="sell" className="text-xs sm:text-sm px-1 sm:px-3">Sell</TabsTrigger>
<TabsTrigger value="my-ads" className="text-xs sm:text-sm px-1 sm:px-3">My Ads</TabsTrigger>
<TabsTrigger value="otc" className="flex items-center gap-1 text-xs sm:text-sm px-1 sm:px-3">
<Blocks className="w-3 h-3" />
OTC
<span className="hidden xs:inline">OTC</span>
</TabsTrigger>
</TabsList>
<TabsContent value="express">
+1 -1
View File
@@ -36,7 +36,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border/40 bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
"fixed left-[50%] top-[50%] z-50 grid w-[calc(100vw-2rem)] sm:w-full max-w-lg max-h-[90vh] overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border border-border/40 bg-background p-4 sm:p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg sm:rounded-lg",
className
)}
{...props}
+2 -2
View File
@@ -12,7 +12,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted/50 p-1 text-muted-foreground",
"inline-flex h-auto min-h-10 items-center justify-center rounded-md bg-muted/50 p-1 text-muted-foreground flex-wrap gap-1",
className
)}
{...props}
@@ -27,7 +27,7 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-primary data-[state=active]:shadow-sm hover:text-foreground",
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-2 sm:px-3 py-1.5 text-xs sm:text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-primary data-[state=active]:shadow-sm hover:text-foreground",
className
)}
{...props}