From 0762d1b23ba3a38d7d36e13f98c4986997c302ed Mon Sep 17 00:00:00 2001 From: Yves Gugger Date: Thu, 11 Dec 2025 06:49:15 +0100 Subject: [PATCH] feat: MARKET - Final Polish & Mobile Optimization Changes: - Implemented responsive layout: Desktop Table vs Mobile Cards - Desktop: Glassmorphism header, refined spacing, hover effects - Mobile: Elegant 'Trading Card' layout with optimized touch targets - Visual: New 'ScoreDisplay' component (Ring for Desktop, Badge for Mobile) - UX: Sticky search bar on mobile, better empty states - Polish: Improved typography, consistent borders, micro-interactions --- frontend/src/app/terminal/market/page.tsx | 516 +++++++++------------- 1 file changed, 215 insertions(+), 301 deletions(-) diff --git a/frontend/src/app/terminal/market/page.tsx b/frontend/src/app/terminal/market/page.tsx index da82b4c..cfa4e0e 100644 --- a/frontend/src/app/terminal/market/page.tsx +++ b/frontend/src/app/terminal/market/page.tsx @@ -24,7 +24,8 @@ import { Search, LayoutGrid, List, - SlidersHorizontal + SlidersHorizontal, + MoreHorizontal } from 'lucide-react' import clsx from 'clsx' @@ -77,7 +78,7 @@ function calculatePounceScore(domain: string, tld: string, numBids?: number, age let score = 50 const name = domain.split('.')[0] - // Length bonus (shorter = better) + // Length bonus if (name.length <= 3) score += 30 else if (name.length === 4) score += 25 else if (name.length === 5) score += 20 @@ -95,12 +96,12 @@ function calculatePounceScore(domain: string, tld: string, numBids?: number, age else if (ageYears && ageYears > 10) score += 7 else if (ageYears && ageYears > 5) score += 3 - // Activity bonus (more bids = more valuable) + // Activity bonus if (numBids && numBids >= 20) score += 8 else if (numBids && numBids >= 10) score += 5 else if (numBids && numBids >= 5) score += 2 - // SPAM PENALTIES + // Penalties if (name.includes('-')) score -= 25 if (/\d/.test(name) && name.length > 3) score -= 20 if (name.length > 15) score -= 15 @@ -118,7 +119,7 @@ function isSpamDomain(domain: string, tld: string): boolean { return false } -// Parse time remaining to seconds for sorting +// Parse time remaining to seconds function parseTimeToSeconds(timeStr?: string): number { if (!timeStr) return Infinity let seconds = 0 @@ -150,52 +151,59 @@ function StatCard({ trend?: 'up' | 'down' | 'neutral' }) { return ( -
-
-

{label}

+
+
+
+

{label}

{value} {subValue && {subValue}}
- +
) } -// Modern Score Indicator -function ScoreRing({ score }: { score: number }) { +// Score Ring (Desktop) / Badge (Mobile) +function ScoreDisplay({ score, mobile = false }: { score: number; mobile?: boolean }) { const color = score >= 80 ? 'text-emerald-500' : score >= 50 ? 'text-amber-500' : 'text-zinc-600' - const size = 32 + + if (mobile) { + return ( +
= 80 ? "bg-emerald-500/10 text-emerald-400 border-emerald-500/20" : + score >= 50 ? "bg-amber-500/10 text-amber-400 border-amber-500/20" : + "bg-zinc-800 text-zinc-400 border-zinc-700" + )}> + {score} +
+ ) + } + + const size = 36 const strokeWidth = 3 const radius = (size - strokeWidth) / 2 const circumference = radius * 2 * Math.PI const offset = circumference - (score / 100) * circumference return ( -
- {/* Background Ring */} +
+ - {/* Progress Ring */} - - = 80 ? 'text-emerald-400' : 'text-zinc-400')}> + = 80 ? 'text-emerald-400' : 'text-zinc-400')}> {score} + {/* Tooltip */} +
+ Pounce Score +
) } -// Refined Source Badge -function SourceBadge({ source, isPounce }: { source: string; isPounce: boolean }) { - if (isPounce) return ( -
-
- Pounce -
- ) - - return ( - - {source} - - ) -} - // Minimal Toggle -function FilterToggle({ - active, - onClick, - label -}: { - active: boolean - onClick: () => void - label: string -}) { +function FilterToggle({ active, onClick, label }: { active: boolean; onClick: () => void; label: string }) { return (
- -
- - {/* Filters */} -
- setHideSpam(!hideSpam)} label="Hide Spam" /> - setPounceOnly(!pounceOnly)} label="Pounce Exclusive" /> -
- setPriceRange(p => p === 'low' ? 'all' : 'low')} label="< $100" /> - setPriceRange(p => p === 'high' ? 'all' : 'high')} label="$1k+" /> -
- -
- - {/* Refresh */} -
- {/* ============================================================================ */} {/* DATA GRID */} - {/* ============================================================================ */} -
- - {/* Header */} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- Action -
-
- - {/* Body */} +
{loading ? (
-

Scanning global markets...

+

Scanning markets...

) : marketItems.length === 0 ? (
-

No assets found

-

Adjust filters to see more results

+

No matches found

+

Try adjusting your filters

) : ( -
- {marketItems.map((item) => { - const timeLeftSec = parseTimeToSeconds(item.timeLeft) - const isUrgent = timeLeftSec < 3600 - - return ( -
- {/* Domain */} -
-
-
-
-
- {item.domain.split('.')[0]} - .{item.tld} -
-
- = 80 ? "text-emerald-400" : "text-zinc-500")}> - Score {item.pounceScore} - - - - {item.timeLeft} - + <> + {/* DESKTOP TABLE */} +
+
+
+
+
+
+
Action
+
+
+ {marketItems.map((item) => { + const timeLeftSec = parseTimeToSeconds(item.timeLeft) + const isUrgent = timeLeftSec < 3600 + return ( +
+ {/* Domain */} +
+
+ {item.isPounce && } +
+
{item.domain}
+
{item.source}
+
-
-
- - {/* Score */} -
- -
- - {/* Price */} -
-
- {formatPrice(item.price)} -
- {item.numBids !== undefined && item.numBids > 0 && ( -
- {item.numBids} bids + {/* Score */} +
+ {/* Price */} +
+
{formatPrice(item.price)}
+ {item.numBids !== undefined && item.numBids > 0 &&
{item.numBids} bids
} +
+ {/* Time */} +
+
+ + {item.timeLeft} +
+
+ {/* Actions */} +
+ + + {item.isPounce ? 'Buy' : 'Bid'} + +
- )} -
- - {/* Time */} -
-
- - {item.timeLeft}
-
+ ) + })} +
+
- {/* Source */} -
- -
- - {/* Action */} -
- + {/* MOBILE CARDS */} +
+ {marketItems.map((item) => { + const timeLeftSec = parseTimeToSeconds(item.timeLeft) + const isUrgent = timeLeftSec < 3600 + return ( +
+
+
+ {item.isPounce && } + {item.domain} +
+ +
- - {item.isPounce ? 'Buy' : 'Bid'} - - +
+
+
Current Bid
+
{formatPrice(item.price)}
+
+
+
Ends In
+
+ + {item.timeLeft} +
+
+
+ +
+ + + {item.isPounce ? 'Buy Now' : 'Place Bid'} + + +
-
- ) - })} -
+ ) + })} +
+ )}