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",