Skip to content

Commit f256ab2

Browse files
committed
ui tweaks
1 parent 1888b88 commit f256ab2

3 files changed

Lines changed: 14 additions & 111 deletions

File tree

‎app/components/AppShell.tsx‎

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { CSSProperties, MouseEvent as ReactMouseEvent, PropsWithChildren, useEff
44
import Link from 'next/link';
55
import { usePathname } from 'next/navigation';
66
import { Dialog } from '@base-ui/react/dialog';
7-
import { AnimatePresence, easeOut, motion, useIsPresent, useMotionTemplate, useMotionValue, usePresenceData, useReducedMotion, type MotionValue } from 'motion/react';
7+
import { AnimatePresence, easeOut, motion, useIsPresent, usePresenceData } from 'motion/react';
88
import { Toaster } from 'sonner';
99

1010
import { getActiveParent, isChildActive, isTopNavActive, navActiveParent, navHighlightPath, NAV_ITEMS, NavIcon, titleForPath } from '../navigation';
@@ -18,7 +18,7 @@ import { NavScrollArea } from './NavScrollArea';
1818
import { AnimatedBaseLogo, BaseMark } from './ui/AnimatedBaseLogo';
1919
import { Breadcrumb } from './ui/Breadcrumb';
2020
import { cn } from './ui/cn';
21-
import { AnimatedArrowIcon, CloseIcon } from './ui/icons';
21+
import { AnimatedArrowIcon } from './ui/icons';
2222
import { Text, textVariantClasses } from './ui/Text';
2323

2424
const SIDEBAR_WIDTH = 248;
@@ -359,8 +359,6 @@ function TopNavList({ highlightPath, onSelect }: { highlightPath: string; onSele
359359
}
360360

361361
const slideTransition = { duration: 0.2, ease: easeOut, x: { visualDuration: 0.2, type: 'spring', bounce: 0 } };
362-
/** Matches `h-9` / theme(spacing.9). */
363-
const APP_BANNER_HEIGHT = '2.25rem';
364362

365363
// How long the nav trusts a tapped href before falling back to the router. Only
366364
// reached if a navigation never commits (aborted, failed, or a modified click that
@@ -649,63 +647,6 @@ function SidebarContent({ dark, onToggleTheme, onNavigate, hideBrand }: SidebarC
649647
);
650648
}
651649

652-
type GlobalBannerProps = {
653-
dismissed: boolean;
654-
onDismiss: () => void;
655-
className?: string;
656-
height: MotionValue<string>;
657-
};
658-
659-
function GlobalBanner({ dismissed, onDismiss, className, height }: GlobalBannerProps) {
660-
const reducedMotion = useReducedMotion();
661-
const transition = reducedMotion ? { duration: 0 } : slideTransition;
662-
663-
return (
664-
<motion.div
665-
className={cn(className, 'overflow-clip after:pointer-events-none after:inset-x-0 after:absolute after:bottom-0 after:border-b after:border-bds-gray-10 bg-bds-gray-5')}
666-
style={{ height }}
667-
initial={false}
668-
animate={{ height: dismissed ? '0rem' : APP_BANNER_HEIGHT }}
669-
transition={transition}
670-
>
671-
<motion.div
672-
className="relative flex w-full shrink-0 items-center justify-center border-b border-transparent pl-4 pr-10 sm:px-10"
673-
initial={false}
674-
animate={{ opacity: dismissed ? 0 : 1 }}
675-
transition={transition}
676-
style={{ height: APP_BANNER_HEIGHT }}
677-
>
678-
<div className="mx-auto flex w-full max-w-6xl flex-col items-center justify-center min-[860px]:flex-row min-[860px]:gap-5">
679-
<div className="flex min-w-0 flex-wrap items-center justify-center gap-x-2 gap-y-1 min-[860px]:flex-nowrap">
680-
<Text as="span" variant="label.medium" className="whitespace-nowrap text-[12.5px] leading-[16px] font-[500] md:text-[12.5px] md:leading-[16px] md:font-[500] [text-box-trim:trim-both] [text-box-edge:cap_alphabetic]">New!</Text>
681-
<Text as="span" variant="label.medium" className="whitespace-nowrap text-[12.5px] leading-[16px] font-[500] md:text-[12.5px] md:leading-[16px] md:font-[500] [text-box-trim:trim-both] [text-box-edge:cap_alphabetic]">EIP-8130: Accounts</Text>
682-
<span className="inline-block h-3.5 w-px shrink-0 bg-bds-gray-20"></span>
683-
<Link
684-
href="/vibenet/demos/account"
685-
className="group flex shrink-0 items-center gap-1 no-underline"
686-
onClick={(event) => {
687-
if (opensInNewTab(event)) return;
688-
onDismiss();
689-
}}
690-
>
691-
<Text as="span" variant="label.medium" className="text-[12.5px] leading-[16px] font-[500] md:text-[12.5px] md:leading-[16px] md:font-[500] [text-box-trim:trim-both] [text-box-edge:cap_alphabetic] text-base-blue">Test on Vibenet</Text>
692-
<AnimatedArrowIcon size={14} strokeWidth={2} className="text-base-blue transition-transform duration-200 ease-out group-hover:translate-x-[3px]" />
693-
</Link>
694-
</div>
695-
</div>
696-
<button
697-
type="button"
698-
onClick={onDismiss}
699-
className="absolute right-4 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center text-bds-gray-40 transition-colors hover:text-foreground"
700-
aria-label="Dismiss banner"
701-
>
702-
<CloseIcon size={10} />
703-
</button>
704-
</motion.div>
705-
</motion.div>
706-
);
707-
}
708-
709650
// next-themes `disableTransitionOnChange`: stamp a global `transition: none`
710651
// rule, apply the theme, force a restyle, then drop the rule on the next tick
711652
// so color tokens don't animate through every `transition-colors` on the page.
@@ -734,10 +675,7 @@ function disableAnimation() {
734675
export function AppShell({ children }: PropsWithChildren) {
735676
const pathname = usePathname() || '/';
736677
const title = titleForPath(pathname);
737-
const bannerHeight = useMotionValue(APP_BANNER_HEIGHT);
738-
const sidebarHeight = useMotionTemplate`calc(100dvh - ${bannerHeight})`;
739678
const [menuOpen, setMenuOpen] = useState(false);
740-
const [bannerDismissed, setBannerDismissed] = useState(false);
741679
// aria-checked only. The switch's look is CSS against html[data-theme],
742680
// which the pre-paint script already set — this state starts false so SSR
743681
// and the first client render match, then catches up after mount.
@@ -775,20 +713,11 @@ export function AppShell({ children }: PropsWithChildren) {
775713

776714
return (
777715
<div className="flex min-h-dvh flex-col">
778-
{/* Desktop: banner spans the full width above the shell. On mobile it is
779-
rendered below the fixed header instead (see below), so it isn't hidden
780-
behind it. */}
781-
<GlobalBanner
782-
dismissed={bannerDismissed}
783-
onDismiss={() => setBannerDismissed(true)}
784-
height={bannerHeight}
785-
className="sticky top-0 z-50 hidden md:block"
786-
/>
787716
<div style={styles.root}>
788717
{/* Desktop sidebar */}
789718
<motion.aside
790719
className="sidebar-desktop sticky self-start"
791-
style={{ ...styles.sidebar, top: bannerHeight, height: sidebarHeight }}
720+
style={{ ...styles.sidebar, top: 0, height: '100dvh' }}
792721
>
793722
<SidebarContent dark={dark} onToggleTheme={toggleTheme} />
794723
</motion.aside>
@@ -823,17 +752,9 @@ export function AppShell({ children }: PropsWithChildren) {
823752
</Dialog.Root>
824753

825754
<div className="pt-14 md:pt-0" style={styles.main}>
826-
{/* Mobile: banner sits below the fixed header (which the top slot is
827-
hidden behind), so it's visible without scrolling. */}
828-
<GlobalBanner
829-
dismissed={bannerDismissed}
830-
onDismiss={() => setBannerDismissed(true)}
831-
height={bannerHeight}
832-
className="sticky top-14 z-50 block md:hidden"
833-
/>
834755
<motion.header
835756
className="topbar-desktop sticky z-40 bg-background"
836-
style={{ ...styles.topbar, top: bannerHeight }}
757+
style={{ ...styles.topbar, top: 0 }}
837758
>
838759
<div id="topbar-actions-slot" className="absolute right-7 top-1/2 z-10 flex -translate-y-1/2 items-center gap-2" />
839760
{(() => {

‎app/vibenet/demos/account/AccountDemo.tsx‎

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { useState } from 'react';
1414
import { AnimatePresence, motion } from 'motion/react';
1515

1616
import { Button } from '../../../components/ui/Button';
17-
import { Modal } from '../../../components/ui/Modal';
1817
import { Text } from '../../../components/ui/Text';
1918
import { AccountDemoShell } from '../_components/AccountDemoShell';
2019
import { FeatureCard } from '../../components/FeatureCard';
@@ -37,7 +36,7 @@ export function AccountDemo() {
3736

3837
function AccountDemoInner() {
3938
const engine = useAccountEngine();
40-
const { accounts, activeAccountId, activity, regenesisNotice, setRegenesisNotice, acct } = engine;
39+
const { accounts, activeAccountId, activity, acct } = engine;
4140

4241
const [transactionRequest, setTransactionRequest] = useState<{
4342
preset?: TransactPreset;
@@ -126,22 +125,6 @@ function AccountDemoInner() {
126125
preset={transactionRequest.preset}
127126
/>
128127
) : null}
129-
130-
<Modal
131-
open={regenesisNotice}
132-
onClose={() => setRegenesisNotice(false)}
133-
title="Chain Was Reset"
134-
footer={
135-
<Button variant="primary" size="sm" onClick={() => setRegenesisNotice(false)}>
136-
Got It
137-
</Button>
138-
}
139-
>
140-
<Text variant="body" tone="muted">
141-
The vibenet devnet has been regenesised — its onchain state was wiped. Your
142-
accounts and keys are still here and their addresses are unchanged; top up to transact again.
143-
</Text>
144-
</Modal>
145128
</>
146129
);
147130

‎app/vibenet/demos/account/useAccountEngine.tsx‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ function useAccountEngineCore() {
205205
setActivity,
206206
networkShort,
207207
setNetworkShort,
208+
genesisHash,
208209
setGenesisHash,
209210
hydrated,
210211
addAccount,
@@ -214,9 +215,6 @@ function useAccountEngineCore() {
214215
const [busy, setBusy] = useState(false);
215216
const [faucetBusy, setFaucetBusy] = useState<string | null>(null);
216217

217-
// Regenesis (devnet reset) detection.
218-
const [regenesisNotice, setRegenesisNotice] = useState(false);
219-
220218
const chain = useMemo(() => getDemoChain(networkShort), [networkShort]);
221219

222220
// A viem public client pointed at vibenet's cross-origin RPC route — reads
@@ -260,18 +258,21 @@ function useAccountEngineCore() {
260258
return;
261259
}
262260
if (!hash || cancelled) return;
263-
setGenesisHash((prev) => {
264-
if (prev && prev !== hash) setRegenesisNotice(true);
265-
return hash;
266-
});
261+
if (genesisHash && genesisHash !== hash) {
262+
toast.info('Vibenet chain was reset', {
263+
description: 'Your accounts, keys, and addresses are unchanged. Top up to transact again.',
264+
duration: 8_000,
265+
});
266+
}
267+
if (genesisHash !== hash) setGenesisHash(hash);
267268
};
268269
checkGenesis();
269270
const t = setInterval(checkGenesis, 10_000);
270271
return () => {
271272
cancelled = true;
272273
clearInterval(t);
273274
};
274-
}, [hydrated, makeRpcClient, setGenesisHash]);
275+
}, [genesisHash, hydrated, makeRpcClient, setGenesisHash]);
275276

276277
// --- helpers -----------------------------------------------------------
277278
// Entries that name a tx hash pick up its inclusion timing automatically, so
@@ -637,8 +638,6 @@ function useAccountEngineCore() {
637638
busy,
638639
activeSigner,
639640
signerForAccount,
640-
regenesisNotice,
641-
setRegenesisNotice,
642641

643642
// Faucet
644643
faucetBusy,

0 commit comments

Comments
 (0)