Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 10 additions & 30 deletions apps/tangle-cloud/src/components/RequireWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,55 +32,35 @@ const RequireWallet: FC<Props> = ({
variant="sandbox"
className="w-full overflow-hidden border-border bg-card shadow-[var(--shadow-card)]"
>
<CardContent className="relative p-6 md:p-8">
<CardContent className="relative p-6 md:p-7">
<div className="pointer-events-none absolute inset-0 opacity-70 [background:radial-gradient(circle_at_18%_12%,rgba(99,102,241,0.20),transparent_34%),radial-gradient(circle_at_84%_10%,rgba(16,185,129,0.10),transparent_30%)]" />

<div className="relative grid gap-6 lg:grid-cols-[1fr_260px] lg:items-center">
<div>
<div className="relative flex flex-col gap-5 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0 max-w-3xl">
<p className="font-bold text-[10px] uppercase tracking-[0.2em] text-muted-foreground">
{eyebrow}
</p>
<div className="mt-3 font-display font-extrabold text-foreground text-xl leading-tight tracking-tight md:text-2xl">
<div className="mt-2 font-display font-extrabold text-foreground text-xl leading-tight tracking-tight md:text-2xl">
{title}
</div>
<p className="mt-3 max-w-xl text-muted-foreground text-sm leading-6">
<p className="mt-2 text-muted-foreground text-sm leading-6">
{description}
</p>
{checks.length > 0 && (
<div className="mt-5 grid gap-2 sm:grid-cols-3">
<div className="mt-4 flex flex-wrap gap-2">
{checks.map((check) => (
<div
<span
key={check}
className="rounded-lg border border-border bg-background/40 px-3 py-2 text-foreground text-xs"
className="rounded-full border border-border bg-background/40 px-3 py-1 text-foreground text-xs"
>
{check}
</div>
</span>
))}
</div>
)}
</div>

<div className="rounded-xl border border-border bg-background/50 p-4">
<div className="grid grid-cols-2 gap-2">
{['Account', 'Network', 'Tx', 'History'].map((label) => (
<div
key={label}
className="rounded-lg border border-border bg-card/80 p-3"
>
<p className="text-muted-foreground text-[10px] uppercase tracking-wider">
{label}
</p>
<p className="mt-1 font-semibold text-foreground text-sm">
Locked
</p>
</div>
))}
</div>

<div className="mt-4">
<ConnectWalletButton className="tangle-cloud-wallet-action" />
</div>
</div>
<ConnectWalletButton className="tangle-cloud-wallet-action shrink-0" />
</div>
</CardContent>
</Card>
Expand Down
39 changes: 25 additions & 14 deletions apps/tangle-cloud/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,11 @@ const Sidebar: FC<Props> = ({ isExpandedByDefault, onExpandedChange }) => {
<>
<aside
className={twMerge(
'fixed bottom-0 left-0 top-0 z-50 hidden shrink-0 border-border border-r bg-background transition-[width] duration-200 lg:flex lg:flex-col',
'group/sidebar fixed bottom-0 left-0 top-0 z-50 hidden shrink-0 border-border border-r bg-background transition-[width] duration-200 lg:flex lg:flex-col',
isDesktopExpanded ? 'w-64' : 'w-16',
)}
>
<SidebarBrand isExpanded={isDesktopExpanded} />
<div className="px-2 pb-3">
<SidebarCollapseButton
isExpanded={isDesktopExpanded}
onClick={toggleDesktopExpanded}
/>
</div>
<SidebarNav
items={SIDEBAR_ITEMS}
pathname={pathname}
Expand All @@ -138,6 +132,11 @@ const Sidebar: FC<Props> = ({ isExpandedByDefault, onExpandedChange }) => {
isExpanded={isDesktopExpanded}
/>
</div>

<SidebarCollapseButton
isExpanded={isDesktopExpanded}
onClick={toggleDesktopExpanded}
/>
</aside>

<div className="fixed left-4 top-2 z-[45] lg:hidden">
Expand Down Expand Up @@ -224,6 +223,10 @@ const SidebarNav = ({
</nav>
);

// Pinned to the sidebar's right edge so it's affordance-clear (matches VS
// Code / Linear / Vercel patterns) and never competes with the nav stack
// for the "what's a nav item" mental model. Floats over the border so it
// stays visible whether the sidebar is expanded (w-64) or collapsed (w-16).
const SidebarCollapseButton = ({
isExpanded,
onClick,
Expand All @@ -233,15 +236,23 @@ const SidebarCollapseButton = ({
}) => (
<button
type="button"
className={twMerge(
'group flex h-10 items-center rounded-md border border-border bg-muted/20 text-xs font-semibold text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground',
isExpanded ? 'w-full justify-between px-3' : 'w-12 justify-center',
)}
aria-label={isExpanded ? 'Collapse navigation' : 'Expand navigation labels'}
onClick={onClick}
aria-label={isExpanded ? 'Collapse sidebar' : 'Expand sidebar'}
className="absolute -right-3 top-20 z-10 hidden h-6 w-6 items-center justify-center rounded-full border border-border bg-background text-muted-foreground opacity-0 shadow-[var(--shadow-card)] transition-opacity hover:text-foreground focus:opacity-100 group-hover/sidebar:opacity-100 group-focus-within/sidebar:opacity-100 lg:inline-flex"
>
{isExpanded && <span>Collapse</span>}
<span aria-hidden>{isExpanded ? '‹' : '›'}</span>
<svg
aria-hidden
viewBox="0 0 16 16"
className={twMerge(
'h-3 w-3 fill-none stroke-current transition-transform',
isExpanded ? '' : 'rotate-180',
)}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M10 4 6 8l4 4" />
</svg>
</button>
);

Expand Down
145 changes: 17 additions & 128 deletions apps/tangle-cloud/src/pages/earnings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,69 +47,21 @@ const EarningsPage: FC = () => {
if (!isConnected) {
return (
<div className="space-y-6">
<Card
variant="sandbox"
className="cloud-hero-card cloud-compact-header overflow-hidden border-border bg-card shadow-[var(--shadow-card)]"
>
<CardContent className="relative p-4 md:p-5">
<div className="pointer-events-none absolute inset-0 opacity-70 [background:radial-gradient(circle_at_12%_8%,rgba(99,102,241,0.18),transparent_32%),radial-gradient(circle_at_86%_12%,rgba(16,185,129,0.10),transparent_28%)]" />
<div className="relative grid gap-5 xl:grid-cols-[minmax(0,1fr)_420px] xl:items-center">
<div>
<h1 className="font-display font-extrabold text-3xl text-foreground leading-[1.05] tracking-[-0.035em] sm:text-4xl">
Publisher earnings
</h1>
<p className="mt-3 max-w-2xl text-muted-foreground text-sm leading-relaxed">
Track blueprint payout totals and indexed payment events for
the connected publisher wallet.
</p>
</div>

<div className="grid grid-cols-3 gap-2">
<HeroMetric label="Assets" value="Grouped" />
<HeroMetric label="Events" value="Indexed" />
<HeroMetric label="Explorer" value="Linked" />
</div>
</div>
</CardContent>
</Card>
<EarningsHero />

<RequireWallet
eyebrow="Earnings"
title="Connect to load earnings"
description="Load publisher balances, payout totals, and indexed payment events for the connected wallet."
checks={['Token totals', 'Payout events', 'Explorer links']}
/>
<EarningsPreviewPanel />
</div>
);
}

return (
<div className="space-y-6">
<Card
variant="sandbox"
className="cloud-hero-card cloud-compact-header overflow-hidden border-border bg-card shadow-[var(--shadow-card)]"
>
<CardContent className="relative p-4 md:p-5">
<div className="pointer-events-none absolute inset-0 opacity-70 [background:radial-gradient(circle_at_12%_8%,rgba(99,102,241,0.18),transparent_32%),radial-gradient(circle_at_86%_12%,rgba(16,185,129,0.10),transparent_28%)]" />
<div className="relative grid gap-5 xl:grid-cols-[minmax(0,1fr)_420px] xl:items-center">
<div>
<h1 className="font-display font-extrabold text-3xl text-foreground leading-[1.05] tracking-[-0.035em] sm:text-4xl">
Publisher earnings
</h1>
<p className="mt-3 max-w-2xl text-muted-foreground text-sm leading-relaxed">
Totals are derived from indexed on-chain payout events.
</p>
</div>

<div className="grid grid-cols-3 gap-2">
<HeroMetric label="Assets" value="Live" />
<HeroMetric label="Events" value="Exact" />
<HeroMetric label="Explorer" value="Linked" />
</div>
</div>
</CardContent>
</Card>
<EarningsHero />

{isLoading ? <EarningsLoadingState /> : null}
{!isLoading && isUnsupportedSchema && data ? (
Expand Down Expand Up @@ -157,85 +109,22 @@ const EarningsPage: FC = () => {

export default EarningsPage;

const EarningsPreviewPanel = () => (
<Card variant="sandbox" className="border-border bg-card">
<CardContent className="space-y-5 p-5">
<div className="grid gap-4 md:grid-cols-3">
<PreviewItem
label="Balances"
title="Token totals"
description="Publisher payouts grouped by asset from indexed payment events."
/>
<PreviewItem
label="Ledger"
title="Payout events"
description="Exact transaction records with service, asset, and explorer context."
/>
<PreviewItem
label="Operations"
title="Withdrawal planning"
description="Use the ledger to reconcile revenue from deployed blueprint services."
/>
</div>

<div className="overflow-hidden rounded-xl border border-border bg-background/40">
<div className="grid grid-cols-[1fr_1fr_1fr_1fr] border-border border-b px-4 py-3 font-semibold text-muted-foreground text-[10px] uppercase tracking-wider">
<span>Asset</span>
<span>Earned</span>
<span>Last payout</span>
<span>Status</span>
</div>
{[
['TNT', 'Connect wallet', 'Indexed event', 'Locked'],
['USDC', 'Connect wallet', 'Service payout', 'Locked'],
['ETH', 'Connect wallet', 'Explorer link', 'Locked'],
].map(([asset, earned, payout, status]) => (
<div
key={asset}
className="grid grid-cols-[1fr_1fr_1fr_1fr] border-border border-b px-4 py-3 text-sm last:border-b-0"
>
<span className="font-semibold text-foreground">{asset}</span>
<span className="text-muted-foreground">{earned}</span>
<span className="text-muted-foreground">{payout}</span>
<span className="font-semibold text-muted-foreground">
{status}
</span>
</div>
))}
const EarningsHero = () => (
<Card
variant="sandbox"
className="cloud-hero-card cloud-compact-header overflow-hidden border-border bg-card shadow-[var(--shadow-card)]"
>
<CardContent className="relative p-4 md:p-5">
<div className="pointer-events-none absolute inset-0 opacity-70 [background:radial-gradient(circle_at_12%_8%,rgba(99,102,241,0.18),transparent_32%),radial-gradient(circle_at_86%_12%,rgba(16,185,129,0.10),transparent_28%)]" />
<div className="relative">
<h1 className="font-display font-extrabold text-3xl text-foreground leading-[1.05] tracking-[-0.035em] sm:text-4xl">
Publisher earnings
</h1>
<p className="mt-3 max-w-2xl text-muted-foreground text-sm leading-relaxed">
Track blueprint payout totals and indexed payment events for the
connected publisher wallet.
</p>
</div>
</CardContent>
</Card>
);

const PreviewItem = ({
label,
title,
description,
}: {
label: string;
title: string;
description: string;
}) => (
<div className="rounded-xl border border-border bg-muted/30 p-4">
<p className="font-semibold text-muted-foreground text-[10px] uppercase tracking-wider">
{label}
</p>
<div className="mt-2 font-display font-bold text-foreground text-base">
{title}
</div>
<p className="mt-2 text-muted-foreground text-sm leading-relaxed">
{description}
</p>
</div>
);

const HeroMetric = ({ label, value }: { label: string; value: string }) => (
<div className="rounded-md border border-border bg-card/70 p-2.5">
<p className="font-medium text-muted-foreground text-[10px] uppercase tracking-wider">
{label}
</p>
<p className="mt-0.5 font-display font-bold text-foreground text-base">
{value}
</p>
</div>
);
31 changes: 8 additions & 23 deletions apps/tangle-cloud/src/pages/instances/AccountStatsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,45 +120,30 @@ export const AccountStatsCard: FC<AccountStatsCardProps> = (props) => {
rootProps?.className,
)}
>
<CardContent className="grid gap-6 p-5 md:grid-cols-[1fr_220px] md:p-6">
<div className="flex min-w-0 gap-4">
<CardContent className="flex h-full flex-col gap-5 p-5 md:p-6">
<div className="flex min-w-0 items-start gap-4">
<Avatar className="h-12 w-12 border border-border bg-muted">
<AvatarFallback className="font-display font-bold text-foreground">
TC
</AvatarFallback>
</Avatar>

<div className="min-w-0">
<div className="min-w-0 flex-1">
<p className="font-semibold text-muted-foreground text-xs uppercase tracking-wider">
Account
</p>
<div className="mt-2 font-display font-bold text-foreground text-lg tracking-tight">
Wallet required
Connect a wallet to load your account
</div>
<p className="mt-2 max-w-xl text-muted-foreground text-sm leading-relaxed">
Connect to load deployed services, operator registrations, and
account-scoped lifecycle events.
account-scoped lifecycle events. Public catalog and operator
registry data load below without a wallet.
</p>
<div className="mt-5">
<ConnectWalletButton className="tangle-cloud-wallet-action" />
</div>
</div>
</div>

<div className="grid grid-cols-2 gap-2">
{['Services', 'Approvals', 'Jobs', 'Balances'].map((label) => (
<div
key={label}
className="rounded-lg border border-border bg-muted/30 p-3"
>
<p className="text-muted-foreground text-[10px] uppercase tracking-wider">
{label}
</p>
<p className="mt-1 font-semibold text-foreground text-sm">
Locked
</p>
</div>
))}
<div className="mt-auto">
<ConnectWalletButton className="tangle-cloud-wallet-action" />
</div>
</CardContent>
</Card>
Expand Down
Loading
Loading