feat(plex): the person page in two columns; a bio on its way holds its place (E30 S6)
The biography sat at reading width in the left half of a full-width panel with nothing on the right. Now the person (headshot, facts, the bio clamped to eight lines with More / Less when it is cut) is on the left and "Known for" on the right; with fewer than four titles the rail takes only its posters' width. One column where the panel is narrow (200% zoom, the largest text size). While the server fetches a bio (`enriching`), the page shows a paragraph skeleton (a new "text" shape of LoadingState) and asks again every 1.5 s for up to 20 s. The view is keyed by the person's name, so another person starts fresh.
This commit is contained in:
@@ -3,7 +3,8 @@ import { SURFACE } from "./surfaces";
|
||||
|
||||
// B8 (docs/DESIGN.md): a first load of a grid, list or table shows the SHAPE of what is coming, so
|
||||
// nothing jumps when the data lands. One block primitive (a tonal fill, the Badge's 8% of the text
|
||||
// colour, pulsing unless the user asked for less motion) and the four page shapes built from it. The
|
||||
// colour, pulsing unless the user asked for less motion) and the page shapes built from it (plus a
|
||||
// paragraph's, for prose that arrives after its page). The
|
||||
// shapes are shown through `LoadingState shape=…`, which owns the 300 ms reveal and the status role.
|
||||
|
||||
export function Skeleton({ className }: { className?: string }) {
|
||||
@@ -15,9 +16,9 @@ export function Skeleton({ className }: { className?: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
export type SkeletonShape = "grid" | "poster" | "list" | "table";
|
||||
export type SkeletonShape = "grid" | "poster" | "list" | "table" | "text";
|
||||
|
||||
const COUNT: Record<SkeletonShape, number> = { grid: 8, poster: 12, list: 6, table: 8 };
|
||||
const COUNT: Record<SkeletonShape, number> = { grid: 8, poster: 12, list: 6, table: 8, text: 5 };
|
||||
|
||||
/** The placeholder for a page's first load, by the shape of its content. */
|
||||
export function SkeletonShapes({ shape }: { shape: SkeletonShape }) {
|
||||
@@ -46,6 +47,15 @@ export function SkeletonShapes({ shape }: { shape: SkeletonShape }) {
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
if (shape === "text")
|
||||
// A paragraph still on its way (a biography): lines at prose height, the last one short.
|
||||
return (
|
||||
<div className="measure flex w-full flex-col gap-2.5 py-1">
|
||||
{n.map((i) => (
|
||||
<Skeleton key={i} className={`h-3 ${i === n.length - 1 ? "w-2/5" : "w-full"}`} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
if (shape === "list")
|
||||
return (
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
|
||||
Reference in New Issue
Block a user