fix: mobile-first UI redesign - bump all text to 12px+, 44px+ touch targets, reduced content density
This commit is contained in:
@@ -248,7 +248,7 @@ export default function ThreadDetailPage() {
|
||||
<Star size={12} className="text-[#D4AF37]" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 text-[10px] text-gray-600">
|
||||
<div className="flex items-center gap-1.5 text-xs text-gray-600">
|
||||
<span className="text-gray-500">{thread.category.name}</span>
|
||||
<span>·</span>
|
||||
<span>{timeAgo(thread.createdAt)}</span>
|
||||
@@ -259,7 +259,7 @@ export default function ThreadDetailPage() {
|
||||
const Icon = SHARIAH_LABELS[thread.shariahStatus].icon;
|
||||
return <Icon size={9} />;
|
||||
})()}
|
||||
<span className="text-[9px]">{SHARIAH_LABELS[thread.shariahStatus].label}</span>
|
||||
<span className="text-[10px]">{SHARIAH_LABELS[thread.shariahStatus].label}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,7 +310,7 @@ export default function ThreadDetailPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-[10px] text-gray-600">
|
||||
<div className="flex items-center gap-1 text-xs text-gray-600">
|
||||
<Clock size={9} />
|
||||
<span>{timeAgo(post.createdAt)}</span>
|
||||
</div>
|
||||
@@ -324,7 +324,7 @@ export default function ThreadDetailPage() {
|
||||
{/* Shariah compliance label */}
|
||||
<div className={`flex items-center gap-0.5 ${shariahInfo.color}`}>
|
||||
<ShariahIcon size={9} />
|
||||
<span className="text-[9px]">{shariahInfo.label}</span>
|
||||
<span className="text-[10px]">{shariahInfo.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -342,7 +342,7 @@ export default function ThreadDetailPage() {
|
||||
</p>
|
||||
<button
|
||||
onClick={() => router.push("/profile")}
|
||||
className="inline-flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-2 text-xs font-medium text-[#D4AF37] active:bg-[#D4AF37]/25 transition"
|
||||
className="inline-flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-3 text-xs font-medium text-[#D4AF37] active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Crown size={12} />
|
||||
Upgrade Now
|
||||
@@ -360,13 +360,13 @@ export default function ThreadDetailPage() {
|
||||
className="w-full bg-transparent px-4 py-3 text-sm text-white placeholder-gray-600 focus:outline-none resize-none"
|
||||
/>
|
||||
<div className="flex items-center justify-between px-4 pb-3">
|
||||
<span className="text-[10px] text-gray-600">
|
||||
<span className="text-xs text-gray-600">
|
||||
{replyContent.length}/5000
|
||||
</span>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={submitting || !replyContent.trim()}
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37] text-[#0a0a0f] rounded-xl px-4 py-2 text-xs font-semibold transition active:bg-[#c5a233] disabled:opacity-50"
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37] text-[#0a0a0f] rounded-xl px-4 py-3 text-xs font-semibold transition active:bg-[#c5a233] disabled:opacity-50"
|
||||
>
|
||||
{submitting ? (
|
||||
<>
|
||||
|
||||
+14
-14
@@ -222,7 +222,7 @@ export default function ForumPage() {
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-bold text-white">Forum</h1>
|
||||
<p className="text-[10px] text-gray-500">Community Discussions</p>
|
||||
<p className="text-xs text-gray-500">Community Discussions</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -237,7 +237,7 @@ export default function ForumPage() {
|
||||
setCreateError(null);
|
||||
setShowCreateModal(true);
|
||||
}}
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-3 py-2 active:bg-[#D4AF37]/25 transition"
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-3 py-3 active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Plus size={14} className="text-[#D4AF37]" />
|
||||
<span className="text-xs font-medium text-[#D4AF37]">New Thread</span>
|
||||
@@ -253,7 +253,7 @@ export default function ForumPage() {
|
||||
<div className="flex items-center gap-2">
|
||||
<Lock size={14} className="text-[#D4AF37] shrink-0" />
|
||||
<div className="flex-1">
|
||||
<p className="text-[11px] text-amber-300/90">
|
||||
<p className="text-xs text-amber-300/90">
|
||||
<span className="font-semibold">Free</span> members can browse.{" "}
|
||||
<span className="text-[#D4AF37] font-semibold">Premium</span> or{" "}
|
||||
<span className="text-purple-400 font-semibold">Pro</span> required to post.
|
||||
@@ -261,7 +261,7 @@ export default function ForumPage() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/profile")}
|
||||
className="text-[10px] font-semibold text-[#D4AF37] bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-lg px-2.5 py-1.5 active:bg-[#D4AF37]/25 transition"
|
||||
className="text-xs font-semibold text-[#D4AF37] bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-lg px-2.5 py-3 active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
Upgrade
|
||||
</button>
|
||||
@@ -278,7 +278,7 @@ export default function ForumPage() {
|
||||
placeholder="Search threads..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full bg-[#111118] border border-gray-800/60 rounded-xl pl-10 pr-4 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
className="w-full bg-[#111118] border border-gray-800/60 rounded-xl pl-10 pr-4 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,7 +363,7 @@ export default function ForumPage() {
|
||||
setCreateError(null);
|
||||
setShowCreateModal(true);
|
||||
}}
|
||||
className="mt-4 flex items-center gap-2 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-2.5 active:bg-[#D4AF37]/25 transition"
|
||||
className="mt-4 flex items-center gap-2 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-3 active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Plus size={16} className="text-[#D4AF37]" />
|
||||
<span className="text-sm font-medium text-[#D4AF37]">Start Discussion</span>
|
||||
@@ -395,7 +395,7 @@ export default function ForumPage() {
|
||||
</div>
|
||||
|
||||
{/* Meta row */}
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-[10px] text-gray-600">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-gray-600">
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-gray-500">by</span>
|
||||
<span className={`font-medium ${
|
||||
@@ -431,12 +431,12 @@ export default function ForumPage() {
|
||||
<div className="flex items-center gap-2 mt-1.5">
|
||||
<div className={`flex items-center gap-0.5 ${shariahInfo.color}`}>
|
||||
<ShariahIcon size={9} />
|
||||
<span className="text-[9px]">{shariahInfo.label}</span>
|
||||
<span className="text-[10px]">{shariahInfo.label}</span>
|
||||
</div>
|
||||
<span className="text-gray-700">·</span>
|
||||
<div className="flex items-center gap-0.5 text-gray-600">
|
||||
<Clock size={9} />
|
||||
<span className="text-[9px]">{timeAgo(thread.createdAt)}</span>
|
||||
<span className="text-xs">{timeAgo(thread.createdAt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -480,7 +480,7 @@ export default function ForumPage() {
|
||||
setCreateForm((f) => ({ ...f, categoryId: e.target.value }))
|
||||
}
|
||||
required
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-[#D4AF37]/40 transition appearance-none"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white focus:outline-none focus:border-[#D4AF37]/40 transition appearance-none"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
@@ -508,7 +508,7 @@ export default function ForumPage() {
|
||||
placeholder="What's on your mind?"
|
||||
required
|
||||
maxLength={200}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -525,7 +525,7 @@ export default function ForumPage() {
|
||||
required
|
||||
maxLength={10000}
|
||||
rows={5}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition resize-none"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -539,14 +539,14 @@ export default function ForumPage() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(false)}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={creating}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
>
|
||||
{creating ? (
|
||||
<>
|
||||
|
||||
+44
-1
@@ -20,6 +20,12 @@
|
||||
|
||||
* {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -27,15 +33,40 @@ body {
|
||||
color: var(--text-primary);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-bottom: 80px;
|
||||
min-height: 100dvh;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Mobile-first container: caps content width for comfortable reading */
|
||||
.mobile-container {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
.mobile-container {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Force all interactive elements to min 44px touch target */
|
||||
.touch-target {
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
width: 3px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
@@ -81,3 +112,15 @@ body {
|
||||
.flame {
|
||||
animation: flicker 0.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Prevent text size adjustment on orientation change */
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* Better readability on OLED screens */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ export default function HalalMonitorPage() {
|
||||
{usage && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-right">
|
||||
<p className="text-[10px] text-gray-500">Today</p>
|
||||
<p className="text-xs text-gray-500">Today</p>
|
||||
<p className="text-xs font-semibold text-gray-300">
|
||||
{usage.remaining}/{usage.queriesLimit}
|
||||
</p>
|
||||
@@ -313,7 +313,7 @@ export default function HalalMonitorPage() {
|
||||
<p className="text-sm font-semibold text-emerald-400">
|
||||
Upgrade for Unlimited
|
||||
</p>
|
||||
<p className="text-[11px] text-gray-500">
|
||||
<p className="text-xs text-gray-500">
|
||||
Unlock restaurants + cafes & unlimited queries
|
||||
</p>
|
||||
</div>
|
||||
@@ -324,7 +324,7 @@ export default function HalalMonitorPage() {
|
||||
|
||||
{/* Free user scope notice */}
|
||||
{isFree && (
|
||||
<div className="mt-2 flex items-center gap-1.5 text-[11px] text-amber-400/70">
|
||||
<div className="mt-2 flex items-center gap-1.5 text-xs text-amber-400/70">
|
||||
<Crown size={12} />
|
||||
Free tier: mosques only • 10 queries/day
|
||||
</div>
|
||||
@@ -333,7 +333,7 @@ export default function HalalMonitorPage() {
|
||||
|
||||
{/* ── Search Bar ─────────────────────────────────────────────────── */}
|
||||
<div className="px-4 mb-3">
|
||||
<div className="flex items-center gap-2 bg-[#111118] border border-gray-800/60 rounded-2xl px-4 py-2.5">
|
||||
<div className="flex items-center gap-2 bg-[#111118] border border-gray-800/60 rounded-2xl px-4 py-3">
|
||||
<Search size={16} className="text-gray-500 shrink-0" />
|
||||
<input
|
||||
type="text"
|
||||
@@ -397,7 +397,7 @@ export default function HalalMonitorPage() {
|
||||
<div className="w-10 h-10 rounded-full bg-emerald-500/20 border-2 border-emerald-500/40 flex items-center justify-center animate-pulse">
|
||||
<MapPin size={18} className="text-emerald-400" />
|
||||
</div>
|
||||
<span className="text-[10px] text-emerald-500/60 font-medium">
|
||||
<span className="text-xs text-emerald-500/60 font-medium">
|
||||
{visiblePlaces.length} places found
|
||||
</span>
|
||||
</div>
|
||||
@@ -460,7 +460,7 @@ export default function HalalMonitorPage() {
|
||||
{place.name}
|
||||
</h3>
|
||||
<span
|
||||
className={`text-[10px] font-medium px-2 py-0.5 rounded-full shrink-0 ${
|
||||
className={`text-xs font-medium px-2 py-0.5 rounded-full shrink-0 ${
|
||||
place.type === "mosque"
|
||||
? "bg-emerald-500/15 text-emerald-300 border border-emerald-500/30"
|
||||
: "bg-amber-500/15 text-amber-300 border border-amber-500/30"
|
||||
@@ -480,7 +480,7 @@ export default function HalalMonitorPage() {
|
||||
|
||||
{/* Halal badge */}
|
||||
{place.halal_certified && (
|
||||
<span className="inline-flex items-center gap-1 text-[10px] font-medium text-emerald-400 bg-emerald-500/10 px-2 py-0.5 rounded-full">
|
||||
<span className="inline-flex items-center gap-1 text-xs font-medium text-emerald-400 bg-emerald-500/10 px-2 py-0.5 rounded-full">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
|
||||
Halal Certified
|
||||
</span>
|
||||
@@ -584,13 +584,13 @@ export default function HalalMonitorPage() {
|
||||
{/* Coords */}
|
||||
<div className="grid grid-cols-2 gap-3 mb-5">
|
||||
<div className="bg-[#0a0a0f] rounded-xl p-3 text-center">
|
||||
<p className="text-[10px] text-gray-600">Latitude</p>
|
||||
<p className="text-xs text-gray-600">Latitude</p>
|
||||
<p className="text-xs text-gray-300 font-mono">
|
||||
{selectedPlace.lat.toFixed(4)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-[#0a0a0f] rounded-xl p-3 text-center">
|
||||
<p className="text-[10px] text-gray-600">Longitude</p>
|
||||
<p className="text-xs text-gray-600">Longitude</p>
|
||||
<p className="text-xs text-gray-300 font-mono">
|
||||
{selectedPlace.lng.toFixed(4)}
|
||||
</p>
|
||||
|
||||
+3
-7
@@ -2,7 +2,6 @@ import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import { AuthProvider } from "@/lib/AuthContext";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import NotificationBell from "@/components/NotificationBell";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Falah — Islamic Lifestyle",
|
||||
@@ -20,7 +19,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" className="dark">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1, user-scalable=no" />
|
||||
<meta name="theme-color" content="#0a0a0f" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
@@ -28,11 +27,8 @@ export default function RootLayout({
|
||||
</head>
|
||||
<body>
|
||||
<AuthProvider>
|
||||
<div className="relative">
|
||||
<div className="absolute top-4 right-4 z-40">
|
||||
<NotificationBell />
|
||||
</div>
|
||||
<main>{children}</main>
|
||||
<div className="mobile-container relative min-h-dvh">
|
||||
<main className="pb-4">{children}</main>
|
||||
</div>
|
||||
<BottomNav />
|
||||
</AuthProvider>
|
||||
|
||||
@@ -133,7 +133,7 @@ export default function LoginPage() {
|
||||
|
||||
{/* Demo credentials */}
|
||||
<div className="rounded-xl bg-[#111118] border border-gray-800/60 p-3 text-center">
|
||||
<p className="text-[10px] text-gray-600 uppercase tracking-wider mb-1">
|
||||
<p className="text-xs text-gray-600 uppercase tracking-wider mb-1">
|
||||
Demo Account
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
|
||||
@@ -214,7 +214,7 @@ function NurChat() {
|
||||
<Bot size={16} className="text-[#D4AF37]" />
|
||||
Nur AI
|
||||
</h1>
|
||||
<p className="text-[10px] text-gray-600">
|
||||
<p className="text-xs text-gray-600">
|
||||
{isPro ? "Pro Plan" : isPremium ? "Premium Plan" : "Free Plan"}
|
||||
</p>
|
||||
</div>
|
||||
@@ -222,9 +222,9 @@ function NurChat() {
|
||||
{!isPremium && (
|
||||
<Link
|
||||
href="/upgrade"
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-full px-3 py-1.5 text-[11px] font-semibold text-[#D4AF37] active:bg-[#D4AF37]/25 transition"
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-full px-4 py-2 min-h-[36px] text-xs font-semibold text-[#D4AF37] active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Sparkles size={12} />
|
||||
<Sparkles size={14} />
|
||||
Upgrade
|
||||
</Link>
|
||||
)}
|
||||
@@ -248,7 +248,7 @@ function NurChat() {
|
||||
{/* ── Daily Cap Bar ── */}
|
||||
<div className="px-4 mt-3">
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<span className="text-[11px] text-gray-500 font-medium">
|
||||
<span className="text-xs text-gray-500 font-medium">
|
||||
{isUnlimited ? (
|
||||
<span className="text-emerald-400 flex items-center gap-1">
|
||||
<CheckCircle2 size={12} />
|
||||
@@ -259,7 +259,7 @@ function NurChat() {
|
||||
)}
|
||||
</span>
|
||||
{!isUnlimited && remaining <= 3 && remaining > 0 && (
|
||||
<span className="text-[10px] text-amber-400 font-medium">
|
||||
<span className="text-xs text-amber-400 font-medium">
|
||||
{remaining} left
|
||||
</span>
|
||||
)}
|
||||
@@ -289,7 +289,7 @@ function NurChat() {
|
||||
<p className="text-sm font-semibold text-white">
|
||||
You've hit your daily limit
|
||||
</p>
|
||||
<p className="text-[11px] text-gray-500 mt-0.5">
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
Upgrade to Premium for 100 messages/day or Pro for unlimited access.
|
||||
</p>
|
||||
<Link
|
||||
@@ -448,7 +448,7 @@ function PersonaSelector({
|
||||
>
|
||||
{persona.name}
|
||||
</span>
|
||||
<span className="text-[8px] text-center leading-tight text-gray-600 max-w-[72px]">
|
||||
<span className="text-[10px] text-center leading-tight text-gray-600 max-w-[72px]">
|
||||
{persona.description}
|
||||
</span>
|
||||
{!accessible && (
|
||||
@@ -494,7 +494,7 @@ function MessageBubble({ message, isPremium, isPro }: { message: ChatMessage; is
|
||||
{message.content}
|
||||
{message.createdAt && (
|
||||
<div
|
||||
className={`text-[10px] mt-2 ${
|
||||
className={`text-xs mt-2 ${
|
||||
isUser ? "text-[#0a0a0f]/50" : "text-gray-600"
|
||||
}`}
|
||||
>
|
||||
|
||||
+28
-28
@@ -110,15 +110,15 @@ export default function HomePage() {
|
||||
<span className={`text-sm font-bold ${currentStreak > 0 ? "text-orange-300" : "text-gray-500"}`}>
|
||||
{currentStreak}
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-500">day</span>
|
||||
<span className="text-xs text-gray-500">day</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* XP Progress Bar */}
|
||||
<div className="mt-2">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-[10px] text-gray-500">XP Progress</span>
|
||||
<span className="text-[10px] text-gray-500">{currentXp} / {xpToNext} XP</span>
|
||||
<span className="text-xs text-gray-500">XP Progress</span>
|
||||
<span className="text-xs text-gray-500">{currentXp} / {xpToNext} XP</span>
|
||||
</div>
|
||||
<div className="h-1.5 bg-gray-800 rounded-full overflow-hidden">
|
||||
<div
|
||||
@@ -131,14 +131,14 @@ export default function HomePage() {
|
||||
{/* Premium banner */}
|
||||
{!isPremium && (
|
||||
<Link href="/upgrade"
|
||||
className="mt-3 flex items-center justify-between glass-gold rounded-2xl px-4 py-3 active:opacity-80 transition">
|
||||
className="mt-3 flex items-center justify-between glass-gold rounded-2xl px-4 py-3.5 active:opacity-80 transition min-h-[44px]">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-full bg-[#D4AF37]/20 flex items-center justify-center">
|
||||
<Sparkles size={16} className="text-[#D4AF37]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-[#D4AF37]">Go Premium</p>
|
||||
<p className="text-[11px] text-gray-500">Unlock unlimited AI & more</p>
|
||||
<p className="text-xs text-gray-500">Unlock unlimited AI & more</p>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight size={16} className="text-[#D4AF37]" />
|
||||
@@ -147,7 +147,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Pro badge */}
|
||||
{isPro && (
|
||||
<div className="mt-3 flex items-center gap-2 bg-purple-900/20 border border-purple-500/30 rounded-2xl px-4 py-2.5">
|
||||
<div className="mt-3 flex items-center gap-2 bg-purple-900/20 border border-purple-500/30 rounded-2xl px-4 py-3 min-h-[44px]">
|
||||
<Crown size={16} className="text-purple-400" />
|
||||
<span className="text-sm font-medium text-purple-300">Pro Member — Unlimited Everything</span>
|
||||
</div>
|
||||
@@ -155,27 +155,27 @@ export default function HomePage() {
|
||||
|
||||
{/* FLH Earning Rate - shown for premium/pro */}
|
||||
{(isPremium || isPro) && (
|
||||
<div className="mt-2 flex items-center gap-2 bg-gradient-to-r from-[#D4AF37]/10 to-purple-900/10 border border-[#D4AF37]/20 rounded-2xl px-4 py-2">
|
||||
<div className="mt-2 flex items-center gap-2 bg-gradient-to-r from-[#D4AF37]/10 to-purple-900/10 border border-[#D4AF37]/20 rounded-2xl px-4 py-3 min-h-[44px]">
|
||||
<TrendingUp size={14} className="text-[#D4AF37]" />
|
||||
<span className="text-xs font-semibold text-[#D4AF37]">2x Earning Active</span>
|
||||
<span className="text-[10px] text-gray-500">— Earn double FLH on marketplace sales</span>
|
||||
<span className="text-xs text-gray-500">— Earn double FLH on marketplace sales</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Daily Verse */}
|
||||
<div className="mx-4 mb-5 bg-gradient-to-br from-emerald-900/20 to-[#111118] border border-emerald-800/30 rounded-2xl p-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="mx-4 mb-5 bg-gradient-to-br from-emerald-900/20 to-[#111118] border border-emerald-800/30 rounded-2xl p-5">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<BookOpen size={14} className="text-emerald-400" />
|
||||
<span className="text-xs font-medium text-emerald-400">Daily Verse</span>
|
||||
</div>
|
||||
<p className="text-lg text-center font-arabic text-emerald-100 mb-2" dir="rtl">
|
||||
<p className="text-lg text-center font-arabic text-emerald-100 mb-3" dir="rtl">
|
||||
{verse.arabic}
|
||||
</p>
|
||||
<p className="text-sm text-gray-400 text-center italic">
|
||||
“{verse.translation}”
|
||||
</p>
|
||||
<p className="text-[10px] text-gray-600 text-center mt-1">— {verse.reference}</p>
|
||||
<p className="text-xs text-gray-600 text-center mt-2">— {verse.reference}</p>
|
||||
</div>
|
||||
|
||||
{/* Streak Reward Card */}
|
||||
@@ -184,7 +184,7 @@ export default function HomePage() {
|
||||
canClaim
|
||||
? "from-orange-900/20 to-amber-900/10 border-orange-700/30"
|
||||
: "from-gray-900/30 to-gray-800/10 border-gray-800/30"
|
||||
} border rounded-2xl p-4`}>
|
||||
} border rounded-2xl p-5`}>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-9 h-9 rounded-xl ${canClaim ? "bg-orange-900/40" : "bg-gray-800/40"} flex items-center justify-center`}>
|
||||
@@ -192,7 +192,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white">Daily Reward</h3>
|
||||
<p className="text-[10px] text-gray-500">
|
||||
<p className="text-xs text-gray-500">
|
||||
{canClaim
|
||||
? `Claim your streak reward — +${todayReward} FLH`
|
||||
: "Reward claimed — come back tomorrow!"}
|
||||
@@ -201,7 +201,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-lg font-bold text-orange-400">{todayReward.toLocaleString()}</p>
|
||||
<p className="text-[9px] text-gray-600">FLH reward</p>
|
||||
<p className="text-[10px] text-gray-600">FLH reward</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,12 +210,12 @@ export default function HomePage() {
|
||||
<button
|
||||
onClick={handleClaimReward}
|
||||
disabled={claiming}
|
||||
className="w-full py-2.5 bg-gradient-to-r from-orange-600 to-amber-600 hover:from-orange-500 hover:to-amber-500 disabled:opacity-50 text-white text-sm font-semibold rounded-xl active:scale-[0.98] transition-all"
|
||||
className="w-full py-3.5 bg-gradient-to-r from-orange-600 to-amber-600 hover:from-orange-500 hover:to-amber-500 disabled:opacity-50 text-white text-sm font-semibold rounded-xl active:scale-[0.98] transition-all min-h-[44px]"
|
||||
>
|
||||
{claiming ? "Claiming..." : "🔥 Claim Streak Reward"}
|
||||
</button>
|
||||
) : (
|
||||
<div className="w-full py-2.5 bg-gray-800/50 text-gray-500 text-sm font-medium rounded-xl text-center">
|
||||
<div className="w-full py-3.5 bg-gray-800/50 text-gray-500 text-sm font-medium rounded-xl text-center min-h-[44px] flex items-center justify-center">
|
||||
✅ Claimed
|
||||
</div>
|
||||
)}
|
||||
@@ -228,7 +228,7 @@ export default function HomePage() {
|
||||
)}
|
||||
|
||||
{/* XP hint */}
|
||||
<p className="text-[10px] text-gray-700 text-center mt-2">
|
||||
<p className="text-xs text-gray-700 text-center mt-3">
|
||||
+{Math.min(10 + currentStreak * 2, 100)} XP also awarded on claim
|
||||
</p>
|
||||
</div>
|
||||
@@ -237,17 +237,17 @@ export default function HomePage() {
|
||||
{/* Quick Actions */}
|
||||
<div className="px-4 mb-5">
|
||||
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3">Quick Actions</h2>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<QuickAction href="/nur" icon={Bot} label="Nur AI" color="bg-amber-900/30 text-amber-300" />
|
||||
<QuickAction href="/souq" icon={ShoppingBag} label="Souq" color="bg-[#D4AF37]/15 text-[#D4AF37]" />
|
||||
<QuickAction href="/halal-monitor" icon={MapPin} label="Halal" color="bg-emerald-900/30 text-emerald-300" />
|
||||
<QuickAction href="/halal-monitor" icon={MapPin} label="Halal Monitor" color="bg-emerald-900/30 text-emerald-300" />
|
||||
<QuickAction href="/wallet" icon={Wallet} label="Wallet" color="bg-blue-900/30 text-blue-300" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Row */}
|
||||
<div className="mx-4 mb-5">
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="flex gap-3">
|
||||
<StatCard label="FLH Balance" value={user.flhBalance.toLocaleString()} icon={Zap} color="text-[#D4AF37]" />
|
||||
<StatCard label="AI Today" value={`${user.dailyMsgCount}/10`} icon={Bot} color="text-amber-400" />
|
||||
<StatCard label="Tier" value={isPro ? "Pro" : isPremium ? "Premium" : "Free"} icon={Crown}
|
||||
@@ -259,7 +259,7 @@ export default function HomePage() {
|
||||
<div className="px-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wider">Activity</h2>
|
||||
<Link href="/forum" className="text-[11px] text-[#D4AF37]">View all</Link>
|
||||
<Link href="/forum" className="text-xs text-[#D4AF37] min-h-[44px] inline-flex items-center">View all</Link>
|
||||
</div>
|
||||
<div className="bg-[#111118] border border-gray-800/60 rounded-2xl p-5 text-center">
|
||||
<MessageCircle size={24} className="mx-auto text-gray-700 mb-2" />
|
||||
@@ -270,7 +270,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Premium upsell at bottom for free users */}
|
||||
{!isPremium && (
|
||||
<div className="mx-4 mt-5 bg-gradient-to-r from-[#D4AF37]/10 to-purple-900/10 border border-[#D4AF37]/20 rounded-2xl p-4 relative overflow-hidden">
|
||||
<div className="mx-4 mt-5 bg-gradient-to-r from-[#D4AF37]/10 to-purple-900/10 border border-[#D4AF37]/20 rounded-2xl p-5 relative overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-[#D4AF37]/5 rounded-full -translate-y-1/2 translate-x-1/2 blur-2xl" />
|
||||
<div className="flex items-start gap-3 relative">
|
||||
<div className="w-10 h-10 rounded-2xl bg-[#D4AF37]/15 flex items-center justify-center shrink-0">
|
||||
@@ -283,7 +283,7 @@ export default function HomePage() {
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mt-1">Premium gives you unlimited AI, halal monitor, <strong className="text-gray-400">2x FLH earning</strong>, and marketplace access.</p>
|
||||
<Link href="/upgrade"
|
||||
className="inline-block mt-3 text-xs font-semibold text-[#D4AF37] border border-[#D4AF37]/40 rounded-full px-4 py-1.5 active:bg-[#D4AF37]/10 transition hover:shadow-[0_0_12px_rgba(212,175,55,0.3)]">
|
||||
className="inline-block mt-3 text-xs font-semibold text-[#D4AF37] border border-[#D4AF37]/40 rounded-full px-6 py-3 active:bg-[#D4AF37]/10 transition hover:shadow-[0_0_12px_rgba(212,175,55,0.3)] min-h-[44px] leading-tight">
|
||||
See Plans
|
||||
</Link>
|
||||
</div>
|
||||
@@ -300,17 +300,17 @@ function QuickAction({ href, icon: Icon, label, color }: { href: string; icon: a
|
||||
<div className={`w-14 h-14 rounded-2xl flex items-center justify-center ${color} bg-opacity-20`}>
|
||||
<Icon size={22} />
|
||||
</div>
|
||||
<span className="text-[10px] text-gray-500 font-medium">{label}</span>
|
||||
<span className="text-xs text-gray-500 font-medium">{label}</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
function StatCard({ label, value, icon: Icon, color }: { label: string; value: string; icon: any; color: string }) {
|
||||
return (
|
||||
<div className="bg-[#111118] border border-gray-800/60 rounded-2xl p-3 text-center">
|
||||
<Icon size={14} className={`mx-auto mb-1 ${color}`} />
|
||||
<div className="flex-1 bg-[#111118] border border-gray-800/60 rounded-2xl p-3 text-center">
|
||||
<Icon size={16} className={`mx-auto mb-1 ${color}`} />
|
||||
<p className="text-sm font-bold text-white">{value}</p>
|
||||
<p className="text-[9px] text-gray-600 mt-0.5">{label}</p>
|
||||
<p className="text-[10px] text-gray-600 mt-0.5">{label}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+13
-13
@@ -187,7 +187,7 @@ export default function ProfilePage() {
|
||||
}`}>
|
||||
{tier === "pro" ? "Pro Member" : "Premium Member"}
|
||||
</p>
|
||||
<p className="text-[10px] text-gray-500 mt-0.5">
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
{tier === "pro"
|
||||
? "Unlimited everything + 0% marketplace fees"
|
||||
: "Enhanced AI + marketplace access"}
|
||||
@@ -253,7 +253,7 @@ export default function ProfilePage() {
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition min-h-[48px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -267,7 +267,7 @@ export default function ProfilePage() {
|
||||
value={preferredName}
|
||||
onChange={(e) => setPreferredName(e.target.value)}
|
||||
placeholder="How Nur AI should address you"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition min-h-[48px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -279,7 +279,7 @@ export default function ProfilePage() {
|
||||
<select
|
||||
value={coachPersona}
|
||||
onChange={(e) => setCoachPersona(e.target.value)}
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition appearance-none"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition appearance-none min-h-[48px]"
|
||||
>
|
||||
<option value="">Default</option>
|
||||
{PERSONAS.map((p) => (
|
||||
@@ -298,7 +298,7 @@ export default function ProfilePage() {
|
||||
<select
|
||||
value={madhab}
|
||||
onChange={(e) => setMadhab(e.target.value)}
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition appearance-none"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition appearance-none min-h-[48px]"
|
||||
>
|
||||
<option value="">Not specified</option>
|
||||
{VALID_MADHABS.map((m) => (
|
||||
@@ -319,14 +319,14 @@ export default function ProfilePage() {
|
||||
onChange={(e) => setCoachingGoals(e.target.value)}
|
||||
placeholder="What would you like to work on?"
|
||||
rows={3}
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition resize-none"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition resize-none min-h-[48px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={saving}
|
||||
className="w-full flex items-center justify-center gap-2 py-3 rounded-xl bg-[#D4AF37] text-[#0a0a0f] font-semibold text-sm active:opacity-80 disabled:opacity-50 transition"
|
||||
className="w-full flex items-center justify-center gap-2 py-4 rounded-xl bg-[#D4AF37] text-[#0a0a0f] font-semibold text-sm active:opacity-80 disabled:opacity-50 transition min-h-[48px]"
|
||||
>
|
||||
{saving ? (
|
||||
<>
|
||||
@@ -384,7 +384,7 @@ export default function ProfilePage() {
|
||||
<div className="mt-4 pt-3 border-t border-gray-800/60">
|
||||
<Link
|
||||
href="/upgrade"
|
||||
className="flex items-center justify-between py-2 px-3 rounded-xl bg-[#D4AF37]/10 border border-[#D4AF37]/20 active:bg-[#D4AF37]/20 transition"
|
||||
className="flex items-center justify-between py-3 px-4 rounded-xl bg-[#D4AF37]/10 border border-[#D4AF37]/20 active:bg-[#D4AF37]/20 transition"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<ExternalLink size={14} className="text-[#D4AF37]" />
|
||||
@@ -395,16 +395,16 @@ export default function ProfilePage() {
|
||||
<ChevronRight size={14} className="text-[#D4AF37]" />
|
||||
</Link>
|
||||
{user.trialEndsAt && (
|
||||
<div className="mt-2 flex items-center gap-1.5 px-3 py-1.5">
|
||||
<span className="text-[10px] text-gray-600">
|
||||
<div className="mt-2 flex items-center gap-2 px-3 py-2.5">
|
||||
<span className="text-xs text-gray-600">
|
||||
Trial ends{" "}
|
||||
{new Date(user.trialEndsAt).toLocaleDateString("en-MY", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}
|
||||
</span>
|
||||
<span className="text-[10px] text-gray-700">·</span>
|
||||
<span className="text-[10px] text-amber-400 font-medium">
|
||||
<span className="text-xs text-gray-700">·</span>
|
||||
<span className="text-xs text-amber-400 font-medium">
|
||||
{Math.max(0, Math.ceil((new Date(user.trialEndsAt).getTime() - Date.now()) / (1000 * 60 * 60 * 24)))} days remaining
|
||||
</span>
|
||||
</div>
|
||||
@@ -416,7 +416,7 @@ export default function ProfilePage() {
|
||||
{/* Logout */}
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="w-full flex items-center justify-between py-3.5 px-5 rounded-xl bg-red-900/10 border border-red-800/30 text-red-400 active:bg-red-900/20 transition"
|
||||
className="w-full flex items-center justify-between py-3.5 px-5 rounded-xl bg-red-900/10 border border-red-800/30 text-red-400 active:bg-red-900/20 transition min-h-[48px]"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<LogOut size={16} />
|
||||
|
||||
@@ -152,7 +152,7 @@ export default function RegisterPage() {
|
||||
|
||||
{/* Bonus info */}
|
||||
<div className="mt-6 rounded-xl bg-[#111118] border border-gray-800/60 p-3 text-center">
|
||||
<p className="text-[10px] text-gray-600 uppercase tracking-wider mb-1">
|
||||
<p className="text-xs text-gray-600 uppercase tracking-wider mb-1">
|
||||
New Member Bonus
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
|
||||
+25
-25
@@ -235,7 +235,7 @@ export default function SouqPage() {
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-bold text-white">Souq</h1>
|
||||
<p className="text-[10px] text-gray-500">Islamic Marketplace</p>
|
||||
<p className="text-xs text-gray-500">Islamic Marketplace</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -246,7 +246,7 @@ export default function SouqPage() {
|
||||
setCreateError(null);
|
||||
setShowCreateModal(true);
|
||||
}}
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-3 py-2 active:bg-[#D4AF37]/25 transition"
|
||||
className="flex items-center gap-1.5 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-3 py-3 active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Plus size={14} className="text-[#D4AF37]" />
|
||||
<span className="text-xs font-medium text-[#D4AF37]">Sell</span>
|
||||
@@ -257,7 +257,7 @@ export default function SouqPage() {
|
||||
<span className="text-xs font-bold text-white">
|
||||
{user.flhBalance.toLocaleString()}
|
||||
</span>
|
||||
<span className="text-[9px] text-gray-600">FLH</span>
|
||||
<span className="text-xs text-gray-600">FLH</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -267,7 +267,7 @@ export default function SouqPage() {
|
||||
<div className="mx-4 mb-3 bg-gradient-to-r from-amber-900/15 to-gray-900/50 border border-amber-800/20 rounded-xl px-3 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertTriangle size={12} className="text-amber-400 shrink-0" />
|
||||
<p className="text-[10px] text-amber-300/80">
|
||||
<p className="text-xs text-amber-300/80">
|
||||
Platform fee: 1.5% for standard listings, <strong>0% for Pro sellers</strong>.
|
||||
All prices in FLH (Falah Coins).
|
||||
</p>
|
||||
@@ -283,7 +283,7 @@ export default function SouqPage() {
|
||||
placeholder="Search listings..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full bg-[#111118] border border-gray-800/60 rounded-xl pl-10 pr-4 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
className="w-full bg-[#111118] border border-gray-800/60 rounded-xl pl-10 pr-4 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -354,7 +354,7 @@ export default function SouqPage() {
|
||||
setCreateError(null);
|
||||
setShowCreateModal(true);
|
||||
}}
|
||||
className="mt-4 flex items-center gap-2 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-2.5 active:bg-[#D4AF37]/25 transition"
|
||||
className="mt-4 flex items-center gap-2 bg-[#D4AF37]/15 border border-[#D4AF37]/30 rounded-xl px-4 py-3 active:bg-[#D4AF37]/25 transition"
|
||||
>
|
||||
<Plus size={16} className="text-[#D4AF37]" />
|
||||
<span className="text-sm font-medium text-[#D4AF37]">Create Listing</span>
|
||||
@@ -410,7 +410,7 @@ export default function SouqPage() {
|
||||
placeholder="e.g. Tafsir Ibn Kathir PDF"
|
||||
required
|
||||
maxLength={100}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -427,7 +427,7 @@ export default function SouqPage() {
|
||||
required
|
||||
maxLength={2000}
|
||||
rows={3}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition resize-none"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -440,7 +440,7 @@ export default function SouqPage() {
|
||||
onChange={(e) =>
|
||||
setCreateForm((f) => ({ ...f, category: e.target.value }))
|
||||
}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-2.5 text-sm text-white focus:outline-none focus:border-[#D4AF37]/40 transition appearance-none"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl px-3.5 py-3 text-sm text-white focus:outline-none focus:border-[#D4AF37]/40 transition appearance-none"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
@@ -469,7 +469,7 @@ export default function SouqPage() {
|
||||
placeholder="100"
|
||||
required
|
||||
min={1}
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl pl-3.5 pr-10 py-2.5 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
className="w-full bg-[#0a0a0f] border border-gray-800/60 rounded-xl pl-3.5 pr-10 py-3 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/40 transition"
|
||||
/>
|
||||
<span className="absolute right-3.5 top-1/2 -translate-y-1/2 text-xs font-medium text-[#D4AF37]">
|
||||
FLH
|
||||
@@ -487,14 +487,14 @@ export default function SouqPage() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(false)}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={creating}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
>
|
||||
{creating ? (
|
||||
<>
|
||||
@@ -548,7 +548,7 @@ export default function SouqPage() {
|
||||
setShowConfirmDialog(null);
|
||||
setPurchaseResult(null);
|
||||
}}
|
||||
className="w-full py-2.5 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition"
|
||||
className="w-full py-3 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
@@ -572,12 +572,12 @@ export default function SouqPage() {
|
||||
<span className="text-xs text-gray-600">FLH</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 mt-2">
|
||||
<span className="text-[10px] text-gray-500">From:</span>
|
||||
<span className="text-[10px] font-medium text-gray-300">
|
||||
<span className="text-xs text-gray-500">From:</span>
|
||||
<span className="text-xs font-medium text-gray-300">
|
||||
{showConfirmDialog.listing.seller.name}
|
||||
</span>
|
||||
{showConfirmDialog.listing.seller.isPro && (
|
||||
<span className="flex items-center gap-0.5 text-[9px] text-purple-400">
|
||||
<span className="flex items-center gap-0.5 text-[10px] text-purple-400">
|
||||
<Crown size={9} /> Pro
|
||||
</span>
|
||||
)}
|
||||
@@ -621,7 +621,7 @@ export default function SouqPage() {
|
||||
setPurchaseResult(null);
|
||||
}}
|
||||
disabled={!!purchasingId}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition disabled:opacity-40"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-medium text-gray-500 bg-gray-800/40 border border-gray-800/60 active:bg-gray-700/40 transition disabled:opacity-40"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
@@ -631,7 +631,7 @@ export default function SouqPage() {
|
||||
purchasingId === showConfirmDialog.listing.id ||
|
||||
user.flhBalance < showConfirmDialog.listing.priceFlh
|
||||
}
|
||||
className="flex-1 py-2.5 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
className="flex-1 py-3 rounded-xl text-sm font-semibold text-[#0a0a0f] bg-[#D4AF37] active:bg-[#c5a233] transition flex items-center justify-center gap-2 disabled:opacity-60"
|
||||
>
|
||||
{purchasingId === showConfirmDialog.listing.id ? (
|
||||
<>
|
||||
@@ -678,7 +678,7 @@ function ListingCard({
|
||||
{listing.featured && (
|
||||
<div className="absolute top-2 right-2 flex items-center gap-1 bg-[#D4AF37]/20 border border-[#D4AF37]/30 rounded-full px-2 py-0.5">
|
||||
<Star size={10} className="text-[#D4AF37]" />
|
||||
<span className="text-[8px] font-bold text-[#D4AF37]">Featured</span>
|
||||
<span className="text-[10px] font-bold text-[#D4AF37]">Featured</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -688,14 +688,14 @@ function ListingCard({
|
||||
<h3 className="text-sm font-semibold text-white truncate mb-1">
|
||||
{listing.title}
|
||||
</h3>
|
||||
<p className="text-[10px] text-gray-600 line-clamp-2 mb-2 leading-relaxed">
|
||||
<p className="text-xs text-gray-600 line-clamp-2 mb-2 leading-relaxed">
|
||||
{listing.description}
|
||||
</p>
|
||||
|
||||
{/* Seller info */}
|
||||
<div className="flex items-center gap-1 mb-2">
|
||||
<span className="text-[9px] text-gray-600">by</span>
|
||||
<span className="text-[9px] font-medium text-gray-400 truncate max-w-[80px]">
|
||||
<span className="text-xs text-gray-600">by</span>
|
||||
<span className="text-xs font-medium text-gray-400 truncate max-w-[80px]">
|
||||
{listing.seller.name}
|
||||
</span>
|
||||
{listing.seller.isPro && (
|
||||
@@ -705,7 +705,7 @@ function ListingCard({
|
||||
<PremiumBadge tier="premium" size="sm" />
|
||||
)}
|
||||
{listing.seller.isPro && (
|
||||
<span className="flex items-center gap-0.5 text-[8px] text-emerald-400 font-semibold ml-0.5">
|
||||
<span className="flex items-center gap-0.5 text-[10px] text-emerald-400 font-semibold ml-0.5">
|
||||
<Percent size={7} />
|
||||
0% fee
|
||||
</span>
|
||||
@@ -719,12 +719,12 @@ function ListingCard({
|
||||
<span className="text-sm font-bold text-[#D4AF37]">
|
||||
{listing.priceFlh.toLocaleString()}
|
||||
</span>
|
||||
<span className="text-[8px] text-gray-600">FLH</span>
|
||||
<span className="text-xs text-gray-600">FLH</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={onBuy}
|
||||
disabled={!canAfford}
|
||||
className={`text-[10px] font-semibold px-3 py-1.5 rounded-lg transition ${
|
||||
className={`text-xs font-semibold px-3 py-3 rounded-lg transition ${
|
||||
canAfford
|
||||
? "bg-[#D4AF37] text-[#0a0a0f] active:bg-[#c5a233]"
|
||||
: "bg-gray-800/60 text-gray-600 cursor-not-allowed"
|
||||
|
||||
@@ -260,7 +260,7 @@ function UpgradeContent() {
|
||||
<div className="text-right">
|
||||
<p className="text-xl font-bold text-white">{tier.price}</p>
|
||||
{tier.period && (
|
||||
<p className="text-[11px] text-gray-500">{tier.period}</p>
|
||||
<p className="text-xs text-gray-500">{tier.period}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -215,7 +215,7 @@ export default function WalletPage() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/upgrade")}
|
||||
className="mt-2 text-[11px] text-[#D4AF37] underline underline-offset-2"
|
||||
className="mt-2 text-xs text-[#D4AF37] underline underline-offset-2 py-1.5 px-2 -mx-2 rounded-lg"
|
||||
>
|
||||
Upgrade now
|
||||
</button>
|
||||
@@ -247,13 +247,13 @@ export default function WalletPage() {
|
||||
<Zap size={16} className="text-[#D4AF37]" />
|
||||
Top Up FLH
|
||||
</h2>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
{TOP_UP_OPTIONS.map((opt) => (
|
||||
<button
|
||||
key={opt.flh}
|
||||
onClick={() => handleTopUp(opt.flh)}
|
||||
disabled={topupLoading === opt.flh}
|
||||
className="bg-[#111118] border border-gray-800/60 rounded-2xl p-4 text-center active:scale-95 transition hover:border-[#D4AF37]/30 disabled:opacity-60"
|
||||
className="bg-[#111118] border border-gray-800/60 rounded-2xl p-5 text-center active:scale-95 transition hover:border-[#D4AF37]/30 disabled:opacity-60 min-h-[100px]"
|
||||
>
|
||||
{topupLoading === opt.flh ? (
|
||||
<Loader2 size={20} className="animate-spin mx-auto text-[#D4AF37]" />
|
||||
@@ -266,7 +266,7 @@ export default function WalletPage() {
|
||||
${opt.usd.toFixed(2)}
|
||||
</p>
|
||||
{opt.bonus && (
|
||||
<p className="text-[10px] text-emerald-400 mt-1 font-medium">
|
||||
<p className="text-xs text-emerald-400 mt-1 font-medium">
|
||||
{opt.bonus}
|
||||
</p>
|
||||
)}
|
||||
@@ -295,13 +295,13 @@ export default function WalletPage() {
|
||||
value={cashoutAmount}
|
||||
onChange={(e) => setCashoutAmount(e.target.value)}
|
||||
placeholder="Amount FLH"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-3 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition"
|
||||
className="w-full bg-[#1a1a24] border border-gray-800/60 rounded-xl px-4 py-4 text-white placeholder-gray-600 focus:outline-none focus:border-[#D4AF37]/50 focus:ring-1 focus:ring-[#D4AF37]/30 transition min-h-[48px]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={cashoutLoading}
|
||||
className="px-5 py-3 rounded-xl bg-[#D4AF37] text-[#0a0a0f] font-semibold text-sm disabled:opacity-50 active:opacity-80 transition flex items-center gap-2"
|
||||
className="px-5 py-4 rounded-xl bg-[#D4AF37] text-[#0a0a0f] font-semibold text-sm disabled:opacity-50 active:opacity-80 transition flex items-center gap-2 min-h-[48px]"
|
||||
>
|
||||
{cashoutLoading ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
@@ -364,7 +364,7 @@ export default function WalletPage() {
|
||||
<p className="text-sm font-medium text-white">
|
||||
{entry.amountFlh.toLocaleString()} FLH
|
||||
</p>
|
||||
<p className="text-[11px] text-gray-500">
|
||||
<p className="text-xs text-gray-500">
|
||||
${entry.fiatAmount.toFixed(2)} —{" "}
|
||||
{new Date(entry.createdAt).toLocaleDateString()}
|
||||
</p>
|
||||
@@ -395,8 +395,8 @@ export default function WalletPage() {
|
||||
</h3>
|
||||
<ul className="space-y-2">
|
||||
{EARNING_TIPS.map((tip, i) => (
|
||||
<li key={i} className="flex items-start gap-2 text-sm text-gray-400">
|
||||
<Info size={12} className="text-[#D4AF37] mt-0.5 shrink-0" />
|
||||
<li key={i} className="flex items-start gap-3 text-sm text-gray-400">
|
||||
<Info size={16} className="text-[#D4AF37] mt-0.5 shrink-0" />
|
||||
<span>{tip}</span>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@@ -24,11 +24,13 @@ export default function BottomNav() {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-[#0a0a0f]/95 backdrop-blur-md border-t border-gray-800/60"
|
||||
style={{ paddingBottom: "env(safe-area-inset-bottom, 0px)", height: "calc(64px + env(safe-area-inset-bottom, 0px))" }}>
|
||||
<div className="flex items-stretch h-16 max-w-lg mx-auto">
|
||||
<nav
|
||||
className="fixed bottom-0 left-0 right-0 z-50 bg-[#0a0a0f]/95 backdrop-blur-md border-t border-gray-800/60 safe-area-bottom"
|
||||
style={{ paddingBottom: "env(safe-area-inset-bottom, 0px)" }}
|
||||
>
|
||||
<div className="flex items-stretch h-14 max-w-lg mx-auto">
|
||||
{navItems.map((item) => {
|
||||
const isActive = pathname === item.href || pathname.startsWith(item.href + "/");
|
||||
const isActive = pathname === item.href || (item.href !== "/" && pathname.startsWith(item.href + "/"));
|
||||
const Icon = item.icon;
|
||||
const isHome = item.isHome;
|
||||
|
||||
@@ -39,13 +41,15 @@ export default function BottomNav() {
|
||||
href="/"
|
||||
className="flex-1 flex items-center justify-center"
|
||||
>
|
||||
<div className={`w-10 h-10 rounded-full flex items-center justify-center transition-all ${
|
||||
pathname === "/"
|
||||
? "bg-[#D4AF37] text-[#0a0a0f]"
|
||||
: "bg-gray-800/60 text-gray-500"
|
||||
}`}>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<div
|
||||
className={`w-11 h-11 rounded-full flex items-center justify-center transition-all ${
|
||||
pathname === "/"
|
||||
? "bg-[#D4AF37] text-[#0a0a0f] shadow-[0_0_12px_rgba(212,175,55,0.3)]"
|
||||
: "bg-gray-800/60 text-gray-500"
|
||||
}`}
|
||||
>
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -56,19 +60,25 @@ export default function BottomNav() {
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className="flex-1 flex flex-col items-center justify-center gap-0.5 transition-opacity active:opacity-60"
|
||||
className="flex-1 flex flex-col items-center justify-center gap-0.5 active:opacity-60 transition-opacity relative"
|
||||
>
|
||||
{Icon && (
|
||||
<Icon
|
||||
size={20}
|
||||
size={22}
|
||||
className={isActive ? "text-[#D4AF37]" : "text-gray-600"}
|
||||
/>
|
||||
)}
|
||||
<span className={`text-[10px] font-medium ${
|
||||
isActive ? "text-[#D4AF37]" : "text-gray-600"
|
||||
}`}>
|
||||
<span
|
||||
className={`text-xs font-medium ${
|
||||
isActive ? "text-[#D4AF37]" : "text-gray-600"
|
||||
}`}
|
||||
>
|
||||
{item.label}
|
||||
</span>
|
||||
{/* Active indicator */}
|
||||
{isActive && (
|
||||
<div className="absolute -top-0.5 left-1/2 -translate-x-1/2 w-5 h-0.5 rounded-full bg-[#D4AF37]" />
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -205,7 +205,7 @@ export default function NotificationPanel({
|
||||
>
|
||||
{notif.title}
|
||||
</p>
|
||||
<span className="text-[10px] text-gray-500 whitespace-nowrap mt-0.5">
|
||||
<span className="text-xs text-gray-500 whitespace-nowrap mt-0.5">
|
||||
{timeAgo(notif.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -9,8 +9,8 @@ interface PremiumBadgeProps {
|
||||
|
||||
export default function PremiumBadge({ tier, size = "sm" }: PremiumBadgeProps) {
|
||||
const sizeMap = {
|
||||
sm: { px: "px-1.5 py-0.5", text: "text-[9px]", icon: 8, gap: "gap-0.5" },
|
||||
md: { px: "px-2 py-0.5", text: "text-[10px]", icon: 10, gap: "gap-1" },
|
||||
sm: { px: "px-1.5 py-0.5", text: "text-[10px]", icon: 8, gap: "gap-0.5" },
|
||||
md: { px: "px-2 py-0.5", text: "text-xs", icon: 10, gap: "gap-1" },
|
||||
lg: { px: "px-2.5 py-1", text: "text-xs", icon: 12, gap: "gap-1" },
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user