diff --git a/src/app/page.tsx b/src/app/page.tsx index 3c35f81..59d03dd 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -6,6 +6,8 @@ import { Text, Spinner, Box, + Grid, + GridItem, Skeleton, useToast, Alert, @@ -31,58 +33,260 @@ const fadeInUp = { }), }; +// ── Ambient background ─────────────────────────────────────────────────────── +// A layer of slow-drifting, multi-hue gradient blobs plus a faint dot grid, +// scoped to this page's own stacking context so it never touches the shared +// AppShell chrome (nav/footer) that other routes' visual-regression +// screenshots depend on. + +function GradientOrb({ + color, + size, + top, + left, + right, + bottom, + driftX = 24, + driftY = 18, + duration = 18, + delay = 0, +}: { + color: string; + size: string; + top?: string; + left?: string; + right?: string; + bottom?: string; + driftX?: number; + driftY?: number; + duration?: number; + delay?: number; +}) { + return ( + + ); +} + +function AmbientBackground() { + return ( + + + + + + + ); +} + +// ── Icons ──────────────────────────────────────────────────────────────────── +// Small inline line icons — no new icon-package dependency for four glyphs. + +function IconVault(props: { color: string }) { + return ( + + + + + + + ); +} + +function IconLayers(props: { color: string }) { + return ( + + + + + + ); +} + +function IconUsers(props: { color: string }) { + return ( + + + + + + + ); +} + +function IconPulse(props: { color: string }) { + return ( + + + + ); +} + function StatCard({ label, value, accent = "app.accent", + glow = "glow", + icon, delay = 0, isLoading = false, + span, + featured = false, }: { label: string; value: string | number; accent?: string; + glow?: string; + icon: (props: { color: string }) => React.ReactElement; delay?: number; isLoading?: boolean; + span?: { base: number; lg: number }; + featured?: boolean; }) { + const Icon = icon; return ( - - - - {label} - - - - {isLoading ? "—" : value} - - - + + + + {featured && ( + + )} + + + {label} + + + + + + + + {isLoading ? "—" : value} + + + + ); } @@ -137,117 +341,173 @@ export default function Home() { value || value === 0 ? value.toLocaleString() : fallback; return ( - - - + + + + + + + Live on {stellarNetwork} + + + + SmartDrop Dashboard + + + Live Soroban RPC data with contract-driven TVL, pool counts, and user + metrics. + + + RPC: {sorobanRpcUrl.replace(/^https?:\/\//, "")} + {publicKey ? ` · Wallet ${publicKey.slice(0, 6)}…` : ""} + + + + + + + + + + + - - Live on {stellarNetwork} + + Your credits + + + Credits are calculated from your on-chain positions across all pools. - - - SmartDrop Dashboard - - - Live Soroban RPC data with contract-driven TVL, pool counts, and user - metrics. - - - RPC: {sorobanRpcUrl.replace(/^https?:\/\//, "")} - {publicKey ? ` · Wallet ${publicKey.slice(0, 6)}…` : ""} - - - - - - - - - - - - Your credits - - - Credits are calculated from your on-chain positions across all pools. - - - {isConnected ? ( - creditsLoading ? ( - + {isConnected ? ( + creditsLoading ? ( + + ) : ( + + {totalCredits ?? "0"} Credits + + ) ) : ( - - {totalCredits ?? "0"} Credits - - ) - ) : ( - - Connect your Freighter wallet to fetch your user credits and positions. - - )} - - - + + Connect your Freighter wallet to fetch your user credits and positions. + + )} + + + + ); } diff --git a/src/lib/theme.ts b/src/lib/theme.ts index 2a7e6ae..1dcce3f 100644 --- a/src/lib/theme.ts +++ b/src/lib/theme.ts @@ -24,6 +24,12 @@ const theme = extendTheme({ // Accent — #0f7a4e passes 4.5:1 on white; #4ae292 is the dark-mode green "app.accent": { default: "#0f7a4e", _dark: "#4ae292" }, "app.accent2": { default: "#2563eb", _dark: "#6dd5ff" }, + // Extended palette for richer, multi-hue surfaces (landing page bento + // grid, ambient background). #7c3aed passes 5.7:1 on white, #c4b5fd + // passes 10.5:1 on the dark bg. + "app.accent3": { default: "#7c3aed", _dark: "#c4b5fd" }, + // #be185d passes 6:1 on white, #f9a8d4 passes 10.7:1 on the dark bg. + "app.accent4": { default: "#be185d", _dark: "#f9a8d4" }, // Text "app.text": { default: "#171717", _dark: "#ffffff" }, "app.muted": { default: "#6b7280", _dark: "#9a9a9a" }, @@ -54,6 +60,10 @@ const theme = extendTheme({ card: "0 1px 2px rgba(0,0,0,0.04), 0 8px 24px -8px rgba(0,0,0,0.35)", cardHover: "0 1px 2px rgba(0,0,0,0.06), 0 16px 40px -12px rgba(74,226,146,0.25)", glow: "0 0 0 1px rgba(74,226,146,0.4), 0 0 32px rgba(74,226,146,0.25)", + // Multi-hue glows for the bento-grid stat cards on the landing page. + glowBlue: "0 0 0 1px rgba(109,213,255,0.4), 0 0 32px rgba(109,213,255,0.25)", + glowViolet: "0 0 0 1px rgba(196,181,253,0.4), 0 0 32px rgba(196,181,253,0.25)", + glowPink: "0 0 0 1px rgba(249,168,212,0.4), 0 0 32px rgba(249,168,212,0.25)", }, radii: { card: "1.25rem",