From b012c73e65cd481d3dd556d359c4d224dab23353 Mon Sep 17 00:00:00 2001 From: adilallo <39313955+adilallo@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:58:15 -0700 Subject: [PATCH] Update Rule Stack component and tests --- app/components/RuleCard/RuleCard.view.tsx | 120 ++++++----- app/components/RuleStack/RuleStack.view.tsx | 208 ++++++++++++++------ messages/en/pages/home.json | 3 + tests/pages/user-journey.test.jsx | 3 +- tests/unit/RuleCard.test.jsx | 4 +- tests/unit/RuleStack.test.jsx | 36 ++-- 6 files changed, 245 insertions(+), 129 deletions(-) diff --git a/app/components/RuleCard/RuleCard.view.tsx b/app/components/RuleCard/RuleCard.view.tsx index 4e637e9..bdd2625 100644 --- a/app/components/RuleCard/RuleCard.view.tsx +++ b/app/components/RuleCard/RuleCard.view.tsx @@ -29,15 +29,22 @@ export function RuleCardView({ const isSmall = size === "S"; const isExtraSmall = size === "XS"; - // Card dimensions - fixed width for expanded states (568px for L, 398px for M per Figma) - // XS and S don't have fixed widths when expanded - const cardPadding = isLarge || isSmall + // Card dimensions - use CSS classes from className if provided, otherwise use size-based logic + // Check if className already has padding/gap classes + const hasResponsivePadding = className?.includes("p-[") || className?.includes("px-[") || className?.includes("py-[") || className?.includes("pt-[") || className?.includes("pb-["); + const hasResponsiveGap = className?.includes("gap-["); + + const cardPadding = hasResponsivePadding + ? "" // If className has responsive padding, don't add size-based padding + : isLarge || isSmall ? "p-[24px]" : isMedium ? "p-[16px]" : "pb-[24px] pt-[12px] px-[12px]"; // XS: asymmetric padding const cardGap = expanded ? "gap-[16px]" + : hasResponsiveGap + ? "" // If className has responsive gap, don't add size-based gap : isLarge ? "gap-[10px]" : isMedium @@ -51,32 +58,24 @@ export function RuleCardView({ : "" // XS and S: no fixed width : ""; - // Logo/Icon dimensions + // Logo/Icon dimensions - use CSS responsive classes // For S: 80px container with 12px padding = 56px icon area - // For XS: 40px container with 16px padding = 8px icon area (very small, but matches Figma) - const logoSize = isLarge - ? 103 - : isMedium - ? 56 - : isSmall - ? 56 // S: 80px container - 12px padding * 2 = 56px icon - : 8; // XS: 40px container - 16px padding * 2 = 8px icon - const logoContainerClass = isLarge - ? "size-[103px]" - : isMedium - ? "size-[56px]" - : isSmall - ? "size-[80px]" // S: 80px container - : "size-[40px]"; // XS: 40px container + // For XS: 72px container with 16px padding = 40px icon (72 - 16*2 = 40px) + const logoSize = 103; // Use max size, CSS will resize + const logoContainerClass = ` + max-[639px]:size-[72px] + min-[640px]:max-[1023px]:size-[80px] + min-[1024px]:max-[1439px]:size-[56px] + min-[1440px]:size-[103px] + `; - // Title typography - const titleClass = isLarge - ? "font-bricolage-grotesque font-extrabold text-[36px] leading-[44px]" - : isMedium - ? "font-bricolage-grotesque font-bold text-[24px] leading-[32px]" - : isSmall - ? "font-bricolage-grotesque font-bold text-[28px] leading-[36px]" // S: 28px, bold, Bricolage - : "font-inter font-bold text-[20px] leading-[28px]"; // XS: 20px, bold, Inter + // Title typography - use CSS responsive classes + const titleClass = ` + max-[639px]:font-inter max-[639px]:font-bold max-[639px]:text-[20px] max-[639px]:leading-[28px] + min-[640px]:max-[1023px]:font-bricolage-grotesque min-[640px]:max-[1023px]:font-bold min-[640px]:max-[1023px]:text-[28px] min-[640px]:max-[1023px]:leading-[36px] + min-[1024px]:max-[1439px]:font-bricolage-grotesque min-[1024px]:max-[1439px]:font-bold min-[1024px]:max-[1439px]:text-[24px] min-[1024px]:max-[1439px]:leading-[32px] + min-[1440px]:font-bricolage-grotesque min-[1440px]:font-extrabold min-[1440px]:text-[36px] min-[1440px]:leading-[44px] + `; // Description typography const descriptionClass = isLarge @@ -93,7 +92,7 @@ export function RuleCardView({ // Check if it's a localhost URL or external URL that needs regular img tag const isLocalhost = logoUrl.startsWith("http://localhost") || logoUrl.startsWith("https://localhost"); - const containerClass = `${logoContainerClass} relative rounded-full overflow-hidden mix-blend-luminosity ${isSmall ? "p-[12px]" : isExtraSmall ? "p-[16px]" : ""}`; + const containerClass = `${logoContainerClass} relative rounded-full overflow-hidden mix-blend-luminosity max-[639px]:p-[16px] min-[640px]:max-[1023px]:p-[12px]`; if (isLocalhost) { return ( @@ -104,7 +103,7 @@ export function RuleCardView({ alt={logoAlt || title} width={logoSize} height={logoSize} - className={`${isSmall || isExtraSmall ? "w-full h-full" : "absolute inset-0 w-full h-full"} object-cover rounded-full`} + className="w-full h-full object-cover rounded-full" /> ); @@ -117,7 +116,7 @@ export function RuleCardView({ alt={logoAlt || title} width={logoSize} height={logoSize} - className={`${isSmall || isExtraSmall ? "w-full h-full" : "absolute inset-0 w-full h-full"} object-cover rounded-full`} + className="w-full h-full object-cover rounded-full" /> ); @@ -125,20 +124,19 @@ export function RuleCardView({ if (icon) { return ( -