Skip to content

[WIP] v3 uplift - #3075

Draft
abjt14 wants to merge 100 commits into
mainfrom
v3-uplift
Draft

[WIP] v3 uplift#3075
abjt14 wants to merge 100 commits into
mainfrom
v3-uplift

Conversation

@abjt14

@abjt14 abjt14 commented Jul 21, 2026

Copy link
Copy Markdown

No description provided.

abjt14 added 29 commits July 16, 2026 08:14
…e transition

Phase 1 of a unified overlay motion system. A shared ScaleFade transition
(opacity 0→1 + scale 0.96→1, modeled on MUI's Grow) is wired as the default
TransitionComponent for MuiMenu and MuiPopover at 100ms, so all menus, selects
and popovers pop consistently instead of using MUI's default Grow. Timing lives
in a single motion-tokens module.

- src/utils/motion.ts: central duration/easing tokens (single source of truth)
- ScaleFade: MUI-compatible transition primitive (scale 0.96, not Grow's 0.75)
- theme: MuiMenu/MuiPopover transition defaults + global prefers-reduced-motion
- showcase: Select/Menu specimens in the Overlays section

Modals and drawers are intentionally untouched (deferred to later phases).
The outlined variant sets border:none at rest, but its :hover block only changed
background + re-asserted the box-shadow ring, so MUI's built-in
.MuiButton-outlinedPrimary:hover border leaked through on hover only. Force
border:none in the hover/focus block so the borderless pill stays borderless.
…radients

- figmaColors.ts: single source of truth for color tokens + the figVars var() accessor.

- theme.tsx: flatten tokens onto the MUI CssVars palette (P3 + sRGB fallback); emit P3 vars.

- colorToP3.ts: Display-P3 conversion for the @supports P3 override layer.

- gradients slot/type removed; the new branding uses the solid purple-1 token.
Sweep explicit color reads onto flattened figma tokens (bare sx strings / figVars) for P3.

Also swaps the brand gradient for the solid purple-1 token in the affected components.
Same token sweep across module components for Display-P3 with sRGB fallback.

Swaps the brand gradient for purple-1 in the E-Mode button, StakeActionBox and version badge.
Token sweep across layouts; swaps the newGradient banner for purple-1 in TopBarNotify.
Buttons, icon and toggle buttons scale to 0.99 on :active (not disabled) via a shared fragment.

MarketSwitcher's custom Box trigger gets the same press feedback inline.
DotsHorizontalIcon: currentColor meatball icon replacing the '...' text supply dropdown.

iconButtonSx (buttonStyles.ts): square icon-only button styling (min-width 0, 0.25rem pad).

Desktop table action buttons across the four dashboard lists set to size=small.
@abjt14 abjt14 self-assigned this Jul 21, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

📦 Next.js Bundle Analysis for aave-ui

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 1.34 MB (🟡 +13.07 KB)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

Sixteen Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load
/ 91.53 KB (🟢 -4.48 KB) 1.42 MB
/404 2.08 KB (🟢 -776 B) 1.34 MB
/500 2.41 KB (🟢 -774 B) 1.34 MB
/bridge 36.68 KB (🟢 -1.06 KB) 1.37 MB
/dashboard 80.93 KB (🟢 -4.66 KB) 1.41 MB
/faucet 9.93 KB (🟢 -5.12 KB) 1.34 MB
/governance 42.19 KB (🟢 -770 B) 1.38 MB
/governance/ipfs-preview 100.03 KB (🟢 -1.62 KB) 1.43 MB
/governance/v3/proposal 86.01 KB (🟢 -2.78 KB) 1.42 MB
/history 31.54 KB (🟢 -4.8 KB) 1.37 MB
/markets 54.07 KB (🟢 -835 B) 1.39 MB
/reserve-overview 38.4 KB (🟢 -1.46 KB) 1.37 MB
/safety-module 54.78 KB (🟢 -1.66 KB) 1.39 MB
/sgho 91.65 KB (🟢 -1.34 KB) 1.42 MB
/staking 30.71 KB (🟢 -2.77 KB) 1.37 MB
/v3-migration 47.76 KB (🟢 -4.88 KB) 1.38 MB
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this.

abjt14 added 2 commits August 5, 2026 11:08
The footer laid itself out directly on its outer Box with a hardcoded
padding array, including an asymmetric '0 22px 0 40px' step, and no
maxWidth at all — so its content ran to the viewport edge and never lined
up with the header's.

Moves the flex layout into a Container so horizontal padding and maxWidth
come from the themed MuiContainer ladder, the same one AppHeader uses. The
outer Box keeps width/boxShadow so the divider still spans full-bleed.
Vertical padding is unchanged (22/40, 0/0, 20/20 per breakpoint).
The container's md step padded 96px while the box was still uncapped, so
padding was the whole gutter. Content *narrowed* crossing 960 (863px to
768px) and stayed 152px behind Markets' content — which drops to 20px at
the same breakpoint — all the way to 1279, where the ladders finally met.
The header and footer visibly disagreed with the page they framed, then
snapped wider at 1280 while the content barely moved. md now matches at
20px, which also makes the ladder monotonic through that range.

Adds the xl step the ladder was missing, so the header tracks content past
1575 instead of staying pinned at 1240 while Markets reached 1440. The
96px gutter is only safe because maxWidth rises with it: 1632 - 2*96 still
leaves 1440 of content, so it grows 1383 to 1440 across 1575-1632 and holds,
meeting xxl exactly. Padding a capped box *without* lifting the cap is the
regression 53a4b3c fixed; the inline comment spells that out.

Content width now matches between header, footer and page at every
breakpoint, verified across 300-2600px. The 23px and 55px dips at 640 and
760 are left as-is per 53a4b3c — they move header and content together, so
they cause no mismatch.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

📦 Next.js Bundle Analysis for aave-ui

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 1.34 MB (🟡 +13.09 KB)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

Sixteen Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load
/ 91.53 KB (🟢 -4.48 KB) 1.42 MB
/404 2.08 KB (🟢 -776 B) 1.34 MB
/500 2.41 KB (🟢 -774 B) 1.34 MB
/bridge 36.68 KB (🟢 -1.06 KB) 1.37 MB
/dashboard 80.93 KB (🟢 -4.66 KB) 1.41 MB
/faucet 9.93 KB (🟢 -5.12 KB) 1.34 MB
/governance 42.19 KB (🟢 -770 B) 1.38 MB
/governance/ipfs-preview 100.03 KB (🟢 -1.62 KB) 1.43 MB
/governance/v3/proposal 86.01 KB (🟢 -2.78 KB) 1.42 MB
/history 31.54 KB (🟢 -4.8 KB) 1.37 MB
/markets 54.07 KB (🟢 -835 B) 1.39 MB
/reserve-overview 38.4 KB (🟢 -1.46 KB) 1.37 MB
/safety-module 54.78 KB (🟢 -1.66 KB) 1.39 MB
/sgho 91.65 KB (🟢 -1.34 KB) 1.42 MB
/staking 30.71 KB (🟢 -2.77 KB) 1.37 MB
/v3-migration 47.76 KB (🟢 -4.88 KB) 1.38 MB
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

- ListWrapper: drop the `collapseLabel` prop so the collapse toggle reads just
  "Hide" / "Show" instead of "Hide assets to borrow" and friends. Removes the
  prop from the four dashboard cards along with the now-unused `t` imports, and
  regenerates the lingui catalogs (six orphaned msgids dropped).
- Alerts: apply `data-size="small"` to SupplyAssetsList's three inline alerts and
  to WalletEmptyInfo, so the supply card matches the borrow card it sits beside
  and WalletEmptyInfo matches its six siblings on the reserve-overview panel.
- Cleanups: drop a redundant `xsm` breakpoint key from ListWrapper's `mt`,
  collapse a single-key responsive `mb` on the dashboard toggle group, and remove
  two Alert small-size declarations that now merely restate the base values.
  Refresh two comments the value changes had invalidated.
- Visual tuning: market-switcher version badge (new purple + weight), alert
  corner radius and icon size, transparent checkbox resting fill, `purple-2`
  hsl -> hex (same color), explicit AaveLogo dimensions, ContentContainer top
  padding, DelegatedInfoPanel button size.
MUI's ToggleButton hard-codes `border: 1px solid action.disabledBackground` on
.Mui-disabled, which outranked StyledToggleButton's base `border: 0`, outlining the
pill and defeating the group's borderless frame. Most segmented controls here
disable the active segment — the dashboard's Supply/Borrow switch, plus the order,
delegation, withdraw and repay type selectors and the voters list — so the selected
pill always carried it. That's the mismatch QA flagged against /dev/components,
whose first two demos never disable anything (its third one did reproduce it).
Re-assert border: 0 on both disabled selectors, which outrank MUI's on specificity.

Also move the two remaining hand-rolled toggle groups onto the shared control:

- TimeRangeSelector (reserve-overview + stkGHO charts) hardcoded 0.5px borders and
  a pre-v3 `0px 2px 1px rgba(...)` shadow on the selected segment. Keeps its 24px
  chart-header footprint.
- SwitchSlippageSelector's presets used a raw group whose `borderWidth: 2` thickened
  MUI's default segment border. The group had no `value`, so selection was faked
  per-button; pass the equivalent value and guard onChange, since a controlled
  exclusive group emits null when the active segment is clicked. Sized to the
  custom-slippage input beside it.

SwapAssetInput's % popover keeps its raw group — with no persistent selection the
shared control would render every option dimmed — but drops the stray border.
Both header overlays portal to <body>, so the `display` breakpoint gates on their
wrappers hide only the trigger. Open one, cross the mdlg breakpoint, and the overlay
floats on beside whatever nav replaced it:

- The mobile drawer stayed open next to the desktop nav. It now closes when mdlg
  goes false, and `open` is gated on mdlg as well so it can't paint for the frame
  before that effect commits.
- The settings dropdown hung detached from its hidden anchor on the way down to
  mobile. SettingsMenu is now unmounted below mdlg rather than CSS-hidden, which
  drops its portal along with anchorEl/settingsOpen/languagesOpen. Safe to JS-gate
  here, unlike MobileMenu, because useMediaQuery reports desktop during SSR —
  gating the hamburger that way would ship mobile HTML without it.

Collapse mobileMenuOpen into the store's mobileDrawerOpen so there is one flag
instead of two hand-synced ones. That split was the root of the original bug, and
it had already drifted elsewhere: the logo's onClick cleared only the local flag,
so TopBarNotify kept suppressing the campaign banner after the drawer had closed.

Drop walletWidgetOpen — setWalletWidgetOpen(true) is never called anywhere, so the
effect branch and the render guard on it were both dead.
Top-nav active underline
- navLinkSx drew the bar with `width: 100%`, which resolves against the button's
  padding box, so it overhung the label by the 0.8125rem of side padding. Inset it
  by the horizontal padding instead, and split the padding argument into Y/X so the
  bar derives from the same value that sets the padding. The Staking trigger pulls
  its right inset in further to clear the chevron.
- Share the nav padding as NAV_LINK_PADDING_Y/X rather than repeating the literals.

Switch <-> label gap
- The MuiFormControlLabel rule set `marginLeft` on the label, which only lands
  between the two for labelPlacement="end". With "start" the row reverses, so the
  margin went to the label's outer edge and the switch sat flush against the text —
  the bridge modal's "Use connected account". Use `gap` on the flex container, which
  is direction-agnostic. Measured 0.5rem for both placements afterwards.
- MarketSwitcher's own `gap: '1rem'` is dead once the theme sets gap, so drop it.
  The legacy-markets switch tightens 16px -> 8px to match every other switch.

Inline alert buttons
- MuiButton size variants pin a fixed height (36px/28px) and ButtonBase aligns
  middle, so an inline text button inside an Alert inflated the line box and
  double-spaced wrapped text. Reset height/vertical-align in the Alert scope: an
  alert message with an inline button drops from 60.4px to 3 clean 16.2px lines.
- ChangeNetworkWarning spread `{...rest}` after `sx`, so a caller's sx replaced its
  styling wholesale. Merge instead, and collapse the doubled 'info' severity branch.

Modal dropdowns
- Bridge modal had no space under its header: it rolls its own title row instead of
  TxModalTitle, so it never got the mb: 6 every other modal has.
- Swap network + expiry selectors and the bridge fee token selector move from Select
  to a text-button trigger + Menu, per spec: 1.125rem icon, 0.38rem, 0.75rem/500/120%
  label, 0.25rem, then the existing 12px fg-3 ChevronDownIcon. This drops a block of
  hardcoded pre-v3 colors (#292E41, #383D51, #EAEBEF) the old Select carried.
The APY cell stacked its rate above its badges in every table. Three separate
components owned that layout, so each needed its own fix:

- IncentivesCard rendered two nested columns — one row for the incentive icons,
  rate and tooltip, and a second row beneath for the points/airdrop badges. Collapse
  both branches into one wrapping row. That also folds away the `inlineIncentives`
  branch, which was a near-duplicate: the two now differ only in justification, and
  `align` drives justifyContent since the axis flipped. Covers markets, migration
  and (via ListAPRColumn) the dashboard lists.
- ListAPRColumn set `display: 'flex column'`, which isn't valid CSS — `display`
  takes one keyword, so it was dropped and the Box fell back to block, stacking the
  card above its tooltip. Use the same horizontal Stack ListGhoAPRColumn already had.
- StakingApyItem hard-coded `direction={isMobile ? 'row' : 'column'}`, so the
  staking table was a column by design. Always row; mobile already was, which left
  `isMobile` dead, so drop it and the one call site passing it.

Verified before/after on the markets table: the points badge moves from a second
line onto the rate's row. The dashboard and staking tables need a connected wallet,
so those are unverified visually.
Tables, first pass:

- ListColumn defaults to `align: 'left'`, and the 32 call sites that passed align
  explicitly (17 left, 8 right, 7 center) drop the prop so every column follows the
  new default. The prop stays for columns that later need to opt out.
- ListItem and ListHeaderWrapper get `gap: '1rem'`, so columns sit at least 1rem
  apart. Measured 16px between all six columns on both header and body rows.
- ListHeaderTitle takes the new header type: fg-3, 0.6875rem, 500, 120%,
  0.00313rem tracking, uppercase, 'cv11'. Measured against the spec — 11px /
  500 / 13.2px / 0.05008px / uppercase / "cv11" / Inter.

Header truncation and nested type:

- `noWrap` was inert here: it emits `text-overflow: ellipsis`, which does nothing
  on the `display: inline-flex` root, so long labels overran into the next column.
  Move truncation to an inner span and let the root shrink. Squeezing a column
  203px -> 90px now truncates (span scroll 162px vs client 70px) and the header
  stays inside its column instead of overlapping its neighbour.
- Header titles are often a tooltip component rendering its own Typography with
  `variant="subheader2"`, which beat the header type — 12px next to 11px siblings.
  Force nested Typography to inherit. Reproduced on the markets table with the rule
  removed ("Borrow APY, variable" at 12px) and confirmed fixed with it in place.
  Same pattern affected BorrowAssetsList, SuppliedPositionsList and UmbrellaAssetsList.

Settings menu:

- "Select language" moves off `variant="h3"` to fg-1 / 0.875rem / 400 / 100%, and
  its back chevron drops 24px -> 20px to match the `Language / English` row it
  mirrors. Font family is left to inherit: the app declares 'Inter' / 'Inter var',
  so a literal "Inter Variable" would match nothing and fall back to the default sans.
The staking table's Available to stake and Available to claim cells hard-coded
`direction={isMobile ? 'row' : 'column'}`, so desktop was a column by design —
amount above its reward icons. Always row; mobile already was, which left the
`isMobile` prop dead in both, so drop it and the call sites passing it.

AmountStakedUnderlyingItem carried the same ternary. Its Stack wraps a single
child, so direction never had any effect there — dead conditional plus a dead
prop rather than a layout change. Removing it leaves no `isMobile ? 'row' :
'column'` anywhere, matching StakingApyItem which was flattened earlier.

Also carries in-flight edits from elsewhere in the tree: the theme's
`palette.divider` moves border-2 -> border-0, ProposalsV3List follows suit, the
two umbrella list containers hide ListMobileItem's leading divider, and small
call-site tweaks to ReadOnlyModal, GasStation, DashboardEModeButton and
SwapAssetInput.
Bumps the market switcher's Popover paper from 32.5rem to 34rem.
Card headers (ListWrapper) become a distinct band: bg-2 fill, a full-bleed bottom
hairline as an inset shadow, and 1rem/1.25rem padding (0.875rem/1rem on mobile,
matching what it was). The title row carries the H4 type, with heading variants
neutralised so consumers' own h2/h3 inherit — scoped to that row only, since the
second row needs its own type.

- topInfo moves up into the band as a second row, separated by a rule drawn as
  that row's own border-top plus `:empty` — so a row with nothing in it takes the
  rule with it ("Your borrows" with nothing borrowed). Documented on the prop,
  since it depends on topInfo rendering no DOM rather than an empty wrapper.
- ListTopInfoItem now wraps PageHeaderStat, so the Balance/APY/Collateral stats
  match the page header exactly: label over value, fg-3 0.875rem/400/100%, value
  h2 (1.5rem/500/120%) dropping to h4 below sm. Tooltips render beside the label,
  following DashboardTopPanel's own pattern.
- subChildrenComponent (the "Show assets with 0 balance" filters) renders below
  the card instead of inside it.
- Dashboard cards sit 2rem apart on both axes; column header padding is 12.5px.
- Drop the dead topInfoSx prop — no consumer among the 13 call sites.

Reserve overview: chart lines resolve from the data tokens via pickFigma rather
than hardcoded #2EBAC6/#B6509E (the visx stroke needs a literal, not a CSS var),
and the borrow ring takes a fixed data-orange via a new CapsCircularStatus
`color` override, so ring and chart match per section. data-green and data-orange
are retuned in both modes.

Also: outlined buttons and Select triggers fill bg-3 in light (bg-4 in dark) via
darkScheme; governance's right-column cards space via a container gap of 16px
rather than each panel's own top margin; the staking table's "Available to
Stake/Claim" headers shorten to "Av. to"; and the borrow modal's parameter-change
alert moves off raw <b>/<a> onto the alert's own 500 weight and a Link, at the
small size variant.

Carries in-flight edits from elsewhere in the tree: the bg-* ramp renumbering in
figmaColors, MarketSwitcher, SGhoCard, StkGhoCard, TxActionsWrapper,
DelegationTxsWrapper, DashboardListTopPanel, StakingPanel and the showcase catalog.

Note: MarketSwitcher sets variant="base", which is not a declared Typography
variant, so `next build` typechecking fails on it.
MarketSwitcher's market blurb passes variant="base", but no such variant existed,
so `next build` failed its typecheck and CI went red on fa3df91.

"Base" is a real style in the design system — 0.875rem / 400 / 100% — so declare
it rather than swapping the call site to the nearest existing variant. MUI needs
it in four places: the TypographyCustomVariants interface, the
TypographyPropsVariantOverrides map so the prop typechecks, the style itself, and
variantMapping -> 'p' alongside the other body variants.

Also collapses the one place that had hand-rolled the same style: the settings
menu's "Select language" row was carrying it as an inline sx, written before the
variant existed.

Verified with `next build` (exit 0).
Brings in 13 commits, including the gasless-voting move from gelato to the
governance vote-relay, the Celo wrapper, the Merkl/Mantle/Plasma icon mappings,
the Polygon v3 incentive disable, and the high-severity transitive dep patches.

Seven files conflicted; all trace to #3089 (replace the V4 announcement banner
with a permanent header button) and #3087 (Avalanche V4 link).

MainLayout.tsx — took origin/main. It deletes the whole getCampaignConfigs
banner block; this branch had only retitled "Try it out here" to "Try it out"
inside configs that no longer exist. TopBarNotify stays mounted with an empty
config, so the /dev/components banner specimen still works.

AppHeader.tsx — took this branch's body and grafted main's V4 button. Main
added exactly 20 lines here; the other 116 in the conflict were unmodified base
content this branch had already rewritten, which is why git misaligned the
block. The button is restyled to match the redesigned header (variant
"outlined", buttonM label, 0.62rem trailing margin) rather than pasted as-is,
which would not have compiled: it read `smd`, a breakpoint this file no longer
defines. It stays visible at every width and abbreviates to "V4" below lg,
because neither MobileMenu nor NavItems carries a V4 entry point and main
removed the banner that previously served mobile.

MarketSwitcher.tsx — merged both refactors instead of picking one. The merge
base had a hardcoded Aave Pro row; this branch had extracted it into a general
renderLinkRow (also used by the V2 Markets legacy row), while main extracted it
into a V4_LINKS config plus renderV4Link and added Avalanche. renderLinkRow
stays and gains optional id/onSelect, and renderV4Link becomes a thin adapter
over it carrying main's trackEvent and data-cy. Sections render v4Ethereum and
v4Other through this branch's renderSection, dropping main's Divider and px
layout. The V4 badge markup now exists once rather than twice.

Consequences worth noting: an Avalanche V4 row now renders under L1 Networks,
where the V3 Avalanche market already sits, so that section shows two rows
labelled "Avalanche" distinguished only by the V4 pill and external-link arrow.
V4 row labels are plain strings in V4_LINKS, so "Aave Pro" is no longer
translatable and its msgid is gone from the catalogs.

The four compiled locale bundles were regenerated with pnpm i18n rather than
hand-merged; their .po sources merged cleanly.

Verified: tsc --noEmit clean; eslint 0 errors, with one exhaustive-deps warning
in MarketSwitcher confirmed pre-existing on origin/main. Lockfile parses and its
patchedDependencies match package.json with both patch files present, though
pnpm install has not been run. Not verified visually — no dev server for this
workspace was running.
@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

📦 Next.js Bundle Analysis for aave-ui

This analysis was generated by the Next.js Bundle Analysis action. 🤖

This PR introduced no changes to the JavaScript bundle! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant