diff --git a/packages/ui/src/app/account/[address]/page.tsx b/packages/ui/src/app/account/[address]/page.tsx
index 1f1a8c2..1806aaf 100644
--- a/packages/ui/src/app/account/[address]/page.tsx
+++ b/packages/ui/src/app/account/[address]/page.tsx
@@ -85,10 +85,8 @@ function AccountPageInner() {
Back to search
- {/* {loading && } */}
- {loading && (
-
Loading...
- )}
+ {loading &&
@@ -124,60 +122,60 @@ export default function AccountPage() {
// ── Skeleton ───────────────────────────────────────────────────────────────
-// function AccountSkeleton() {
-// return (
-//
-// );
-// }
+function AccountSkeleton() {
+ return (
+
+ );
+}
diff --git a/packages/ui/src/app/page.tsx b/packages/ui/src/app/page.tsx
index cd7bcef..c5f82f0 100644
--- a/packages/ui/src/app/page.tsx
+++ b/packages/ui/src/app/page.tsx
@@ -1,6 +1,9 @@
'use client";';
import HeroSection from '@/components/landing/HeroSection';
+import HowItWorksSection from '@/components/landing/HowItWorksSection';
import Navbar from '@/components/landing/Navbar';
+import UseCasesSection from '@/components/landing/UseCasesSection';
+import WhatWeDecodeSection from '@/components/landing/WhatWeDecodeSection';
export default function LandingPage() {
return (
@@ -42,6 +45,9 @@ export default function LandingPage() {
+
+
+
);
}
diff --git a/packages/ui/src/app/tx/[hash]/page.tsx b/packages/ui/src/app/tx/[hash]/page.tsx
index 9c69e23..7f85a21 100644
--- a/packages/ui/src/app/tx/[hash]/page.tsx
+++ b/packages/ui/src/app/tx/[hash]/page.tsx
@@ -84,10 +84,8 @@ function TxPageInner() {
Back to search
- {/* {loading && Loading...
- )}
+ {loading &&
@@ -112,49 +110,49 @@ export default function TxPage() {
// ── Skeleton ───────────────────────────────────────────────────────────────
-// function TransactionSkeleton() {
-// return (
-//
-// );
-// }
+function TransactionSkeleton() {
+ return (
+
+ );
+}
diff --git a/packages/ui/src/components/landing/Footer.tsx b/packages/ui/src/components/landing/Footer.tsx
new file mode 100644
index 0000000..e5a07de
--- /dev/null
+++ b/packages/ui/src/components/landing/Footer.tsx
@@ -0,0 +1,52 @@
+import Link from "next/link";
+import React from "react";
+
+export default function Footer() {
+ return (
+
+ );
+}
diff --git a/packages/ui/src/components/landing/HowItWorksSection.tsx b/packages/ui/src/components/landing/HowItWorksSection.tsx
new file mode 100644
index 0000000..99ab72f
--- /dev/null
+++ b/packages/ui/src/components/landing/HowItWorksSection.tsx
@@ -0,0 +1,48 @@
+import { STEPS } from '@/lib/landing-data';
+import React from 'react';
+
+function HowItWorksSection() {
+ return (
+
+
+
+ How it works
+
+
+ Three steps to clarity
+
+
+
+
+ {STEPS.map((step) => (
+
+ {/* step number watermark */}
+
+ {step.n}
+
+
+
+ {step.icon}
+
+
+
+ {step.title}
+
+
{step.body}
+
+ ))}
+
+
+ );
+}
+
+export default HowItWorksSection;
diff --git a/packages/ui/src/components/landing/OpenSourceSection.tsx b/packages/ui/src/components/landing/OpenSourceSection.tsx
new file mode 100644
index 0000000..93d198e
--- /dev/null
+++ b/packages/ui/src/components/landing/OpenSourceSection.tsx
@@ -0,0 +1,69 @@
+import React from "react";
+
+export default function OpenSourceSection() {
+ return (
+
+
+ {/* inner glow */}
+
+
+
+
+
+
+ Built in the open.
+
+ Come build with us.
+
+
+
+ Stellar Explain is fully open source. Whether you want to add a new
+ operation explainer, improve the UI, or fix a bug — every
+ contribution makes Web3 more human readable.
+
+
+
+
+
+
+ );
+}
diff --git a/packages/ui/src/components/landing/UseCasesSection.tsx b/packages/ui/src/components/landing/UseCasesSection.tsx
new file mode 100644
index 0000000..0ce2a9d
--- /dev/null
+++ b/packages/ui/src/components/landing/UseCasesSection.tsx
@@ -0,0 +1,524 @@
+'use client';
+
+import { useEffect, useRef, useState } from 'react';
+
+const NODES = [
+ {
+ id: 'developers',
+ label: 'Developers',
+ sub: 'debug with clarity',
+ icon: '>',
+ x: 185,
+ y: 190,
+ floatDur: 2.8,
+ floatAmp: 9,
+ floatDelay: 0,
+ },
+ {
+ id: 'analysts',
+ label: 'Analysts',
+ sub: 'audit made readable',
+ icon: '~~~',
+ x: 830,
+ y: 172,
+ floatDur: 3.4,
+ floatAmp: 11,
+ floatDelay: 0.4,
+ },
+ {
+ id: 'curious',
+ label: 'Curious Users',
+ sub: 'your wallet, explained',
+ icon: '◉',
+ x: 158,
+ y: 440,
+ floatDur: 3.1,
+ floatAmp: 8,
+ floatDelay: 0.8,
+ },
+ {
+ id: 'businesses',
+ label: 'Businesses',
+ sub: 'compliance-ready context',
+ icon: '⬡',
+ x: 840,
+ y: 438,
+ floatDur: 2.6,
+ floatAmp: 10,
+ floatDelay: 0.2,
+ },
+ {
+ id: 'auditors',
+ label: 'Auditors',
+ sub: 'trace every operation',
+ icon: '◈',
+ x: 920,
+ y: 310,
+ floatDur: 3.7,
+ floatAmp: 7,
+ floatDelay: 1.0,
+ },
+];
+
+const CENTER = { x: 530, y: 315 };
+
+const CURVES: Record
= {
+ developers: `M${CENTER.x - 26},${CENTER.y - 26} C420,265 320,230 248,200`,
+ analysts: `M${CENTER.x + 24},${CENTER.y - 28} C630,248 720,205 768,182`,
+ curious: `M${CENTER.x - 28},${CENTER.y + 24} C420,378 310,408 222,440`,
+ businesses: `M${CENTER.x + 26},${CENTER.y + 24} C635,378 728,412 778,438`,
+ auditors: `M${CENTER.x + 30},${CENTER.y} C668,308 768,310 858,312`,
+};
+
+const SEQUENCE_DELAYS: Record = {
+ developers: { line: 1100, node: 1500 },
+ analysts: { line: 1750, node: 2100 },
+ curious: { line: 2300, node: 2650 },
+ businesses: { line: 2900, node: 3250 },
+ auditors: { line: 3500, node: 3850 },
+};
+
+export default function UseCasesSection() {
+ const sectionRef = useRef(null);
+ const [visible, setVisible] = useState(false);
+ const [centerVisible, setCenterVisible] = useState(false);
+ const [linesVisible, setLinesVisible] = useState>({});
+ const [nodesVisible, setNodesVisible] = useState>({});
+ const [started, setStarted] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting && !started) {
+ setVisible(true);
+ setStarted(true);
+ }
+ },
+ { threshold: 0.25 },
+ );
+ if (sectionRef.current) observer.observe(sectionRef.current);
+ return () => observer.disconnect();
+ }, [started]);
+
+ useEffect(() => {
+ if (!visible) return;
+
+ const t0 = setTimeout(() => setCenterVisible(true), 600);
+
+ const lineTimers: ReturnType[] = [];
+ const nodeTimers: ReturnType[] = [];
+
+ NODES.forEach((node) => {
+ const d = SEQUENCE_DELAYS[node.id];
+ lineTimers.push(
+ setTimeout(() => {
+ setLinesVisible((prev) => ({ ...prev, [node.id]: true }));
+ }, d.line),
+ );
+ nodeTimers.push(
+ setTimeout(() => {
+ setNodesVisible((prev) => ({ ...prev, [node.id]: true }));
+ }, d.node),
+ );
+ });
+
+ return () => {
+ clearTimeout(t0);
+ [...lineTimers, ...nodeTimers].forEach(clearTimeout);
+ };
+ }, [visible]);
+
+ return (
+
+ {/* Section heading */}
+
+
+ who is this for??
+
+
+ Everyone navigating Stellar.
+
+
+
+ {/* SVG node graph */}
+
+
+
+ {/* Line pulse filter */}
+
+
+
+
+
+
+
+
+ {/* CSS animations injected inline */}
+
+
+
+ {/* Ambient dots */}
+ {[
+ [360, 140],
+ [680, 560],
+ [90, 320],
+ [980, 200],
+ [460, 560],
+ [740, 118],
+ [55, 210],
+ [1010, 500],
+ [200, 560],
+ [900, 80],
+ ].map(([cx, cy], i) => (
+
+ ))}
+
+ {/* Connector lines */}
+ {NODES.map((node) => (
+
+ ))}
+
+ {/* CENTER NODE */}
+
+
+ {/* Star icon */}
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ Stellar Explain
+ */}
+
+ plain-english blockchain
+
+
+
+ {/* AUDIENCE NODES */}
+ {NODES.map((node, i) => {
+ const w = node.id === 'businesses' ? 196 : node.id === 'curious' ? 192 : 180;
+ const h = 84;
+ const nx = node.x - w / 2;
+ const ny = node.y - h / 2;
+
+ return (
+
+
+ {/* Icon box */}
+
+
+ {node.icon}
+
+ {/* Label */}
+
+ {node.label}
+
+
+ {node.sub}
+
+ {/* Decorative corner dot */}
+
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/packages/ui/src/components/landing/WhatWeDecodeSection.tsx b/packages/ui/src/components/landing/WhatWeDecodeSection.tsx
new file mode 100644
index 0000000..53bddaf
--- /dev/null
+++ b/packages/ui/src/components/landing/WhatWeDecodeSection.tsx
@@ -0,0 +1,38 @@
+import { FEATURES } from '@/lib/landing-data';
+import React from 'react';
+
+function WhatWeDecodeSection() {
+ return (
+
+
+
Coverage
+
+ What we decode
+
+
+ Every major Stellar operation type, explained in context.
+
+
+
+
+ {FEATURES.map((f) => (
+
+ ))}
+
+
+ );
+}
+
+export default WhatWeDecodeSection;
diff --git a/packages/ui/src/lib/landing-data.tsx b/packages/ui/src/lib/landing-data.tsx
new file mode 100644
index 0000000..1000a47
--- /dev/null
+++ b/packages/ui/src/lib/landing-data.tsx
@@ -0,0 +1,80 @@
+export const FEATURES = [
+ {
+ label: "Payments",
+ desc: "XLM and custom asset transfers between accounts",
+ },
+ {
+ label: "Accounts",
+ desc: "Balances, trust lines, signers, flags, and home domain",
+ },
+ {
+ label: "Set Options",
+ desc: "Account configuration changes decoded line by line",
+ },
+ {
+ label: "Create Account",
+ desc: "New account funding and activation events",
+ },
+ { label: "Change Trust", desc: "Asset trust line additions and removals" },
+ { label: "Clawback", desc: "Regulated asset recovery operations explained" },
+];
+
+export const STEPS = [
+ {
+ n: "01",
+ title: "Paste a hash or address",
+ body: "Copy any transaction hash or account address from your wallet, exchange, or block explorer.",
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ n: "02",
+ title: "Hit Explain",
+ body: "Stellar Explain fetches the data from the Stellar network and processes each operation in real time.",
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ n: "03",
+ title: "Read plain English",
+ body: "Every operation is translated into a clear, human-readable explanation — no blockchain knowledge needed.",
+ icon: (
+
+
+
+
+
+
+
+ ),
+ },
+];
\ No newline at end of file