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