QA pass: layout, create-flow, and About books #68
@@ -36,54 +36,54 @@ const Logo = memo<LogoProps>(
|
|||||||
({ size = "default", palette = "default", wordmark = true }) => {
|
({ size = "default", palette = "default", wordmark = true }) => {
|
||||||
const t = useTranslation("controlsChrome");
|
const t = useTranslation("controlsChrome");
|
||||||
|
|
||||||
// Size configurations
|
// Figma: "Asset / Logo" (4002:6735) — 40×6×27 at 1x; nav/footer/create-flow
|
||||||
|
// instances scale that lockup.
|
||||||
const sizes: Record<string, SizeConfig> = {
|
const sizes: Record<string, SizeConfig> = {
|
||||||
default: {
|
default: {
|
||||||
containerHeight: "h-[41px]",
|
containerHeight: "h-[var(--spacing-scale-040)]",
|
||||||
gap: "gap-[8.28px]",
|
gap: "gap-[var(--spacing-scale-006)]",
|
||||||
textSize: "text-[21.97px]",
|
textSize: "text-[21.97px]",
|
||||||
lineHeight: "leading-[27.05px]",
|
lineHeight: "leading-[27.05px]",
|
||||||
iconSize: "w-[27.05px] h-[27.05px]",
|
iconSize: "w-[27px] h-[27px]",
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
containerHeight:
|
containerHeight: "h-[41px] md:h-[56px] lg:h-[82px]",
|
||||||
"h-[41px] md:h-[calc(40px*1.37)] lg:h-[calc(40px*2.05)]",
|
gap: "gap-[6.21px] md:gap-[8.49px] lg:gap-[12.43px]",
|
||||||
gap: "gap-[8.28px] md:gap-[calc(8px*1.37)] lg:gap-[calc(8px*2.05)]",
|
|
||||||
textSize:
|
textSize:
|
||||||
"text-[21.97px] md:text-[calc(21.97px*1.37)] lg:text-[calc(21.97px*2.05)]",
|
"text-[22.75px] md:text-[31.08px] lg:text-[45.51px]",
|
||||||
lineHeight:
|
lineHeight:
|
||||||
"leading-[27.05px] md:leading-[calc(27.05px*1.37)] lg:leading-[calc(27.05px*2.05)]",
|
"leading-[28px] md:leading-[38.25px] lg:leading-[56.01px]",
|
||||||
iconSize:
|
iconSize:
|
||||||
"w-[27.05px] h-[27.05px] md:w-[calc(27.05px*1.37)] md:h-[calc(27.05px*1.37)] lg:w-[calc(27.05px*2.05)] lg:h-[calc(27.05px*2.05)]",
|
"w-[27.96px] h-[27.96px] md:w-[38.18px] md:h-[38.18px] lg:w-[55.91px] lg:h-[55.91px]",
|
||||||
},
|
},
|
||||||
createFlow: {
|
createFlow: {
|
||||||
containerHeight: "h-[30px] md:h-[41px]",
|
containerHeight: "h-[30px] md:h-[var(--spacing-scale-040)]",
|
||||||
gap: "gap-[6px] md:gap-[8.28px]",
|
gap: "gap-[4.5px] md:gap-[var(--spacing-scale-006)]",
|
||||||
textSize: "text-[16.48px] md:text-[21.97px]",
|
textSize: "text-[16.48px] md:text-[21.97px]",
|
||||||
lineHeight: "leading-[20.28px] md:leading-[27.05px]",
|
lineHeight: "leading-[20.28px] md:leading-[27.05px]",
|
||||||
iconSize: "w-[20.28px] h-[20.28px] md:w-[27.05px] md:h-[27.05px]",
|
iconSize: "w-[20.25px] h-[20.25px] md:w-[27px] md:h-[27px]",
|
||||||
},
|
},
|
||||||
topNavFolderTop: {
|
topNavFolderTop: {
|
||||||
containerHeight:
|
containerHeight:
|
||||||
"h-[14.11px] sm:h-[21.06px] md:h-[32.24px] lg:h-[28px] xl:h-[36px]",
|
"h-[14.1px] sm:h-[21.35px] md:h-[var(--spacing-scale-032)] lg:h-[var(--spacing-scale-040)] xl:h-[50.35px]",
|
||||||
gap: "gap-0 sm:gap-[3.19px] md:gap-[4.89px] lg:gap-[6.55px] xl:gap-[8.64px]",
|
gap: "gap-0 sm:gap-[3.2px] md:gap-[4.8px] lg:gap-[var(--spacing-scale-006)] xl:gap-[7.5px]",
|
||||||
textSize:
|
textSize:
|
||||||
"text-[11.57px] sm:text-[11.69px] md:text-[17.89px] lg:text-[21.97px] xl:text-[29.01px]",
|
"text-[11.57px] sm:text-[11.72px] md:text-[17.58px] lg:text-[21.97px] xl:text-[27.47px]",
|
||||||
lineHeight:
|
lineHeight:
|
||||||
"leading-[14.24px] sm:leading-[14.39px] md:leading-[22.02px] lg:leading-[27.05px] xl:leading-[35.7px]",
|
"leading-[14.24px] sm:leading-[14.42px] md:leading-[21.64px] lg:leading-[27.05px] xl:leading-[33.81px]",
|
||||||
iconSize:
|
iconSize:
|
||||||
"w-[14.11px] h-[14.11px] sm:w-[14.39px] sm:h-[14.39px] md:w-[22.02px] md:h-[22.02px] lg:w-[27.05px] lg:h-[27.05px] xl:w-[35.7px] xl:h-[35.7px]",
|
"w-[14.1px] h-[14.1px] sm:w-[14.4px] sm:h-[14.4px] md:w-[21.6px] md:h-[21.6px] lg:w-[27px] lg:h-[27px] xl:w-[33.75px] xl:h-[33.75px]",
|
||||||
},
|
},
|
||||||
topNavHeader: {
|
topNavHeader: {
|
||||||
containerHeight:
|
containerHeight:
|
||||||
"h-[20.85px] sm:h-[20.85px] md:h-[17.91px] lg:h-[28px] xl:h-[34px]",
|
"h-[14.2px] sm:h-[21.22px] md:h-[var(--spacing-scale-032)] lg:h-[40.69px] xl:h-[50.35px]",
|
||||||
gap: "gap-0 sm:gap-[4.21px] md:gap-[6.51px] lg:gap-[6.55px] xl:gap-[8.19px]",
|
gap: "gap-0 sm:gap-[3.18px] md:gap-[4.85px] lg:gap-[6.06px] xl:gap-[7.5px]",
|
||||||
textSize:
|
textSize:
|
||||||
"text-[11.57px] sm:text-[11.57px] md:text-[17.89px] lg:text-[21.97px] xl:text-[27.47px]",
|
"text-[11.57px] sm:text-[11.66px] md:text-[17.76px] lg:text-[22.2px] xl:text-[27.47px]",
|
||||||
lineHeight:
|
lineHeight:
|
||||||
"leading-[14.24px] sm:leading-[14.24px] md:leading-[22.02px] lg:leading-[27.05px] xl:leading-[33.81px]",
|
"leading-[14.24px] sm:leading-[14.35px] md:leading-[21.86px] lg:leading-[27.32px] xl:leading-[33.81px]",
|
||||||
iconSize:
|
iconSize:
|
||||||
"w-[14.24px] h-[14.24px] sm:w-[14.24px] sm:h-[14.24px] md:w-[22.02px] md:h-[22.02px] lg:w-[27.05px] lg:h-[27.05px] xl:w-[33.81px] xl:h-[33.81px]",
|
"w-[14.2px] h-[14.2px] sm:w-[14.33px] sm:h-[14.33px] md:w-[21.82px] md:h-[21.82px] lg:w-[27.27px] lg:h-[27.27px] xl:w-[33.75px] xl:h-[33.75px]",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,8 +121,8 @@ const Logo = memo<LogoProps>(
|
|||||||
<img
|
<img
|
||||||
src={getAssetPath(ASSETS.LOGO)}
|
src={getAssetPath(ASSETS.LOGO)}
|
||||||
alt={t("logoAlt")}
|
alt={t("logoAlt")}
|
||||||
width={27.05}
|
width={27}
|
||||||
height={27.05}
|
height={27}
|
||||||
className={`flex-shrink-0 ${config.iconSize} origin-center transition-transform duration-200 ease-out group-hover:scale-110 ${
|
className={`flex-shrink-0 ${config.iconSize} origin-center transition-transform duration-200 ease-out group-hover:scale-110 ${
|
||||||
isInverse ? "brightness-0" : ""
|
isInverse ? "brightness-0" : ""
|
||||||
}`}
|
}`}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Logo from "../../asset/logo";
|
import Logo from "../../asset/Logo";
|
||||||
import Button from "../../buttons/Button";
|
import Button from "../../buttons/Button";
|
||||||
import ListItem from "../../layout/ListItem";
|
import ListItem from "../../layout/ListItem";
|
||||||
import Popover from "../../modals/Popover";
|
import Popover from "../../modals/Popover";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { useTranslation } from "../../contexts/MessagesContext";
|
import { useTranslation } from "../../contexts/MessagesContext";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Logo from "../asset/logo";
|
import Logo from "../asset/Logo";
|
||||||
import Divider from "../utility/Divider";
|
import Divider from "../utility/Divider";
|
||||||
import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
|
import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ASSETS, getAssetPath } from "../../../../lib/assetUtils";
|
|||||||
import Menu from "../Menu";
|
import Menu from "../Menu";
|
||||||
import type { TopViewProps } from "./Top.types";
|
import type { TopViewProps } from "./Top.types";
|
||||||
|
|
||||||
import Logo from "../../asset/logo";
|
import Logo from "../../asset/Logo";
|
||||||
|
|
||||||
function TopView({
|
function TopView({
|
||||||
folderTop,
|
folderTop,
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Figma: "Sections / LogoWall" (see registry)
|
* Figma: "Section / Logo Wall" (18847:22366)
|
||||||
|
* Index frames: 320–429 2×3 grid, 430–639 3×2 grid, 640+ space-between row.
|
||||||
|
* Logo heights from those instances (1× / 1.25 at lg / 1.5625 at xl).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { memo, useState, useEffect, useMemo } from "react";
|
import { memo, useMemo } from "react";
|
||||||
import { useTranslation } from "../../../contexts/MessagesContext";
|
import { useTranslation } from "../../../contexts/MessagesContext";
|
||||||
import { getAssetPath, partnerLogoPath } from "../../../../lib/assetUtils";
|
import { getAssetPath, partnerLogoPath } from "../../../../lib/assetUtils";
|
||||||
import LogoWallView from "./LogoWall.view";
|
import LogoWallView from "./LogoWall.view";
|
||||||
@@ -12,39 +14,44 @@ import type { LogoWallProps } from "./LogoWall.types";
|
|||||||
|
|
||||||
const LogoWallContainer = memo<LogoWallProps>(({ logos, className = "" }) => {
|
const LogoWallContainer = memo<LogoWallProps>(({ logos, className = "" }) => {
|
||||||
const t = useTranslation("logoWall");
|
const t = useTranslation("logoWall");
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
|
||||||
|
|
||||||
const defaultLogos = useMemo(
|
const defaultLogos = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("food-not-bombs")),
|
src: getAssetPath(partnerLogoPath("food-not-bombs")),
|
||||||
alt: t("partners.foodNotBombs"),
|
alt: t("partners.foodNotBombs"),
|
||||||
size: "h-11 lg:h-14 xl:h-[70px]",
|
size: "h-[48px] lg:h-[60px] xl:h-[74.6px]",
|
||||||
|
order: "sm:order-4 md:order-4",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("start-coop")),
|
src: getAssetPath(partnerLogoPath("start-coop")),
|
||||||
alt: t("partners.startCoop"),
|
alt: t("partners.startCoop"),
|
||||||
size: "h-[42px] lg:h-[53px] xl:h-[66px]",
|
size: "h-[51.4px] lg:h-[64.2px] xl:h-[80.3px]",
|
||||||
|
order: "sm:order-1 md:order-3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("metagov")),
|
src: getAssetPath(partnerLogoPath("metagov")),
|
||||||
alt: t("partners.metagov"),
|
alt: t("partners.metagov"),
|
||||||
size: "h-6 lg:h-8 xl:h-[41px]",
|
size: "h-[26.2px] lg:h-[33px] xl:h-[41px]",
|
||||||
|
order: "sm:order-6 md:order-1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("open-civics")),
|
src: getAssetPath(partnerLogoPath("open-civics")),
|
||||||
alt: t("partners.openCivics"),
|
alt: t("partners.openCivics"),
|
||||||
size: "h-8 lg:h-10 xl:h-[50px]",
|
size: "h-[50.1px] lg:h-[61.1px] xl:h-[72px]",
|
||||||
|
order: "sm:order-5 md:order-2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("mutual-aid-co")),
|
src: getAssetPath(partnerLogoPath("mutual-aid-co")),
|
||||||
alt: t("partners.mutualAidCo"),
|
alt: t("partners.mutualAidCo"),
|
||||||
size: "h-11 lg:h-14 xl:h-[70px]",
|
size: "h-[51.1px] lg:h-[63.6px] xl:h-[79.5px]",
|
||||||
|
order: "sm:order-2 md:order-5",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: getAssetPath(partnerLogoPath("cu-boulder")),
|
src: getAssetPath(partnerLogoPath("cu-boulder")),
|
||||||
alt: t("partners.cuBoulder"),
|
alt: t("partners.cuBoulder"),
|
||||||
size: "h-10 lg:h-12 xl:h-[60px]",
|
size: "h-[44.6px] lg:h-[55.8px] xl:h-[69.7px]",
|
||||||
|
order: "sm:order-3 md:order-6",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[t],
|
[t],
|
||||||
@@ -55,18 +62,9 @@ const LogoWallContainer = memo<LogoWallProps>(({ logos, className = "" }) => {
|
|||||||
[logos, defaultLogos],
|
[logos, defaultLogos],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Trigger fade-in animation after component mounts
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setIsVisible(true);
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LogoWallView
|
<LogoWallView
|
||||||
isVisible={isVisible}
|
heading={t("heading")}
|
||||||
displayLogos={displayLogos}
|
displayLogos={displayLogos}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export interface LogoWallProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LogoWallViewProps {
|
export interface LogoWallViewProps {
|
||||||
isVisible: boolean;
|
heading: string;
|
||||||
displayLogos: Array<{
|
displayLogos: Array<{
|
||||||
src: string;
|
src: string;
|
||||||
alt: string;
|
alt: string;
|
||||||
|
|||||||
@@ -5,25 +5,24 @@ import Image from "next/image";
|
|||||||
import type { LogoWallViewProps } from "./LogoWall.types";
|
import type { LogoWallViewProps } from "./LogoWall.types";
|
||||||
|
|
||||||
function LogoWallView({
|
function LogoWallView({
|
||||||
isVisible,
|
heading,
|
||||||
displayLogos,
|
displayLogos,
|
||||||
className,
|
className,
|
||||||
}: LogoWallViewProps) {
|
}: LogoWallViewProps) {
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={`p-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-024)] md:py-[var(--spacing-scale-032)] lg:px-[var(--spacing-scale-064)] lg:py-[var(--spacing-scale-048)] xl:px-[160px] xl:py-[var(--spacing-scale-064)] ${className}`}
|
className={`bg-[var(--color-surface-default-primary)] p-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-024)] md:py-[var(--spacing-scale-032)] lg:px-[var(--spacing-scale-064)] lg:py-[var(--spacing-scale-048)] xl:px-[160px] xl:py-[var(--spacing-scale-064)] ${className}`}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-[var(--spacing-scale-032)] md:gap-[var(--spacing-scale-024)] xl:gap-[var(--spacing-scale-032)]">
|
<div className="flex flex-col items-center gap-[var(--spacing-scale-032)] md:gap-[var(--spacing-scale-024)] xl:gap-[var(--spacing-scale-032)]">
|
||||||
<div
|
<p className="font-inter text-center text-[10px] font-medium uppercase leading-[12px] text-[var(--color-content-default-primary)] xl:text-[14px] xl:leading-[12px]">
|
||||||
className={`transition-opacity duration-500 ${
|
{heading}
|
||||||
isVisible ? "opacity-60" : "opacity-0"
|
</p>
|
||||||
}`}
|
<div className="w-full opacity-60">
|
||||||
>
|
<div className="grid grid-cols-2 grid-rows-3 sm:grid-cols-3 sm:grid-rows-2 md:flex md:w-full md:flex-nowrap md:items-center md:justify-between gap-[38.4px] lg:gap-[var(--spacing-scale-048)]">
|
||||||
<div className="grid grid-cols-2 grid-rows-3 sm:grid-cols-3 sm:grid-rows-2 md:flex md:flex-wrap md:justify-center md:items-center gap-x-[var(--spacing-scale-032)] gap-y-[var(--spacing-scale-032)] sm:gap-y-[var(--spacing-scale-048)]">
|
|
||||||
{displayLogos.map((logo, index) => (
|
{displayLogos.map((logo, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`flex items-center justify-center ${
|
className={`flex items-center justify-center md:shrink-0 ${
|
||||||
logo.order || ""
|
logo.order || ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"heading": "Trusted by leading cooperators",
|
||||||
"partners": {
|
"partners": {
|
||||||
"foodNotBombs": "Food Not Bombs",
|
"foodNotBombs": "Food Not Bombs",
|
||||||
"metagov": "Metagov",
|
"metagov": "Metagov",
|
||||||
|
|||||||
@@ -11,16 +11,15 @@ export default {
|
|||||||
|
|
||||||
## Responsive Behavior
|
## Responsive Behavior
|
||||||
|
|
||||||
- **Mobile**: 3 rows × 2 columns grid with 32px gaps
|
- **Mobile**: 3 rows × 2 columns grid with 38.4px gaps
|
||||||
- **SM**: 2 rows × 3 columns grid with 48px row gap and 32px column gap
|
- **SM**: 2 rows × 3 columns grid with 38.4px gaps
|
||||||
- **MD+**: Centered flex-wrap row of logos
|
- **MD+**: Single space-between row (no wrap)
|
||||||
- **LG**: Larger logo sizes and 64px horizontal padding
|
- **LG**: 1.25× logo sizes, 48px gaps, 64px horizontal padding
|
||||||
- **XL**: Largest logo sizes and 160px horizontal padding
|
- **XL**: 1.5625× logo sizes, 48px gaps, 160px horizontal padding
|
||||||
|
|
||||||
## Animations & Transitions
|
## Animations & Transitions
|
||||||
|
|
||||||
- **Fade-in Effect**: Logos fade in from opacity 0 to 60% after component mounts (500ms transition)
|
- **Opacity**: Partner logos render at 60% opacity to match Figma `Section / Logo Wall`.
|
||||||
- **Loading States**: Progressive loading with fallback timer for reliable display
|
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
@@ -70,7 +69,7 @@ export const Default = {
|
|||||||
docs: {
|
docs: {
|
||||||
description: {
|
description: {
|
||||||
story:
|
story:
|
||||||
"Default LogoWall with all partner logos. Displays in a 3×2 grid on mobile, 2×3 grid on small screens, single row on medium screens, and larger sizes on large screens. Features a fade-in on mount.",
|
"Default LogoWall with all partner logos. Displays in a 2×3 grid on mobile, 3×2 grid from 430px, and a space-between row from 640px with Figma lockup sizes. Logos render at 60% opacity to match Figma.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ describe("Logo (behavioral tests)", () => {
|
|||||||
expect(img).toHaveClass("brightness-0");
|
expect(img).toHaveClass("brightness-0");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the Figma 6px wordmark-to-mark gap at the default size", () => {
|
||||||
|
const { container } = render(<Logo />);
|
||||||
|
const row = container.querySelector("a > div");
|
||||||
|
expect(row?.className).toContain("gap-[var(--spacing-scale-006)]");
|
||||||
|
expect(row?.className).toContain("h-[var(--spacing-scale-040)]");
|
||||||
|
});
|
||||||
|
|
||||||
it("renders with different size variants", () => {
|
it("renders with different size variants", () => {
|
||||||
const { rerender } = render(<Logo size="default" />);
|
const { rerender } = render(<Logo size="default" />);
|
||||||
expect(screen.getByRole("link")).toBeInTheDocument();
|
expect(screen.getByRole("link")).toBeInTheDocument();
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ describe("LogoWall Component", () => {
|
|||||||
render(<LogoWall />);
|
render(<LogoWall />);
|
||||||
|
|
||||||
const section = document.querySelector("section");
|
const section = document.querySelector("section");
|
||||||
expect(section).toHaveClass("p-[var(--spacing-scale-032)]");
|
expect(section).toHaveClass(
|
||||||
|
"bg-[var(--color-surface-default-primary)]",
|
||||||
|
"p-[var(--spacing-scale-032)]",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders with design tokens", () => {
|
test("renders with design tokens", () => {
|
||||||
@@ -70,7 +73,9 @@ describe("LogoWall Component", () => {
|
|||||||
"sm:grid-cols-3",
|
"sm:grid-cols-3",
|
||||||
"sm:grid-rows-2",
|
"sm:grid-rows-2",
|
||||||
"md:flex",
|
"md:flex",
|
||||||
"md:justify-center",
|
"md:justify-between",
|
||||||
|
"md:flex-nowrap",
|
||||||
|
"gap-[38.4px]",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,7 +87,11 @@ describe("LogoWall Component", () => {
|
|||||||
"src",
|
"src",
|
||||||
"/assets/logos/partners/food-not-bombs.svg",
|
"/assets/logos/partners/food-not-bombs.svg",
|
||||||
);
|
);
|
||||||
expect(foodNotBombsLogo).toHaveClass("h-11", "lg:h-14", "xl:h-[70px]");
|
expect(foodNotBombsLogo).toHaveClass(
|
||||||
|
"h-[48px]",
|
||||||
|
"lg:h-[60px]",
|
||||||
|
"xl:h-[74.6px]",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("handles empty logos array", () => {
|
test("handles empty logos array", () => {
|
||||||
@@ -109,16 +118,17 @@ describe("LogoWall Component", () => {
|
|||||||
const section = document.querySelector("section");
|
const section = document.querySelector("section");
|
||||||
expect(section).toBeInTheDocument();
|
expect(section).toBeInTheDocument();
|
||||||
|
|
||||||
expect(screen.queryByText("Trusted by leading cooperators")).not.toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText("Trusted by leading cooperators"),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("applies transition effects", () => {
|
test("renders partner logos at Figma 60% opacity", () => {
|
||||||
render(<LogoWall />);
|
render(<LogoWall />);
|
||||||
|
|
||||||
const logoContainers = document.querySelectorAll(
|
expect(
|
||||||
'[class*="transition-opacity duration-500"]',
|
document.querySelectorAll('[class*="opacity-60"]').length,
|
||||||
);
|
).toBeGreaterThan(0);
|
||||||
expect(logoContainers.length).toBeGreaterThan(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders with proper image optimization", () => {
|
test("renders with proper image optimization", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user