Match list skeletons to the card surface
ListItemSkeleton reused a sand-2 fill that read as a different card; use the real row shell with pulse bars instead, and shrink the updates skeleton to five rows. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -27,7 +27,10 @@ import { HeaderBand } from "#/components/HeaderBand/HeaderBand";
|
|||||||
import { pageHeader } from "#/components/PageHeader/variants";
|
import { pageHeader } from "#/components/PageHeader/variants";
|
||||||
|
|
||||||
import { updatesList } from "./_components/variants";
|
import { updatesList } from "./_components/variants";
|
||||||
import { UPDATES_PAGE_SIZE } from "./_lib/constants";
|
|
||||||
|
// Placeholder rows for the loading card — enough to read as a list, far fewer
|
||||||
|
// than UPDATES_PAGE_SIZE so the skeleton does not dominate the viewport.
|
||||||
|
const UPDATES_SKELETON_COUNT = 5;
|
||||||
|
|
||||||
export function UpdatesPageSkeleton() {
|
export function UpdatesPageSkeleton() {
|
||||||
const { card, rows } = updatesList();
|
const { card, rows } = updatesList();
|
||||||
@@ -47,7 +50,7 @@ export function UpdatesPageSkeleton() {
|
|||||||
<div className="flex w-full max-w-5xl flex-col gap-8">
|
<div className="flex w-full max-w-5xl flex-col gap-8">
|
||||||
<div className={card()} aria-hidden>
|
<div className={card()} aria-hidden>
|
||||||
<div className={rows()}>
|
<div className={rows()}>
|
||||||
{Array.from({ length: UPDATES_PAGE_SIZE }, (_, index) => (
|
{Array.from({ length: UPDATES_SKELETON_COUNT }, (_, index) => (
|
||||||
<ComplianceArticleItemSkeleton key={index} />
|
<ComplianceArticleItemSkeleton key={index} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const dialog = tv({
|
|||||||
],
|
],
|
||||||
popup: [
|
popup: [
|
||||||
"fixed left-1/2 top-1/2 z-5 -translate-x-1/2 -translate-y-1/2",
|
"fixed left-1/2 top-1/2 z-5 -translate-x-1/2 -translate-y-1/2",
|
||||||
"flex w-[calc(100vw-2rem)] max-w-[600px] flex-col gap-4",
|
"flex w-[calc(100vw-2rem)] max-w-150 flex-col gap-4",
|
||||||
"max-h-[calc(100vh-2rem)] overflow-y-auto overflow-x-clip",
|
"max-h-[calc(100vh-2rem)] overflow-y-auto overflow-x-clip",
|
||||||
"rounded-5 border border-sand-6 bg-sand-1 py-6 shadow-6 outline-none",
|
"rounded-5 border border-sand-6 bg-sand-1 py-6 shadow-6 outline-none",
|
||||||
"transition-all duration-150",
|
"transition-all duration-150",
|
||||||
@@ -51,7 +51,7 @@ export const dialog = tv({
|
|||||||
// so a placeholder can render before Base UI (and the content) loads.
|
// so a placeholder can render before Base UI (and the content) loads.
|
||||||
export const dialogSkeleton = tv({
|
export const dialogSkeleton = tv({
|
||||||
base: [
|
base: [
|
||||||
"flex w-full max-w-[600px] flex-col gap-4",
|
"flex w-full max-w-150 flex-col gap-4",
|
||||||
"rounded-5 border border-sand-6 bg-sand-1 py-6 shadow-6",
|
"rounded-5 border border-sand-6 bg-sand-1 py-6 shadow-6",
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,15 +20,24 @@
|
|||||||
|
|
||||||
import type { ComponentProps } from "react";
|
import type { ComponentProps } from "react";
|
||||||
|
|
||||||
|
import { TextSkeleton } from "../typography/TextSkeleton";
|
||||||
|
|
||||||
import { list } from "./variants";
|
import { list } from "./variants";
|
||||||
|
|
||||||
export type ListItemSkeletonProps = Omit<ComponentProps<"li">, "children">;
|
export type ListItemSkeletonProps = Omit<ComponentProps<"li">, "children">;
|
||||||
|
|
||||||
// Loading placeholder paired with ListItem: a pulse bar that keeps the row
|
// Loading placeholder paired with ListItem: same row shell (card background +
|
||||||
// dividers of a List.
|
// dividers) with pulse bars for the primary column — not a filled sand-2 slab.
|
||||||
export function ListItemSkeleton(props: ListItemSkeletonProps) {
|
export function ListItemSkeleton(props: ListItemSkeletonProps) {
|
||||||
const { className, ...rest } = props;
|
const { className, ...rest } = props;
|
||||||
const { skeletonItem } = list();
|
const { item, content } = list();
|
||||||
|
|
||||||
return <li className={skeletonItem({ className })} aria-hidden {...rest} />;
|
return (
|
||||||
|
<li className={item({ className })} aria-hidden {...rest}>
|
||||||
|
<div className={content()}>
|
||||||
|
<TextSkeleton size={2} className="w-40" />
|
||||||
|
<TextSkeleton size={1} className="w-24" />
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,5 @@ export const list = tv({
|
|||||||
root: "list-none overflow-hidden rounded-4 border border-sand-a3 bg-sand-1",
|
root: "list-none overflow-hidden rounded-4 border border-sand-a3 bg-sand-1",
|
||||||
item: "flex items-center gap-4 border-b border-sand-a3 px-4 py-3 last:border-b-0",
|
item: "flex items-center gap-4 border-b border-sand-a3 px-4 py-3 last:border-b-0",
|
||||||
content: "flex min-w-0 flex-1 flex-col gap-0.5",
|
content: "flex min-w-0 flex-1 flex-col gap-0.5",
|
||||||
skeletonItem: "h-16 animate-pulse border-b border-sand-a3 bg-sand-2 last:border-b-0",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user