Match Rule card type and section gaps to the template grid.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilallo
2026-08-18 20:56:02 -06:00
co-authored by Cursor
parent b6cf980d23
commit 73cb73a5af
4 changed files with 59 additions and 22 deletions
+16 -12
View File
@@ -108,10 +108,11 @@ export function RuleView({
const showRecommendedTag = recommended && !expanded; const showRecommendedTag = recommended && !expanded;
const titleClass = templateGridFigmaShell const titleClass = templateGridFigmaShell
? ` ? `
max-[639px]:text-x-small-heading font-bricolage-grotesque
min-[640px]:max-[1023px]:font-bricolage-grotesque min-[640px]:max-[1023px]:text-medium-heading max-[639px]:text-small-heading
min-[1024px]:max-[1439px]:font-bricolage-grotesque min-[1024px]:max-[1439px]:text-x-large-heading min-[640px]:max-[767px]:text-x-large-heading
min-[1440px]:font-bricolage-grotesque min-[1440px]:text-x-large-heading min-[768px]:max-[1023px]:text-small-heading
min-[1024px]:text-x-large-heading
` `
: ` : `
max-[639px]:text-x-small-heading max-[639px]:text-x-small-heading
@@ -120,15 +121,18 @@ export function RuleView({
min-[1440px]:font-bricolage-grotesque min-[1440px]:text-x-large-heading min-[1440px]:font-bricolage-grotesque min-[1440px]:text-x-large-heading
`; `;
const descriptionClass = isLarge const descriptionClass = templateGridFigmaShell
? `
max-[639px]:text-small-label max-[639px]:leading-[18px]
min-[640px]:max-[767px]:text-large-label
min-[768px]:max-[1023px]:text-small-label min-[768px]:max-[1023px]:leading-[18px]
min-[1024px]:text-large-label
`
: isLarge
? "text-large-label" ? "text-large-label"
: isMedium : isExtraSmall
? templateGridFigmaShell ? "text-x-small-label"
? "text-small-label min-[1024px]:max-[1439px]:text-large-label" : "text-small-label";
: "text-small-label"
: isSmall
? "text-small-label" // S: 14px, medium, Inter
: "text-x-small-label"; // XS: 12px, medium, Inter
const headerIconCellClass = templateGridFigmaShell const headerIconCellClass = templateGridFigmaShell
? ` ? `
@@ -27,7 +27,7 @@ export function RuleStackView({
min-[1024px]:px-[64px] min-[1024px]:py-[64px] min-[1024px]:px-[64px] min-[1024px]:py-[64px]
min-[1440px]:px-[96px] min-[1440px]:px-[96px]
gap-[24px] gap-[24px]
min-[640px]:gap-[32px] min-[768px]:gap-[32px]
min-[1024px]:gap-[40px] min-[1024px]:gap-[40px]
${className} ${className}
`} `}
@@ -53,14 +53,7 @@ export function RuleStackView({
/> />
)} )}
<div <div className="flex w-full justify-center">
className="
flex justify-center w-full
max-[767px]:mt-[var(--measures-spacing-600,24px)]
min-[768px]:max-[1023px]:mt-[var(--measures-spacing-800,32px)]
min-[1024px]:mt-[var(--measures-spacing-1000,40px)]
"
>
<Button <Button
buttonType="outline" buttonType="outline"
palette="default" palette="default"
+35
View File
@@ -195,6 +195,41 @@ describe("Rule Component", () => {
expect(heading?.className).toMatch(/min-\[1440px\]:text-x-large-heading/); expect(heading?.className).toMatch(/min-\[1440px\]:text-x-large-heading/);
}); });
it("applies template-grid title and description type scales", () => {
render(
<Rule
{...defaultProps}
templateGridFigmaShell
description="Important decisions require unanimous agreement."
/>,
);
const heading = screen.getByRole("heading", { level: 3 });
expect(heading).toHaveClass("font-bricolage-grotesque");
expect(heading.className).toMatch(/max-\[639px\]:text-small-heading/);
expect(heading.className).toMatch(
/min-\[640px\]:max-\[767px\]:text-x-large-heading/,
);
expect(heading.className).toMatch(
/min-\[768px\]:max-\[1023px\]:text-small-heading/,
);
expect(heading.className).toMatch(/min-\[1024px\]:text-x-large-heading/);
expect(heading.className).not.toMatch(/text-x-small-heading/);
const description = screen.getByText(
"Important decisions require unanimous agreement.",
);
expect(description.className).toMatch(/max-\[639px\]:text-small-label/);
expect(description.className).toMatch(
/min-\[640px\]:max-\[767px\]:text-large-label/,
);
expect(description.className).toMatch(
/min-\[768px\]:max-\[1023px\]:text-small-label/,
);
expect(description.className).toMatch(/min-\[1024px\]:text-large-label/);
expect(description.className).not.toMatch(/text-x-small-label/);
});
it("renders expanded state with categories", () => { it("renders expanded state with categories", () => {
const categories = [ const categories = [
{ {
+5
View File
@@ -188,6 +188,10 @@ describe("RuleStack Component", () => {
expect(section).toHaveClass("px-[20px]", "py-[32px]"); expect(section).toHaveClass("px-[20px]", "py-[32px]");
expect(section?.className).toMatch(/min-\[640px\]:px-\[32px\]/); expect(section?.className).toMatch(/min-\[640px\]:px-\[32px\]/);
expect(section?.className).toMatch(/min-\[640px\]:py-\[48px\]/); expect(section?.className).toMatch(/min-\[640px\]:py-\[48px\]/);
expect(section?.className).toMatch(/gap-\[24px\]/);
expect(section?.className).toMatch(/min-\[768px\]:gap-\[32px\]/);
expect(section?.className).toMatch(/min-\[1024px\]:gap-\[40px\]/);
expect(section?.className).not.toMatch(/min-\[640px\]:gap-\[32px\]/);
}); });
test("applies responsive grid layout", async () => { test("applies responsive grid layout", async () => {
@@ -338,6 +342,7 @@ describe("RuleStack Component", () => {
.getByRole("link", { name: "See all templates" }) .getByRole("link", { name: "See all templates" })
.closest("div"); .closest("div");
expect(linkContainer).toHaveClass("flex", "justify-center"); expect(linkContainer).toHaveClass("flex", "justify-center");
expect(linkContainer?.className).not.toMatch(/mt-\[/);
}); });
test("falls back to static catalog when templates API errors", async () => { test("falls back to static catalog when templates API errors", async () => {