UI: feature skater photo in Lab cross-link + polish mobile bottom nav (1.3.8)
- Lab "Just a skater?" card now features the uploaded photo, framed and faded into the card body with a neon-red edge consistent with the app's look; adds a "The Crew" eyebrow label and a circular arrow affordance. - Mobile bottom nav redesigned: glowing rounded pill behind the active tab (replaces the tiny dot), gradient glass bar with a top hairline glow, ring-2 wallet badge, and refined active/press micro-animations. Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
1d769ed564
commit
8145379190
3 changed files with 90 additions and 52 deletions
BIN
public/images/just-a-skater.png
Normal file
BIN
public/images/just-a-skater.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
|
|
@ -329,7 +329,9 @@ function MobileNav({
|
||||||
const active = isActive(tab.href);
|
const active = isActive(tab.href);
|
||||||
const isWallet = tab.id === 'wallet';
|
const isWallet = tab.id === 'wallet';
|
||||||
const accent = isWallet ? 'text-orange-400' : 'text-[#ff0040]';
|
const accent = isWallet ? 'text-orange-400' : 'text-[#ff0040]';
|
||||||
const dot = isWallet ? 'bg-orange-400' : 'bg-[#ff0040]';
|
const glow = isWallet
|
||||||
|
? 'bg-orange-500/15 shadow-[0_0_16px_rgba(249,115,22,0.35)]'
|
||||||
|
: 'bg-[#ff0040]/15 shadow-[0_0_16px_rgba(255,0,64,0.35)]';
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={key}
|
key={key}
|
||||||
|
|
@ -342,26 +344,34 @@ function MobileNav({
|
||||||
onCustomize();
|
onCustomize();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex flex-col items-center justify-center gap-0.5 py-1.5 px-1 rounded-xl transition-all duration-150 flex-1 touch-manipulation active:scale-90',
|
'group relative flex flex-col items-center justify-center gap-1 py-1.5 px-1 flex-1 touch-manipulation active:scale-90 transition-transform duration-150',
|
||||||
active ? accent : 'text-gray-500',
|
active ? accent : 'text-gray-500',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{active && (
|
{/* Glowing pill behind the active icon */}
|
||||||
<span className={cn('absolute top-0 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full', dot)} />
|
<span
|
||||||
)}
|
className={cn(
|
||||||
{isWallet ? (
|
'relative flex items-center justify-center h-9 w-12 rounded-2xl transition-all duration-300',
|
||||||
<div className="relative">
|
active ? glow : 'bg-transparent',
|
||||||
<Wallet className={cn('h-[22px] w-[22px] transition-transform', active && 'scale-110')} />
|
)}
|
||||||
{cashuBalance > 0 && (
|
>
|
||||||
<span className="absolute -top-1.5 -right-2.5 min-w-[16px] h-4 px-1 text-[8px] font-bold bg-orange-500 text-white rounded-full flex items-center justify-center leading-none">
|
{isWallet ? (
|
||||||
{formatSatsCompact(cashuBalance)}
|
<>
|
||||||
</span>
|
<Wallet className={cn('h-[22px] w-[22px] transition-transform duration-300', active ? 'scale-110' : 'group-active:scale-95')} />
|
||||||
)}
|
{cashuBalance > 0 && (
|
||||||
</div>
|
<span className="absolute -top-1 -right-1.5 min-w-[16px] h-4 px-1 text-[8px] font-bold bg-orange-500 text-white rounded-full flex items-center justify-center leading-none ring-2 ring-black">
|
||||||
) : (
|
{formatSatsCompact(cashuBalance)}
|
||||||
<tab.icon className={cn('h-[22px] w-[22px] transition-transform', active && 'scale-110')} />
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-[9px] xs:text-[10px] font-semibold leading-tight tracking-wide uppercase">
|
</>
|
||||||
|
) : (
|
||||||
|
<tab.icon className={cn('h-[22px] w-[22px] transition-transform duration-300', active ? 'scale-110' : 'group-active:scale-95')} />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className={cn(
|
||||||
|
'text-[9px] xs:text-[10px] leading-tight tracking-wide uppercase transition-all',
|
||||||
|
active ? 'font-extrabold' : 'font-semibold',
|
||||||
|
)}>
|
||||||
{tab.labelKey ? t(tab.labelKey) : tab.label}
|
{tab.labelKey ? t(tab.labelKey) : tab.label}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -370,12 +380,14 @@ function MobileNav({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="fixed bottom-0 left-0 right-0 z-50 md:hidden">
|
<nav className="fixed bottom-0 left-0 right-0 z-50 md:hidden">
|
||||||
|
{/* Top hairline glow — gives the bar a lifted, premium edge */}
|
||||||
|
<div className="h-px w-full bg-gradient-to-r from-transparent via-[#ff0040]/50 to-transparent" />
|
||||||
{/* Nav bar */}
|
{/* Nav bar */}
|
||||||
<div
|
<div
|
||||||
className="glass border-t border-white/10"
|
className="glass border-t border-white/10 bg-gradient-to-b from-black/70 to-black/95 backdrop-blur-xl"
|
||||||
style={{ paddingBottom: 'env(safe-area-inset-bottom, 0px)', paddingLeft: 'env(safe-area-inset-left, 0px)', paddingRight: 'env(safe-area-inset-right, 0px)' }}
|
style={{ paddingBottom: 'env(safe-area-inset-bottom, 0px)', paddingLeft: 'env(safe-area-inset-left, 0px)', paddingRight: 'env(safe-area-inset-right, 0px)' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-stretch justify-around px-1 pt-1 pb-1">
|
<div className="flex items-stretch justify-around px-1.5 pt-1.5 pb-1">
|
||||||
{/* FIXED: Map / Shops & Spots */}
|
{/* FIXED: Map / Shops & Spots */}
|
||||||
{renderTab(fixedMapTab, 'fixed-map')}
|
{renderTab(fixedMapTab, 'fixed-map')}
|
||||||
|
|
||||||
|
|
@ -400,30 +412,37 @@ function MobileNav({
|
||||||
onCustomize();
|
onCustomize();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex flex-col items-center justify-center gap-0.5 py-1.5 px-1 rounded-xl transition-all duration-150 flex-1 touch-manipulation active:scale-90',
|
'group relative flex flex-col items-center justify-center gap-1 py-1.5 px-1 flex-1 touch-manipulation active:scale-90 transition-transform duration-150',
|
||||||
tabActive ? 'text-[#ff0040]' : 'text-gray-500'
|
tabActive ? 'text-[#ff0040]' : 'text-gray-500'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{tabActive && (
|
<span
|
||||||
<span className="absolute top-0 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-[#ff0040]" />
|
className={cn(
|
||||||
)}
|
'relative flex items-center justify-center h-9 w-12 rounded-2xl transition-all duration-300',
|
||||||
{isLoggedIn && userPubkey ? (
|
tabActive ? 'bg-[#ff0040]/15 shadow-[0_0_16px_rgba(255,0,64,0.35)]' : 'bg-transparent',
|
||||||
<div className="relative">
|
)}
|
||||||
<Avatar className={cn(
|
>
|
||||||
'h-[22px] w-[22px] border-2 transition-transform',
|
{isLoggedIn && userPubkey ? (
|
||||||
tabActive ? 'border-[#ff0040] scale-110' : 'border-gray-600'
|
<div className="relative">
|
||||||
)}>
|
<Avatar className={cn(
|
||||||
<AvatarImage src={userAvatar} alt={userName} />
|
'h-[24px] w-[24px] border-2 transition-transform duration-300',
|
||||||
<AvatarFallback className="bg-[#ff0040]/20 text-[#ff0040] text-[8px] font-bold">
|
tabActive ? 'border-[#ff0040] scale-110' : 'border-gray-600 group-active:scale-95'
|
||||||
{(userName || '??').slice(0, 2).toUpperCase()}
|
)}>
|
||||||
</AvatarFallback>
|
<AvatarImage src={userAvatar} alt={userName} />
|
||||||
</Avatar>
|
<AvatarFallback className="bg-[#ff0040]/20 text-[#ff0040] text-[8px] font-bold">
|
||||||
<span className="absolute -bottom-0.5 -right-0.5 w-2 h-2 bg-green-500 border border-black rounded-full" />
|
{(userName || '??').slice(0, 2).toUpperCase()}
|
||||||
</div>
|
</AvatarFallback>
|
||||||
) : (
|
</Avatar>
|
||||||
<User className="h-[22px] w-[22px]" />
|
<span className="absolute -bottom-0.5 -right-0.5 w-2 h-2 bg-green-500 border border-black rounded-full" />
|
||||||
)}
|
</div>
|
||||||
<span className="text-[9px] xs:text-[10px] font-semibold leading-tight tracking-wide uppercase">
|
) : (
|
||||||
|
<User className={cn('h-[22px] w-[22px] transition-transform duration-300', tabActive ? 'scale-110' : 'group-active:scale-95')} />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span className={cn(
|
||||||
|
'text-[9px] xs:text-[10px] leading-tight tracking-wide uppercase transition-all',
|
||||||
|
tabActive ? 'font-extrabold' : 'font-semibold',
|
||||||
|
)}>
|
||||||
{isLoggedIn ? 'Profile' : 'Log In'}
|
{isLoggedIn ? 'Profile' : 'Log In'}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -1297,20 +1297,39 @@ export default function LabPage() {
|
||||||
{/* ── Skater directory cross-link ── */}
|
{/* ── Skater directory cross-link ── */}
|
||||||
<Link
|
<Link
|
||||||
to="/skaters"
|
to="/skaters"
|
||||||
className="group flex items-center gap-3 rounded-2xl border border-white/10 bg-gradient-to-r from-[#ff0040]/10 via-black to-[#ccff00]/5 p-4 mb-5 hover:border-[#ff0040]/40 transition-all"
|
className="group relative flex items-stretch gap-0 rounded-2xl overflow-hidden border border-white/10 bg-gradient-to-r from-[#ff0040]/10 via-black to-[#ccff00]/5 mb-5 hover:border-[#ff0040]/50 transition-all duration-300 shadow-lg shadow-black/40 hover:shadow-[#ff0040]/10"
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0 w-11 h-11 rounded-xl bg-[#ff0040]/15 flex items-center justify-center group-hover:bg-[#ff0040]/25 transition-colors">
|
{/* Featured photo — framed with a neon edge, consistent with the app's look */}
|
||||||
<PersonStanding className="h-6 w-6 text-[#ff0040]" />
|
<div className="relative flex-shrink-0 w-[104px] sm:w-[128px] overflow-hidden">
|
||||||
|
<img
|
||||||
|
src="/images/just-a-skater.png"
|
||||||
|
alt="Skater"
|
||||||
|
loading="lazy"
|
||||||
|
className="absolute inset-0 h-full w-full object-cover object-center transition-transform duration-500 group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
{/* Fade the photo into the card body so it feels integrated, not pasted on */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-transparent to-black" />
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-[#ff0040]/20 to-transparent mix-blend-screen" />
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
|
||||||
<p className="font-black uppercase text-sm leading-tight">
|
{/* Copy */}
|
||||||
Just a <span className="text-[#ff0040]">skater</span>?
|
<div className="relative min-w-0 flex-1 flex items-center gap-3 py-4 pr-4 pl-4">
|
||||||
</p>
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-xs text-gray-400 mt-0.5">
|
<p className="inline-flex items-center gap-1.5 text-[10px] font-black uppercase tracking-widest text-[#ccff00] mb-1">
|
||||||
The Lab is for services. Browse & join the whole skater community
|
<PersonStanding className="h-3.5 w-3.5" />
|
||||||
</p>
|
The Crew
|
||||||
|
</p>
|
||||||
|
<p className="font-black uppercase text-base leading-tight">
|
||||||
|
Just a <span className="text-[#ff0040]" style={{ textShadow: '0 0 12px rgba(255,0,64,0.6)' }}>skater</span>?
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-400 mt-1 leading-snug">
|
||||||
|
The Lab's for services. Browse & join the whole skater community →
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex-shrink-0 w-9 h-9 rounded-full bg-[#ff0040]/15 flex items-center justify-center group-hover:bg-[#ff0040]/30 transition-colors">
|
||||||
|
<ArrowRight className="h-5 w-5 text-[#ff0040] group-hover:translate-x-0.5 transition-transform" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ArrowRight className="h-5 w-5 text-gray-500 group-hover:text-[#ff0040] group-hover:translate-x-0.5 transition-all flex-shrink-0" />
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* ── Sticky toolbar (tabs + search + location + filter button + active chips) ── */}
|
{/* ── Sticky toolbar (tabs + search + location + filter button + active chips) ── */}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue