ListPage
SourceCreate link, skeleton, empty, and error rows for lists.
Overview
One idiom for the console's list pages, so an operator moving between them reads the same shape every time.
The table is always rendered. Loading, empty, and error are body states, not page states, so the thead stays on screen through all four and nothing jumps when the data lands.
The create action is a solid pill in the PageHeader right slot. It looks like a button and is a link, because navigation is the whole action.
Create link
The header-slot action. A 36px pill, the wizards' primary weight scaled to sit on a title baseline.
Strategies
Per-collateral risk parameters and the positions they govern.
import { ListCreateLink } from "@clear-labs/lens/next/list-page";
import { PageHeader } from "@clear-labs/lens/next/page-header";
<PageHeader
title="Strategies"
right={
<ListCreateLink href="/ez/strategies/new" testId="strategies-new-link">
+ New strategy
</ListCreateLink>
}
/>Loading
Rows by columns of pulsing cells under the real thead. Widths cycle through three fixed steps rather than guessing the data's shape.
| Asset | Debt ceiling | Max LTV | Positions |
|---|---|---|---|
<table>
<thead>{/* the real header, in every state */}</thead>
<tbody>
<ListSkeletonRows columns={4} testId="strategies-loading" />
</tbody>
</table>Empty
One full-width row: the headline says what is true, the hint says why that is fine, and the primary action gets full weight. The secondary link is optional and demoted.
| Asset | Debt ceiling | Max LTV | Positions |
|---|---|---|---|
No strategies registered on chain. Zero add_strategy calls have landed on this cluster. That is chain truth, not a loading artifact. Add the first strategyOpen the generic wizard instead | |||
<ListEmptyRow
columns={4}
headline="No strategies registered on chain."
hint="Zero add_strategy calls have landed on this cluster."
cta={{
href: "/ez/strategies/new",
label: "Add the first strategy",
testId: "strategies-empty-add-link",
}}
secondaryCta={{
href: "/ez/feeds/new",
label: "Open the generic wizard instead",
testId: "feeds-empty-wizard-link",
}}
testId="strategies-empty"
/>Error
Tinted fill, no border, and the message verbatim. An operator debugging a failed read needs the real string.
| Asset | Debt ceiling | Max LTV | Positions |
|---|---|---|---|
RPC 429: too many requests. Retry in 12s. | |||
<ListErrorRow
columns={4}
message={error.message}
testId="strategies-error"
/>ListCreateLink props
ListSkeletonRows props
ListEmptyRow props
The colspan. Match the thead.
What is true. Chain truth, stated plainly.
Why that is not an error.
The primary action at full weight: a 48px pill.
A demoted text link under the pill. Never a second button.
data-testid on the centred block.