fix(design): an audit of the S3d claims — the float shadow, filter hints, one action size per row (E28 S3d)
- A glass role's shadow is one token (shadow-float); the header search's drop-shadow utility had replaced its top highlight, and the debug pill's shadow-lg did the same. The surface-role lint rule now refuses a shadow size beside a role. - Plex: every value that filters carries a hint (genre, certificate, studio had none), and the facts panel's year and certificate filter like the header's. filterKeyword -> filterValue. - Downloads: the row resized its buttons with a [&_button] override that the save link escaped (28px beside 32px); the size is the primitive's md rung now.
This commit is contained in:
@@ -170,11 +170,20 @@ const SURFACE_OWNERS = new Set([
|
||||
"fieldStyles.ts", // the header search floats over the page
|
||||
]);
|
||||
const GLASS_TIER = /^glass(-card|-menu)?$/;
|
||||
// A glass surface's depth is its own box-shadow, whose inset top highlight a `shadow-*` utility would
|
||||
// replace wholesale (the header search and the debug pill lost theirs). A shadow COLOUR only sets a
|
||||
// variable, and `shadow-float` IS the surface's shadow, so both pass.
|
||||
const SHADOW_SIZE = /^shadow-(xs|sm|md|lg|xl|2xl|\[.+\]|\(.+\))$/;
|
||||
const isShadowSize = (w) => SHADOW_SIZE.test(w.slice(w.lastIndexOf(":") + 1));
|
||||
const isSurfaceRole = (n) =>
|
||||
n?.type === "MemberExpression" && n.object.type === "Identifier" && n.object.name === "SURFACE";
|
||||
const surfaceRole = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
messages: {
|
||||
raw: "A bare `{{tier}}` class: use a role from ui/surfaces.ts (SURFACE.panel / drawer / card / menu / popover / tooltip), which brings the radius too.",
|
||||
shadow:
|
||||
"`{{shadow}}` on a glass surface replaces its own shadow and drops the top highlight; the role's depth is the intended one.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
@@ -191,6 +200,20 @@ const surfaceRole = {
|
||||
const tier = words.find((w) => GLASS_TIER.test(w));
|
||||
if (tier) context.report({ node, messageId: "raw", data: { tier } });
|
||||
};
|
||||
// A role plus a shadow size in one class list: `${SURFACE.x} shadow-lg` or clsx(SURFACE.x, "shadow-lg").
|
||||
const shadowBeside = (node, parts) => {
|
||||
if (!parts.some(isSurfaceRole)) return;
|
||||
for (const part of parts) {
|
||||
const text =
|
||||
part.type === "TemplateElement"
|
||||
? part.value.cooked
|
||||
: part.type === "Literal" && typeof part.value === "string"
|
||||
? part.value
|
||||
: "";
|
||||
const shadow = text.split(/\s+/).find(isShadowSize);
|
||||
if (shadow) context.report({ node, messageId: "shadow", data: { shadow } });
|
||||
}
|
||||
};
|
||||
return {
|
||||
Literal(node) {
|
||||
check(node, node.value);
|
||||
@@ -198,6 +221,12 @@ const surfaceRole = {
|
||||
TemplateElement(node) {
|
||||
check(node, node.value.cooked);
|
||||
},
|
||||
TemplateLiteral(node) {
|
||||
shadowBeside(node, [...node.quasis, ...node.expressions]);
|
||||
},
|
||||
CallExpression(node) {
|
||||
shadowBeside(node, node.arguments);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user