Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,20 @@
.touch-target {
@apply flex items-center justify-center min-w-[44px] min-h-[44px] -m-2;
}

/* Tablet-specific responsive adjustments (768px-1024px) */
@media (min-width: 768px) and (max-width: 1024px) {
.page-header-row {
@apply px-6 py-4;
}

.page-title {
@apply text-xl;
}

/* Increase touch targets for tablet */
.touch-target {
@apply min-w-[48px] min-h-[48px];
}
}
Comment on lines +177 to +190

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all usages of the global utility classes that have tablet-only media queries

echo "=== Pages using .page-header-row ==="
rg -n --type=tsx --type=ts -C2 'page-header-row'

echo -e "\n=== Pages using .page-title ==="
rg -n --type=tsx --type=ts -C2 'page-title'

echo -e "\n=== Pages using .touch-target ==="
rg -n --type=tsx --type=ts -C2 'touch-target'

echo -e "\n=== Components using PageContainer (affected by spacing mismatch) ==="
rg -n --type=tsx --type=ts -C2 'PageContainer'

Repository: Pi-Defi-world/acbu-frontend

Length of output: 377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== globals.css relevant section ==="
ls -la app/globals.css
sed -n '150,220p' app/globals.css | nl -ba

echo
echo "=== Locate PageContainer implementation ==="
# Find the file that defines PageContainer
fd -a "page-container.*" . || true
fd -a "PageContainer" . || true

# Prefer common path; if not found, fall back to rg
pc_file="$(rg -l --hidden --glob '!*node_modules/*' --glob '!*dist/*' "PageContainer" . || true | head -n 1)"
echo "First match file for 'PageContainer': ${pc_file:-<none>}"

if [[ -n "${pc_file}" ]]; then
  echo "=== PageContainer lines around first occurrence ==="
  rg -n --glob '*.tsx' --glob '*.ts' --hidden --glob '!*node_modules/*' --glob '!*dist/*' "PageContainer" "$pc_file" || true
  sed -n '1,220p' "$pc_file" | nl -ba | head -n 220
fi

echo
echo "=== Search for .page-header-row / .page-title / .touch-target usages (tsx/ts only) ==="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '*.tsx' --glob '*.ts' -C2 'page-header-row' . || true
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '*.tsx' --glob '*.ts' -C2 'page-title' . || true
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '*.tsx' --glob '*.ts' -C2 'touch-target' . || true

Repository: Pi-Defi-world/acbu-frontend

Length of output: 234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== globals.css tablet media query section ==="
# Show with line numbers using cat -n (nl not available)
cat -n app/globals.css | sed -n '150,220p'

echo
echo "=== Locate PageContainer definition ==="
# Search for definition/exports
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '*.tsx' --glob '*.ts' -S 'PageContainer' app || true

# Try locating the likely file by name first
echo
echo "=== Candidate files containing 'page-container' in name ==="
find app -maxdepth 6 -type f \( -iname '*page-container*' \) 2>/dev/null || true

echo
echo "=== Usage counts (tsx/ts) ==="
for cls in page-header-row page-title touch-target; do
  echo "--- $cls ---"
  rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '*.tsx' --glob '*.ts' -S "${cls}" app || true
done

Repository: Pi-Defi-world/acbu-frontend

Length of output: 15380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find PageContainer file explicitly by path pattern
find . -type f \( -iname '*page-container*' -o -path '*page-container*' \) | head -n 50

echo
# Print PageContainer component implementation (first match)
pc_file="$(find . -type f \( -iname 'page-container.tsx' -o -iname 'page-container.ts' \) | head -n 1)"
echo "Using: ${pc_file:-<none>}"
if [[ -n "${pc_file:-}" ]]; then
  sed -n '1,200p' "$pc_file" | cat -n
  echo
  rg -n "className=|md:px|px-|md:py|py-" "$pc_file" || true
fi

echo
echo "=== Inspect globals.css around tablet media query (for exact snippet) ==="
cat -n app/globals.css | sed -n '140,210p'

Repository: Pi-Defi-world/acbu-frontend

Length of output: 2624


Critical: Tablet-only (max-width) media query makes header styles revert on desktop vs PageContainer’s md:* spacing

