Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(BoxWithImage component) #1569

Merged
merged 5 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 24 additions & 21 deletions app/components/BoxWithImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,50 @@

export type BoxWithImageProps = {
image: ImageProps;
variant?: "default" | "ImgMTextL";
variant?: Variant;
identifier?: string;
heading?: HeadingProps;
content?: string;
};

const variantStyles = {
default: {
textSize: "1rem",
imageContainer: "basis-1/6",
columnBreakpoint: "md:flex-row",
},
ImgMTextL: {
textSize: "1.25rem",
imageContainer: "basis-1/3",
columnBreakpoint: "lg:flex-row",
},
} as const;
export type Variant = "ImgMTextL" | "XS" | "S" | "M" | "L" | "XL" | "XXL";

export const variantWidths: Record<Variant, string> = {
// TODO: Remove after new variant implementation

Check warning on line 16 in app/components/BoxWithImage.tsx

View workflow job for this annotation

GitHub Actions / code-quality / npm run lint

Complete the task associated to this "TODO" comment
ImgMTextL: "max-w-[280px]",
XS: "max-w-[80px]",
S: "max-w-[120px]",
M: "max-w-[280px]",
L: "max-w-[400px]",
XL: "max-w-[630px]",
XXL: "max-w-[848px]",
};

const BoxWithImage = ({
variant = "default",
variant = "S",
identifier,
heading,
image,
content,
}: BoxWithImageProps) => {
const shouldWrapByDefault = variant === "XL" || variant === "XXL";
const hasTextContent = Boolean(heading || content);
return (
<div
id={identifier}
className={`flex flex-col items-start gap-24 ${variantStyles[variant].columnBreakpoint}`}
style={{ fontSize: variantStyles[variant].textSize }}
className={`flex flex-wrap ${shouldWrapByDefault ? "md:flex-wrap" : "sm:flex-nowrap"} items-start gap-24 text-base`}
>
<div
className={`shrink-0 overflow-hidden max-w-[70ch] ${content ? variantStyles[variant].imageContainer : "basis-full"}`}
className={`lg:shrink-0 overflow-hidden ${hasTextContent ? variantWidths[variant] : "max-w-full"}`}
>
<Image {...image} />
</div>
<div className={"ds-stack-8 break-words basis-auto"}>
{heading && <Heading {...heading} />}
{content && <RichText markdown={content} />}
</div>
{hasTextContent && (
<div className={`ds-stack-8 break-words min-w-[120px] max-w-[696px]`}>
{heading && <Heading {...heading} />}
{content && <RichText markdown={content} />}
</div>
)}
</div>
);
};
Expand Down
57 changes: 57 additions & 0 deletions app/components/__test__/BoxWithImage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { render } from "@testing-library/react";
import type { Variant } from "~/components/BoxWithImage";
import BoxWithImage, { variantWidths } from "~/components/BoxWithImage";

describe("BoxWithImage", () => {
const imageAltText = "Alt text";
it("should render", () => {
const imageText = "A beautiful image";
const headerText = "Some title description";
const { getByText, getByAltText } = render(
<BoxWithImage
image={{ alternativeText: imageAltText, url: "image.png" }}
content={imageText}
heading={{ text: headerText }}
/>,
);
expect(getByText(imageText)).toBeInTheDocument();
expect(getByText(headerText)).toBeInTheDocument();
expect(getByAltText(imageAltText)).toBeInTheDocument();
});

it.each(
Object.entries(variantWidths).map(([key, value]) => [
key as Variant,
value,
]),
)(
"image variant %s should have proper styling",
(imageVariant, expectedStyle) => {
const { getByAltText } = render(
<BoxWithImage
variant={imageVariant}
image={{ url: "image.png", alternativeText: imageAltText }}
content="Wow great image!"
/>,
);
const imageContainer = getByAltText(imageAltText).parentElement;
const shouldWrap = imageVariant === "XL" || imageVariant === "XXL";
const flexContainer = imageContainer?.parentElement;
expect(flexContainer).toHaveClass(
shouldWrap ? "md:flex-wrap" : "sm:flex-nowrap",
);
expect(imageContainer).toHaveClass(expectedStyle);
},
);

it("should display just an image if there is no text content", () => {
const { getByAltText } = render(
<BoxWithImage
image={{ url: "image.png", alternativeText: imageAltText }}
/>,
);
const image = getByAltText(imageAltText);
expect(image).toBeInTheDocument();
expect(image.parentElement).toHaveClass("max-w-full");
});
});
13 changes: 11 additions & 2 deletions app/services/cms/models/StrapiBoxWithImage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { z } from "zod";
import { type BoxWithImageProps } from "~/components/BoxWithImage";
import {
variantWidths,
type Variant,
type BoxWithImageProps,
} from "~/components/BoxWithImage";
import { omitNull } from "~/util/omitNull";
import { HasOptionalStrapiIdSchema } from "./HasStrapiId";
import { OptionalStrapiLinkIdentifierSchema } from "./HasStrapiLinkIdentifier";
Expand All @@ -8,13 +12,18 @@ import { StrapiContainerSchema } from "./StrapiContainer";
import { getHeadingProps, StrapiHeadingSchema } from "./StrapiHeading";
import { StrapiImageSchema, getImageProps } from "./StrapiImage";

// Necessary destructuring for zod enum type
const [firstWidth, ...widths] = Object.keys(variantWidths).map(
(key) => key as Variant,
);

const StrapiBoxWithImageSchema = z
.object({
heading: StrapiHeadingSchema.nullable(),
image: StrapiImageSchema,
content: z.string().nullable(),
outerBackground: StrapiBackgroundSchema.nullable(),
variant: z.enum(["ImgMTextL"]).nullable(),
variant: z.enum([firstWidth, ...widths]).nullable(),
container: StrapiContainerSchema,
})
.merge(HasOptionalStrapiIdSchema)
Expand Down
17 changes: 6 additions & 11 deletions stories/BoxWithImage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,13 @@ export default meta;
export const Default: StoryObj<typeof meta> = {
args: {
image: { url: "public/og-image.png" },
variant: "ImgMTextL",
heading: {
text: "Heading text",
tagName: "h2",
look: "ds-heading-03-bold",
text: "Ein Pilotprojekt des Bundesministeriums der Justiz und der Justizministerien der Länder.",
tagName: "h1",
look: "ds-label-01-reg",
},
content: `Non blanditiis vel quis. A molestias id quia modi veniam sunt. Quia eligendi quos ut.

Totam quis saepe sed qui in. Beatae occaecati et aperiam non iusto sequi. Ut nihil similique aut magni neque.

- Laboriosam quae esse libero eum. Iure et veritatis voluptates. Fugiat voluptates sunt aperiam accusantium ab voluptatum doloribus veniam. Maiores esse et est.
- Quia distinctio earum accusamus aut ullam aut. Porro quis beatae ut rerum quas nemo itaque sed. Dolores voluptates in laborum deserunt cupiditate pariatur est.

Est perspiciatis blanditiis aliquam. Ut perferendis et illo eligendi aliquid. Est mollitia vel molestiae. Enim sed eius et saepe voluptatem occaecati quasi voluptas.`,
content:
"In diesem Projekt geht es darum, den Zugang zum Recht zu verbessern. Diese Seite befindet sich im Aufbau. Weitere Funktionen und Dienstleistungen werden mit der Zeit ergänzt.",
},
};
Loading