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
42 changes: 19 additions & 23 deletions app/components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const styles: Record<string, CSSProperties> = {
borderRadius: 999,
padding: '1px 6px',
},
// Pinned below the sliding panes so Status/Support/Docs/Upgrades/Blog stay put
// Pinned below the sliding panes so Upgrades/Docs/Status/Support/Blog stay put
// when a section sub-nav slides in. The switch sits on the last row beside Blog.
sidebarFooter: {
display: 'flex',
Expand Down Expand Up @@ -574,6 +574,16 @@ function SidebarContent({ dark, onToggleTheme, onNavigate, hideBrand }: SidebarC
<span className={TEXT_TRIM}>Upgrades</span>
</span>
</a>
<a href="https://docs.base.org" target="_blank" rel="noreferrer" className={SIDEBAR_FOOTER_LINK} style={styles.footerLink}>
<span className={SIDEBAR_FOOTER_LINK_LABEL}>
<span style={styles.footerIcon}>
<svg width={18} height={18} viewBox="6 6 28 28" fill="none" stroke="currentColor" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<path d="M15 15H19.5M15 25H19.5M15 20H16M24 15L25 15M24 25H25M21 20H25M13 31H27C29.2091 31 31 29.2091 31 27V13C31 10.7909 29.2091 9 27 9H13C10.7909 9 9 10.7909 9 13V27C9 29.2091 10.7909 31 13 31Z" />
</svg>
</span>
<span className={TEXT_TRIM}>Docs</span>
</span>
</a>
<a href="https://status.base.org" target="_blank" rel="noreferrer" className={SIDEBAR_FOOTER_LINK} style={styles.footerLink}>
<span className={SIDEBAR_FOOTER_LINK_LABEL}>
<span style={styles.footerIcon}>
Expand All @@ -594,32 +604,18 @@ function SidebarContent({ dark, onToggleTheme, onNavigate, hideBrand }: SidebarC
<span className={TEXT_TRIM}>Support</span>
</span>
</a>
<a href="https://docs.base.org" target="_blank" rel="noreferrer" className={SIDEBAR_FOOTER_LINK} style={styles.footerLink}>
<a href="https://blog.base.org" target="_blank" rel="noreferrer" className={SIDEBAR_FOOTER_LINK} style={styles.footerLink}>
<span className={SIDEBAR_FOOTER_LINK_LABEL}>
<span style={styles.footerIcon}>
<svg width={18} height={18} viewBox="6 6 28 28" fill="none" stroke="currentColor" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<path d="M15 15H19.5M15 25H19.5M15 20H16M24 15L25 15M24 25H25M21 20H25M13 31H27C29.2091 31 31 29.2091 31 27V13C31 10.7909 29.2091 9 27 9H13C10.7909 9 9 10.7909 9 13V27C9 29.2091 10.7909 31 13 31Z" />
<svg width={16} height={16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<path d="M12.75 19.5V18.75C12.75 16.76 11.96 14.85 10.55 13.45C9.15 12.04 7.24 11.25 5.25 11.25H4.5M4.5 4.5H5.25C13.12 4.5 19.5 10.88 19.5 18.75V19.5M6 18.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
</svg>
</span>
<span className={TEXT_TRIM}>Docs</span>
<span className={TEXT_TRIM}>Blog</span>
</span>
</a>
<div style={styles.footerLastRow}>
<a href="https://blog.base.org" target="_blank" rel="noreferrer" className={SIDEBAR_FOOTER_LINK} style={{ ...styles.footerLink, flex: 1 }}>
<span className={SIDEBAR_FOOTER_LINK_LABEL}>
<span style={styles.footerIcon}>
<svg width={16} height={16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<path d="M12.75 19.5V18.75C12.75 16.76 11.96 14.85 10.55 13.45C9.15 12.04 7.24 11.25 5.25 11.25H4.5M4.5 4.5H5.25C13.12 4.5 19.5 10.88 19.5 18.75V19.5M6 18.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
</svg>
</span>
<span className={TEXT_TRIM}>Blog</span>
</span>
</a>
{/* `role="switch"` rather than a plain button: the control reports a state
rather than firing an action, so screen readers announce "on"/"off"
against a stable label instead of the label itself changing. The switch
renders bare, so that name comes from `aria-label` — the visible track
is decorative and hidden from the tree. */}
<div style={styles.footerLastRow} className="justify-between -mb-1.5">
<span className="pl-2.5 text-[12px] font-medium text-bds-gray-20 dark:text-bds-gray-40">Developer Console</span>
<button
type="button"
role="switch"
Expand All @@ -631,11 +627,11 @@ function SidebarContent({ dark, onToggleTheme, onNavigate, hideBrand }: SidebarC
>
<span
aria-hidden
className={`${THEME_SWITCH_ANIM} bg-bds-gray-50 transition-colors duration-[180ms] motion-reduce:transition-none group-hover:bg-bds-gray-70 dark:bg-brand-blue dark:group-hover:bg-[color-mix(in_srgb,var(--bds-brand)_82%,white)] group-focus-visible:outline group-focus-visible:outline-2 group-focus-visible:outline-offset-2 group-focus-visible:outline-brand-blue`}
className={`${THEME_SWITCH_ANIM} bg-brand-blue transition-colors duration-[180ms] motion-reduce:transition-none group-hover:bg-[color-mix(in_srgb,var(--bds-brand)_82%,black)] dark:bg-brand-blue dark:group-hover:bg-[color-mix(in_srgb,var(--bds-brand)_82%,white)] group-focus-visible:outline group-focus-visible:outline-2 group-focus-visible:outline-offset-2 group-focus-visible:outline-brand-blue`}
style={styles.switchTrack}
>
<span
className={`${THEME_SWITCH_ANIM} text-bds-gray-50 transition-[transform,color] duration-[180ms] ease-out motion-reduce:transition-none dark:translate-x-[14px] dark:text-brand-blue`}
className={`${THEME_SWITCH_ANIM} text-brand-blue transition-[transform,color] duration-[180ms] ease-out motion-reduce:transition-none dark:translate-x-[14px] dark:text-brand-blue`}
style={styles.switchThumb}
>
<ThemeIcon />
Expand Down
101 changes: 24 additions & 77 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Button } from './components/ui/Button';
import { Card, LinkCard } from './components/ui/Card';
import { Text } from './components/ui/Text';
import { listedDemos } from './vibenet/demos/catalogue';
import { DemoCard } from './vibenet/demos/DemoCard';
Expand All @@ -11,28 +10,6 @@ import { SnapshotDownloadBox } from './snapshots/SnapshotDownloadBox';
// content (including the live snapshot stats) instead of a per-request render.
export const revalidate = 300;

type Surface = {
label: string;
href: string;
description: string;
enabled: boolean;
};

const SURFACES: Surface[] = [
{
label: 'Vibenet',
href: '/vibenet',
description: 'An ephemeral Base developer network for testing in-flight features.',
enabled: true,
},
{
label: 'Snapshots',
href: '/snapshots',
description: 'Download and configure Reth v2 snapshots to sync a Base node faster.',
enabled: true,
},
];

// Latest Mainnet archive snapshot for the homepage download box. Mirrors the
// loadSnapshots fallback on /snapshots: sample data in dev when R2 is
// unconfigured, and null (box hidden) if R2 is down in production.
Expand Down Expand Up @@ -61,24 +38,28 @@ export default async function Home() {
const mainnetSnapshot = await loadMainnetSnapshot();

return (
<div className="animate-in flex min-w-0 flex-1 flex-col gap-12 py-4 text-foreground">
<div className="animate-in mx-auto flex w-full min-w-0 max-w-5xl flex-1 flex-col gap-16 pt-8 pb-4 text-foreground">
<header className="flex max-w-2xl flex-col gap-3">
<Text variant="title2">Base&apos;s Building Ground</Text>
<Text variant="title2">Base Developer Console</Text>
<Text variant="body" tone="muted">
Explore in-flight features on Vibenet and sync a node from the latest snapshot.
</Text>
</header>

<section className="flex flex-col gap-6">
<div className="flex flex-wrap items-end justify-between gap-3">
<div className="flex flex-col gap-1">
<section className="flex flex-col gap-4">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-3">
<Text variant="headline">Featured Demos</Text>
<Text variant="label.regular" tone="muted">
Interactive walkthroughs running on Vibenet right now.
</Text>
<span className="inline-flex items-center gap-2 rounded-lg bg-[color-mix(in_srgb,var(--base-blue-p3)_10%,transparent)] px-2 py-0.5 text-[13px] font-[450] text-base-blue">
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-base-blue opacity-75" />
<span className="relative inline-flex h-2 w-2 rounded-full bg-base-blue" />
</span>
Live on Vibenet
</span>
</div>
<Button href="/vibenet" variant="outline" size="sm" arrow>
All demos
All Demos
</Button>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
Expand All @@ -89,56 +70,22 @@ export default async function Home() {
</section>

{mainnetSnapshot ? (
<section className="flex flex-col gap-6">
<div className="flex flex-col gap-1">
<Text variant="headline">Sync a Node Faster</Text>
<Text variant="label.regular" tone="muted">
Grab the latest Base Mainnet archive snapshot, or customize your own.
</Text>
<section className="flex flex-col gap-4">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex flex-col gap-1">
<Text variant="headline">Snapshots</Text>
<Text variant="label.regular" tone="muted">
Sync a node from the latest Base Mainnet archive snapshot, or customize your own.
</Text>
</div>
<Button href="/snapshots" variant="outline" size="sm" arrow>
Customize
</Button>
</div>
<SnapshotDownloadBox snapshot={mainnetSnapshot} />
</section>
) : null}

<section className="flex flex-col gap-6">
<Text variant="headline">Explore</Text>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{SURFACES.map((surface) => (
<SurfaceCard key={surface.href} surface={surface} />
))}
</div>
</section>
</div>
);
}

function SurfaceCard({ surface }: { surface: Surface }) {
if (!surface.enabled) {
return (
<Card className="bg-background p-5 opacity-60 dark:bg-white/5">
<div className="flex items-center gap-2">
<Text variant="headline">{surface.label}</Text>
<span className="rounded-full border border-bds-gray-15 px-2.5 py-0.5 text-[13px] text-bds-gray-60">
Soon
</span>
</div>
<Text variant="label.regular" tone="muted" className="mt-1">
{surface.description}
</Text>
</Card>
);
}

return (
<LinkCard
href={surface.href}
interactive={false}
className="group bg-background p-5 transition-colors hover:bg-bds-gray-5 dark:bg-white/5 dark:hover:bg-white/[0.08]"
>
<Text variant="headline">{surface.label}</Text>
<Text variant="label.regular" tone="muted" className="mt-1">
{surface.description}
</Text>
</LinkCard>
);
}
22 changes: 5 additions & 17 deletions app/snapshots/SnapshotDownloadBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Button } from '../components/ui/Button';
import { Card } from '../components/ui/Card';
import { CommandLine } from '../components/ui/CommandLine';
import { Text } from '../components/ui/Text';
Expand All @@ -25,34 +24,23 @@ export function SnapshotDownloadBox({ snapshot }: { snapshot: Snapshot }) {
<Card className="flex flex-col gap-5 bg-background p-6 dark:bg-white/5">
<div className="flex flex-wrap items-center gap-2">
<Text variant="headline">Mainnet Archive</Text>
<span className="rounded-full border border-bds-gray-15 px-2.5 py-0.5 text-[13px] text-bds-gray-60 dark:border-white/15">
Full historical data
<span className="rounded-lg bg-bds-gray-5 px-2 py-0.5 text-[13px] font-[450] text-bds-gray-50 dark:bg-white/10">
Full Historical Data
</span>
</div>

<div className="grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4">
{stats.map((stat) => (
<div key={stat.label} className="flex flex-col gap-1">
<Text variant="label.regular" tone="muted">
<Text variant="label.medium" tone="muted">
{stat.label}
</Text>
<Text variant="headline">{stat.value}</Text>
<Text variant="label.medium">{stat.value}</Text>
</div>
))}
</div>

<div className="flex flex-col gap-3 sm:flex-row sm:items-stretch">
<CommandLine command={ARCHIVE_COMMAND} className="sm:w-3/4" />
<Button
href="/snapshots"
variant="outline"
size="sm"
arrow
className="sm:h-auto sm:w-auto sm:flex-1"
>
Customize
</Button>
</div>
<CommandLine command={ARCHIVE_COMMAND} />
</Card>
);
}
7 changes: 6 additions & 1 deletion app/vibenet/demos/DemoCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Image from 'next/image';

import { Card, LinkCard } from '../../components/ui/Card';
import { cn } from '../../components/ui/cn';
import { Text } from '../../components/ui/Text';
Expand Down Expand Up @@ -33,6 +35,9 @@ export function DemoCard({ demo, className }: { demo: DemoEntry; className?: str
function DemoCardBody({ demo }: { demo: DemoEntry }) {
return (
<>
{demo.icon && (
<Image src={demo.icon} alt="" width={48} height={48} />
)}
<div>
<div className="flex items-center gap-2">
<Text variant="headline">{demo.title}</Text>
Expand All @@ -42,7 +47,7 @@ function DemoCardBody({ demo }: { demo: DemoEntry }) {
</span>
) : null}
</div>
<Text variant="body" tone="muted" className="mt-2">
<Text variant="label.regular" tone="muted" className="mt-2">
{demo.summary}
</Text>
</div>
Expand Down
6 changes: 3 additions & 3 deletions app/vibenet/demos/_shared/DemoGate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export function DemoGate({
return (
<div className="flex flex-1 items-center justify-center py-16">
<Card className="flex max-w-md flex-col items-center gap-4 bg-background px-8 py-14 text-center dark:bg-white/5">
<Image src="/vibenet-illo.svg" alt="" width={44} height={44} />
<Text variant="title2">{title}</Text>
<Text variant="label.regular" tone="muted" className="max-w-sm">
<Image src="/account-illo.svg" alt="" width={44} height={44} />
<Text variant="headline" className="mt-2">{title}</Text>
<Text variant="body" tone="muted" className="-mt-2 max-w-sm">
{description}
</Text>
<Button onClick={onCreate} disabled={creating} className="mt-2">
Expand Down
8 changes: 4 additions & 4 deletions app/vibenet/demos/account/components/CreateAccountModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) {
aria-checked={createMode === mode}
onClick={() => setCreateMode(mode)}
className={cn(
'flex flex-col gap-1 rounded-lg border p-3 text-left transition-colors',
'flex flex-col gap-1 rounded-lg border p-3 text-left transition-[color,box-shadow] duration-150 ease-out',
createMode === mode
? 'border-foreground'
? 'border-transparent ring-2 ring-foreground'
: 'border-bds-gray-10 hover:border-foreground dark:border-white/10 dark:hover:border-white',
)}
>
Expand Down Expand Up @@ -297,9 +297,9 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) {
aria-checked={modalType === type}
onClick={() => setModalType(type)}
className={cn(
'flex flex-col gap-1 rounded-lg border p-3 text-left transition-colors',
'flex flex-col gap-1 rounded-lg border p-3 text-left transition-[color,box-shadow] duration-150 ease-out',
modalType === type
? 'border-foreground'
? 'border-transparent ring-2 ring-foreground'
: 'border-bds-gray-10 hover:border-foreground dark:border-white/10 dark:hover:border-white',
)}
>
Expand Down
4 changes: 4 additions & 0 deletions app/vibenet/demos/catalogue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type DemoEntry = {
available: boolean;
/** When false, the route stays live but is omitted from the Vibenet demos grid. */
listed?: boolean;
/** Path to an icon image in /public, shown at the top of the demo card. */
icon?: string;
};

/** Demos shown on the Vibenet index. Unlisted entries stay reachable by URL. */
Expand All @@ -31,6 +33,7 @@ export const DEMOS: DemoEntry[] = [
href: '/vibenet/demos/account',
title: 'Accounts',
shortTitle: 'Account',
icon: '/account-illo.svg',
summary:
'Create portable account-abstraction accounts from in-browser keys, fund them from the faucet, and inspect balances across networks.',
points: [
Expand All @@ -44,6 +47,7 @@ export const DEMOS: DemoEntry[] = [
href: '/vibenet/demos/b20',
title: 'Tokens',
shortTitle: 'Tokens',
icon: '/token-illo.svg',
summary:
"Create tokens with B20 — Base's enshrined, ERC-20-compatible token standard — then attach transfer policies, transaction memos, and Asset announcements with no custom contracts.",
points: [
Expand Down
4 changes: 2 additions & 2 deletions app/vibenet/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function VibenetHomePage() {

return (
<div className="animate-in -mb-20 flex min-w-0 flex-1 flex-col gap-16 pb-4 text-foreground">
<header className="flex flex-col gap-4 pb-4 md:flex-row md:items-start md:justify-between md:gap-8">
<header className="flex flex-col gap-4 pb-4 md:flex-row md:items-end md:justify-between md:gap-8">
<div className="flex max-w-xl flex-1 flex-col gap-6">
<Image src="/vibenet-illo.svg" alt="" width={48} height={48} className="mt-8" />
<Text variant="title2" tone="muted">
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function VibenetHomePage() {
</Card>
</header>

<section className="flex flex-col gap-6">
<section className="flex flex-col gap-4">
<Text variant="headline">Demos</Text>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{listedDemos().map((demo) => (
Expand Down
4 changes: 2 additions & 2 deletions e2e/home.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { expect, test } from '@playwright/test';
test('home page loads and shows the landing copy', async ({ page }) => {
await page.goto('/');

await expect(page.getByText("Base's Building Ground")).toBeVisible();
await expect(page.getByRole('main').getByRole('link', { name: /^Vibenet/i })).toBeVisible();
await expect(page.getByText("Base Developer Console")).toBeVisible();
await expect(page.getByRole('main').getByRole('link', { name: /^All Demos/i })).toBeVisible();
});
Loading
Loading