In app/globals.css, .page-header-row / .page-title (and .touch-target) are only increased inside @media (min-width: 768px) and (max-width: 1024px). PageContainer uses unbounded md:px-6 md:py-6 ..., so on widths >1024px the content wrapper stays at px-6 while the header row reverts to base px-4 py-3 and the title to base text-lg (e.g., app/rates/page.tsx).

Recommended fix (align with Tailwind `md:` behavior)
-  `@media` (min-width: 768px) and (max-width: 1024px) {
+  `@media` (min-width: 768px) {
     .page-header-row {
       `@apply` px-6 py-4;
     }
 
     .page-title {
       `@apply` text-xl;
     }
 
     /* Increase touch targets for tablet */
     .touch-target {
       `@apply` min-w-[48px] min-h-[48px];
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@media (min-width: 768px) and (max-width: 1024px) {
.page-header-row {
@apply px-6 py-4;
}
.page-title {
@apply text-xl;
}
/* Increase touch targets for tablet */
.touch-target {
@apply min-w-[48px] min-h-[48px];
}
}
`@media` (min-width: 768px) {
.page-header-row {
`@apply` px-6 py-4;
}
.page-title {
`@apply` text-xl;
}
/* Increase touch targets for tablet */
.touch-target {
`@apply` min-w-[48px] min-h-[48px];
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/globals.css` around lines 177 - 190, The tablet-only media query causes
.page-header-row, .page-title and .touch-target to revert on desktop; change the
CSS rule that targets "`@media` (min-width: 768px) and (max-width: 1024px)" to be
unbounded from the top (e.g., "`@media` (min-width: 768px)") so the increased
padding/text size/touch-targets apply the same way Tailwind's md: utilities used
by PageContainer do; update the selectors for .page-header-row, .page-title, and
.touch-target accordingly so their md-equivalent styles match PageContainer's
md:px/md:py and text sizing on all widths >=768px.

}
42 changes: 21 additions & 21 deletions app/me/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,52 +235,52 @@ export default function MePage() {
return (
<>
<div className="bg-gradient-to-b from-primary/10 to-background border-b border-border">
<div className="px-4 py-6 space-y-4">
<div className="flex items-center gap-3">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center flex-shrink-0 text-white text-lg font-bold">{initials}</div>
<div className="px-4 py-6 space-y-4 md:px-6 md:py-8 md:max-w-4xl md:mx-auto">
<div className="flex items-center gap-3 md:gap-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center flex-shrink-0 text-white text-lg font-bold md:w-20 md:h-20 md:text-2xl">{initials}</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-0.5">
<h1 className="page-title truncate">{displayName}</h1>
<KycBadge status={user?.kyc_status} />
<h1 className="page-title truncate md:text-2xl">{displayName}</h1>
<LocalKycBadge status={user?.kyc_status} loading={loading} />
</div>
<p className="text-xs text-muted-foreground truncate">{user?.email || user?.phone_e164 || '—'}</p>
<p className="text-xs text-muted-foreground truncate md:text-sm">{user?.email || user?.phone_e164 || '—'}</p>
</div>
</div>
</div>
</div>

<PageContainer>
<div className="space-y-5">
<div className="grid grid-cols-2 gap-3">
<div className="rounded-lg border border-border bg-card p-4 text-center">
<p className="text-xs text-muted-foreground mb-2 font-medium">Total Balance</p>
<p className="text-2xl font-bold text-foreground">
<div className="grid grid-cols-2 gap-3 md:gap-4">
<div className="rounded-lg border border-border bg-card p-4 text-center md:p-6">
<p className="text-xs text-muted-foreground mb-2 font-medium md:text-sm">Total Balance</p>
<p className="text-2xl font-bold text-foreground md:text-3xl">
{balanceLoading ? '...' : `ACBU ${formatAmount(balance)}`}
</p>
</div>
<div className="rounded-lg border border-border bg-card p-4 text-center">
<p className="text-xs text-muted-foreground mb-2 font-medium">This Month</p>
<p className={`text-2xl font-bold ${monthlyNetPositive ? 'text-accent' : 'text-destructive'}`}>
<div className="rounded-lg border border-border bg-card p-4 text-center md:p-6">
<p className="text-xs text-muted-foreground mb-2 font-medium md:text-sm">This Month</p>
<p className={`text-2xl font-bold md:text-3xl ${monthlyNetPositive ? 'text-accent' : 'text-destructive'}`}>
{loading ? '...' : monthlyNet === null ? '—' : `${monthlyNetPositive ? '+' : '-'}ACBU ${formatAmount(Math.abs(monthlyNet))}`}
</p>
</div>
</div>

{menuItems.map((section) => (
<div key={section.section} className="space-y-2">
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wide px-1">{section.section}</h3>
<div className="space-y-2">
<div key={section.section} className="space-y-2 md:space-y-3">
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wide px-1 md:text-sm">{section.section}</h3>
<div className="space-y-2 md:space-y-3">
{section.items.map((item) => {
const Icon = item.icon;
return (
<Link key={item.href} href={item.href} className="w-full text-left transition-colors active:bg-muted">
<div className="rounded-lg border border-border bg-card p-4 flex items-center justify-between gap-3">
<div className="flex items-center gap-3 flex-1 min-w-0">
<Icon className="w-5 h-5 text-primary flex-shrink-0" />
<span className="font-medium text-foreground text-sm truncate">{item.title}</span>
<div className="rounded-lg border border-border bg-card p-4 flex items-center justify-between gap-3 md:p-5">
<div className="flex items-center gap-3 flex-1 min-w-0 md:gap-4">
<Icon className="w-5 h-5 text-primary flex-shrink-0 md:w-6 md:h-6" />
<span className="font-medium text-foreground text-sm truncate md:text-base">{item.title}</span>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<ArrowRight className="w-4 h-4 text-muted-foreground" />
<ArrowRight className="w-4 h-4 text-muted-foreground md:w-5 md:h-5" />
</div>
</div>
</Link>
Expand Down
80 changes: 40 additions & 40 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,61 +182,61 @@ export default function Home() {
return (
<>
<header className="page-header">
<div className="px-4 py-3">
<div className="px-4 py-3 md:px-6 md:py-4 md:max-w-4xl md:mx-auto">
<div className="flex items-center justify-between gap-2">
<div className="flex-1">
<h1 className="text-base font-bold text-foreground">Welcome back</h1>
<p className="text-xs text-muted-foreground">Manage your finances</p>
<h1 className="text-base font-bold text-foreground md:text-lg">Welcome back</h1>
<p className="text-xs text-muted-foreground md:text-sm">Manage your finances</p>
</div>
<div className="w-9 h-9 rounded-full bg-primary/20 flex items-center justify-center flex-shrink-0">
<div className="w-7 h-7 rounded-full bg-primary" />
<div className="w-9 h-9 rounded-full bg-primary/20 flex items-center justify-center flex-shrink-0 md:w-12 md:h-12">
<div className="w-7 h-7 rounded-full bg-primary md:w-10 md:h-10" />
</div>
</div>
</div>
</header>

<PageContainer>
<div className="space-y-5">
<div className="rounded-lg border border-border bg-gradient-to-br from-primary/20 via-secondary/10 to-transparent p-5 relative overflow-hidden">
<div className="rounded-lg border border-border bg-gradient-to-br from-primary/20 via-secondary/10 to-transparent p-5 relative overflow-hidden md:p-6">
<button
type="button"
onClick={() => setShowBalance(!showBalance)}
className="absolute top-4 right-4 p-1.5 hover:bg-muted rounded-full transition-colors flex-shrink-0 z-10"
className="absolute top-4 right-4 p-1.5 hover:bg-muted rounded-full transition-colors flex-shrink-0 z-10 md:p-2 md:top-5 md:right-5"
aria-label={showBalance ? 'Hide balances' : 'Show balances'}
>
{showBalance ? <Eye className="w-4 h-4 text-muted-foreground" /> : <EyeOff className="w-4 h-4 text-muted-foreground" />}
{showBalance ? <Eye className="w-4 h-4 text-muted-foreground md:w-5 md:h-5" /> : <EyeOff className="w-4 h-4 text-muted-foreground md:w-5 md:h-5" />}
</button>
<div className="flex items-start gap-3 pr-12 mb-1">
<div className="flex-1 min-w-0 border-r border-border/60 pr-3">
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground mb-1">
<div className="flex items-start gap-3 pr-12 mb-1 md:gap-6 md:pr-16">
<div className="flex-1 min-w-0 border-r border-border/60 pr-3 md:pr-6">
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground mb-1 md:text-xs">
ACBU
</p>
<p className="text-[10px] text-muted-foreground mb-1">Wallet balance</p>
<h2 className="text-2xl sm:text-3xl font-bold text-foreground tabular-nums">
<p className="text-[10px] text-muted-foreground mb-1 md:text-xs">Wallet balance</p>
<h2 className="text-2xl sm:text-3xl font-bold text-foreground tabular-nums md:text-4xl">
{!showBalance
? '••••••'
: balanceLoading
? <BalanceSkeleton variant="compact" />
: `ACBU ${formatAmount(balance)}`}
</h2>
{!showBalance ? (
<p className="text-sm text-muted-foreground mt-1.5 tabular-nums">••••••</p>
<p className="text-sm text-muted-foreground mt-1.5 tabular-nums md:text-base">••••••</p>
) : balanceLoading || ratesLoading ? (
<p className="text-sm text-muted-foreground mt-1.5"><BalanceSkeleton variant="compact" /></p>
<p className="text-sm text-muted-foreground mt-1.5 md:text-base"><BalanceSkeleton variant="compact" /></p>
) : acbuUsd != null ? (
<p className="text-sm text-muted-foreground mt-1.5 tabular-nums">
<p className="text-sm text-muted-foreground mt-1.5 tabular-nums md:text-base">
≈ USD {formatAmount(acbuUsd, 2)}
</p>
) : (
<p className="text-sm text-muted-foreground mt-1.5">≈ USD —</p>
<p className="text-sm text-muted-foreground mt-1.5 md:text-base">≈ USD —</p>
)}
</div>
<div className="flex-1 min-w-0 text-right">
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground mb-1">
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground mb-1 md:text-xs">
Fiat
</p>
<p className="text-[10px] text-muted-foreground mb-1">Simulated · USD equivalent</p>
<div className="text-2xl sm:text-3xl font-bold text-foreground tabular-nums space-y-1">
<p className="text-[10px] text-muted-foreground mb-1 md:text-xs">Simulated · USD equivalent</p>
<div className="text-2xl sm:text-3xl font-bold text-foreground tabular-nums space-y-1 md:text-4xl">
{!showBalance ? (
<p>••••••</p>
) : fiatLoading || ratesLoading ? (
Expand All @@ -248,12 +248,12 @@ export default function Home() {
{formatAmount(fiatUsdInfo?.usd ?? 0, 2)}
</p>
{fiatUsdInfo?.partial && fiatAccounts.length > 0 && (
<p className="text-[10px] font-normal text-muted-foreground">
<p className="text-[10px] font-normal text-muted-foreground md:text-xs">
Some currencies missing a rate
</p>
)}
{!fiatAccounts.length && (
<p className="text-sm font-normal text-muted-foreground mt-1">
<p className="text-sm font-normal text-muted-foreground mt-1 md:text-base">
<Link href="/fiat" className="text-primary font-medium underline-offset-2 hover:underline">
Add demo funds
</Link>
Expand All @@ -265,31 +265,31 @@ export default function Home() {
</div>
</div>
{showBalance && balanceError && (
<div className="flex items-center gap-1 text-xs text-destructive mt-2">
<div className="flex items-center gap-1 text-xs text-destructive mt-2 md:text-sm">
<span>{balanceError}</span>
</div>
)}
</div>

<div className="grid grid-cols-2 gap-3">
<div className="grid grid-cols-2 gap-3 md:grid-cols-3 md:gap-4">
{features.map((feature) => {
const Icon = feature.icon;
return (
<Link key={feature.href} href={feature.href} className="block">
<div className={`${feature.color} rounded-lg border border-border/50 p-4 h-full transition-all active:scale-95`}>
<Icon className={`w-6 h-6 ${feature.iconColor} mb-2`} />
<h3 className="text-sm font-semibold text-foreground mb-0.5">{feature.title}</h3>
<p className="text-xs text-muted-foreground">{feature.description}</p>
<div className={`${feature.color} rounded-lg border border-border/50 p-4 h-full transition-all active:scale-95 md:p-5`}>
<Icon className={`w-6 h-6 ${feature.iconColor} mb-2 md:w-7 md:h-7 md:mb-3`} />
<h3 className="text-sm font-semibold text-foreground mb-0.5 md:text-base">{feature.title}</h3>
<p className="text-xs text-muted-foreground md:text-sm">{feature.description}</p>
</div>
</Link>
);
})}
</div>

<div className="space-y-3">
<div className="space-y-3 md:space-y-4">
<div className="flex items-center justify-between px-1">
<h3 className="text-sm font-semibold text-foreground">Recent Activity</h3>
<Link href="/activity" className="text-xs text-primary font-medium">View all</Link>
<h3 className="text-sm font-semibold text-foreground md:text-base">Recent Activity</h3>
<Link href="/activity" className="text-xs text-primary font-medium md:text-sm">View all</Link>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
{loading ? (
Expand All @@ -305,12 +305,12 @@ export default function Home() {
}
/>
) : (
<div className="space-y-2">
<div className="space-y-2 md:space-y-3">
{transactions.slice(0, 5).map((t) => (
<Link key={t.transaction_id} href={`/transactions/${t.transaction_id}`} className="block rounded-lg border border-border bg-card p-3 transition-colors active:bg-muted">
<Link key={t.transaction_id} href={`/transactions/${t.transaction_id}`} className="block rounded-lg border border-border bg-card p-3 transition-colors active:bg-muted md:p-4">
<div className="flex items-center gap-3 mb-2">
<div
className={`p-2 rounded-full flex-shrink-0 ${
className={`p-2 rounded-full flex-shrink-0 md:p-3 ${
t.type === 'mint'
? 'bg-green-100 dark:bg-green-900/30'
: t.type === 'burn'
Expand All @@ -319,7 +319,7 @@ export default function Home() {
}`}
>
<ArrowUpRight
className={`w-4 h-4 ${
className={`w-4 h-4 md:w-5 md:h-5 ${
t.type === 'mint'
? 'text-green-600 dark:text-green-400'
: t.type === 'burn'
Expand All @@ -329,14 +329,14 @@ export default function Home() {
/>
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-foreground truncate">
<p className="text-sm font-medium text-foreground truncate md:text-base">
{t.type === 'mint' ? 'Mint' : t.type === 'burn' ? 'Burn' : 'Transfer'}
</p>
<p className="text-xs text-muted-foreground">{formatDate(t.created_at)}</p>
<p className="text-xs text-muted-foreground md:text-sm">{formatDate(t.created_at)}</p>
</div>
</div>
<div className="flex items-center justify-between pl-11">
<p className="text-sm font-semibold text-foreground">
<div className="flex items-center justify-between pl-11 md:pl-14">
<p className="text-sm font-semibold text-foreground md:text-base">
{t.type === 'burn'
? `- ACBU ${formatAcbu(t.acbu_amount_burned ?? t.amount_acbu)}`
: t.type === 'mint'
Expand All @@ -347,7 +347,7 @@ export default function Home() {
: '—'
: `ACBU ${formatAcbu(t.amount_acbu)}`}
</p>
<Badge variant="outline" className="text-xs">{t.status}</Badge>
<Badge variant="outline" className="text-xs md:text-sm">{t.status}</Badge>
</div>
</Link>
))}
Expand Down
2 changes: 1 addition & 1 deletion components/app-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function AppLayout({ children }: AppLayoutProps) {

return (
<div className="min-h-screen bg-background flex flex-col">
<main className={`flex-1 ${!isPublic ? 'pb-24' : ''}`}>{children}</main>
<main className={`flex-1 ${!isPublic ? 'pb-24 md:pb-28' : ''}`}>{children}</main>
{!isPublic && <MobileNav />}
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions components/layout/page-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ interface PageContainerProps {
}

/**
* Mobile-first content wrapper: px-4 py-4 pb-24 so content is never hidden under the bottom nav (h-20).
* Mobile-first content wrapper with tablet-optimized spacing.
* - Mobile (< 768px): px-4 py-4 pb-24
* - Tablet (768px-1024px): px-6 py-6 pb-28 with max-width constraint
* - Desktop (> 1024px): Inherits tablet styles
*/
export function PageContainer({ children, className = '' }: PageContainerProps) {
return (
<div className={`px-4 py-4 pb-24 ${className}`.trim()}>
<div className={`px-4 py-4 pb-24 md:px-6 md:py-6 md:pb-28 md:max-w-4xl md:mx-auto ${className}`.trim()}>
{children}
</div>
);
Expand Down
Loading