-
Notifications
You must be signed in to change notification settings - Fork 14
Lite - Improve layout stability, bundle size, and UX on dashboard #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@fscgustavo is attempting to deploy a commit to the Morpho Association Team on Vercel. A member of the Team first needs to authorize it. |
e88a87c to
7a10e91
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Saving 1.7KB by using https://vecta.io/nano
| </SafeLinksProvider> | ||
| <AddressScreeningModal /> | ||
| </AddressScreeningProvider> | ||
| <TooltipProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following Radix UI best practices, wrapping the entire application in a single is efficient because it allows all tooltip components to share a common configuration (like delay duration). This avoids redundant provider instances, keeps the component tree cleaner and with less code to compile.
https://www.radix-ui.com/primitives/docs/components/tooltip#provider
If a specific tooltip ever needs unique timing or behavior, we can still nest a separate provider locally for that case, but the global one handles the default case for the whole app.
| defaultValue={userMarkets.length > 0 ? "user-positions" : "markets"} | ||
| className="w-full max-w-7xl px-2 lg:px-8" | ||
| > | ||
| <TabsList className="grid grid-cols-2 p-0"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we are matching the strategy used on the main Morpho app. By placing the static Call-to-Action (CTA) cards at the top, we ensure immediate visual feedback for the user without blocking the render. The data-heavy, asynchronous content (tables for user positions and markets) is moved to the bottom within Tabs. This separation allows the core interface to load instantly while heavier data fetches happen in the background, significantly improving perceived performance and eliminating the layout shift that would occur if dynamic content pushed the static elements down after loading.
| }} | ||
| /> | ||
| </div> | ||
| <BoxTopRoundedCorners> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BoxTopRoundedCorners to standardize the layout structure and avoid repetition
| <Table className="border-separate border-spacing-y-3"> | ||
| <TableHeader className="bg-primary"> | ||
| <TableRow className="text-xs font-light"> | ||
| <TableHead className="text-secondary-foreground w-[30%] min-w-[18rem] rounded-l-lg pl-4">Vault</TableHead> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We applied explicit width percentages and minimum width constraints (e.g., w-[23%] min-w-[13rem]) to the table headers. By strictly defining the column geometry upfront, we prevent the browser from auto-calculating widths based on content length. This ensures the table structure remains completely stable regardless of the data loaded, effectively eliminating the layout shift
(CLS) that typically occurs when dynamic content populates the cells.
| })} | ||
| </TableBody> | ||
| </Table> | ||
| {selectedRow && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored the table to use a single instance that wraps the entire table, rather than rendering a separate Sheet component for every single row. The rows now act as SheetTriggers that simply update the selectedMarket state. This reduces the number of React component instances, leading to a lighter DOM and less code to compile.
Additionally, the EarnSheetContent is now imported via lazy() loading. This ensures that the heavy logic and dependencies required for the sheet (transaction forms, detailed market data) are only fetched and parsed when the user actually opens a position
| url: "https://www.cicada.partners/", | ||
| imageSrc: | ||
| "https://static.wixstatic.com/media/f9d184_1702c7c11ec647f480ad8e0c8c4859c3~mv2.png/v1/fill/w_120,h_155,al_c,lg_1,q_85,enc_avif,quality_auto/Cicada%20Image_Black%20on%20White_25%25.png", | ||
| "https://static.wixstatic.com/media/f9d184_1702c7c11ec647f480ad8e0c8c4859c3~mv2.png/v1/fill/w_16,h_16,al_c,lg_1,q_85,enc_avif,quality_auto/Cicada%20Image_Black%20on%20White_25%25.png", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.

This PR introduces performance and user experience improvements to the dashboard, focusing on reducing layout shifts, optimizing bundle size, and speeding up perceived load times.
🚀 Performance & UX Improvements
Adopted the same structural strategy as the main Morpho app (e.g., morpho.org/ethereum/earn). Static content (CTA cards) is now displayed immediately at the top, while asynchronous/heavy content (tables) is loaded in the
Tabssection below.Benefit: Provides immediate visual feedback to the user and removes perceived latency.
Benefit: Eliminates Layout Shift: Static content no longer "jumps" when dynamic data loads.
Fixed Column Sizing: Applied explicit width percentages and minimum constraints to table headers in
borrow-table.tsx.Efficient Sheet Rendering: Refactored the Borrow/Earn tables to use a single
<Sheet>instance shared across all rows, rather than rendering a separate Sheet for every row.CSS Optimization: Extracted and reused common CSS utility classes for
CtaCardcomponents, reducing duplication.Code Splitting & Lazy Loading:
BorrowSheetContentandEarnSheetContentso its dependencies are only fetched when a user actually interacts with the sheet.📊 Metrics
Previous Lighthouse Score:
Current Lighthouse Score (built version of branch):
Visual Comparison:
Borrow (before)
Screen.Recording.2025-11-20.at.00.01.14.mov
Borrow (after)
Screen.Recording.2025-11-20.at.00.21.09.mov
Earn (before)
Screen.Recording.2025-11-20.at.00.23.08.mov
Earn (after)
Screen.Recording.2025-11-20.at.00.17.11.mov
📝 Notes on Image Optimization
If I had direct access to the infrastructure, further optimizations could be made:
Cache-ControlTTL for assets oncdn.morpho.org(likeearn-animation.webm) to reduce repeated downloads for returning users.cdn.morpho.orgsupports on-the-fly resizing via query params (e.g.,?width=16), please let me know so I can update thecurator.tsfile to use them instead of uploading new files.