Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

// Images with captions
.uds-figure {
margin: 0;
width: 100%;
img.img-original {
width: initial;
Expand Down Expand Up @@ -60,8 +61,5 @@
&.uds-img-drop-shadow {
box-shadow: $uds-size-spacing-0 $uds-size-spacing-1 $uds-size-spacing-2
rgba(25, 25, 25, 0.2);
.uds-figure {
margin-bottom: $uds-size-spacing-0;
}
}
}
115 changes: 114 additions & 1 deletion packages/unity-react-core/src/components/Card/Card.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,69 @@ export const Card = ({
tags,
showBorders = true,
cardLink,
cards = [],
columns = "0",
layout = "auto"
}) => {
// If multiple cards are provided, render them in a card container
if (cards.length > 1) {
const getColumnClass = () => {
switch (columns) {
case "2":
return "";
case "3":
return "three-columns";
case "4":
return "four-columns";
default:
return "";
}
};

return (
<div className={classNames("uds-card-arrangement", {
"uds-card-arrangement-vertical": layout === "vertical",
"auto-arrangement": layout !== "vertical"
})
}>
<div
className={classNames(
"uds-card-arrangement-card-container",
getColumnClass()
)}
>
{cards.map((card, index) => (
<BaseCard
key={index}
type={card.type || type}
width={card.width || width}
horizontal={
card.horizontal !== undefined ? card.horizontal : horizontal
}
image={card.image}
imageAltText={card.imageAltText}
title={card.title}
icon={card.icon}
body={card.body}
eventFormat={card.eventFormat || eventFormat}
eventLocation={card.eventLocation}
eventTime={card.eventTime}
buttons={card.buttons}
linkLabel={card.linkLabel}
linkUrl={card.linkUrl}
tags={card.tags}
showBorders={
card.showBorders !== undefined ? card.showBorders : showBorders
}
cardLink={card.cardLink}
/>
))}
</div>
</div>
);
}

// Single card - render as before
return (
<BaseCard
type={type}
Expand Down Expand Up @@ -86,7 +148,7 @@ Card.propTypes = {
/**
* Card title
*/
title: PropTypes.string.isRequired,
title: PropTypes.string,
/**
React Font Awesome icon prefix and name string to be rendered in button label. Ex: ['fab', 'drupal']
*/
Expand Down Expand Up @@ -152,6 +214,57 @@ Card.propTypes = {
* Card link
*/
cardLink: PropTypes.string,
/**
* Array of card objects for rendering multiple cards
*/
cards: PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.oneOf(["default", "degree", "event", "news", "story"]),
width: PropTypes.oneOf(["25%", "50%", "75%", "100%"]),
horizontal: PropTypes.bool,
title: PropTypes.string.isRequired,
icon: PropTypes.arrayOf(PropTypes.string),
body: PropTypes.string,
eventFormat: PropTypes.oneOf(["stack", "inline"]),
eventLocation: PropTypes.string,
eventTime: PropTypes.string,
image: PropTypes.string,
imageAltText: PropTypes.string,
buttons: PropTypes.arrayOf(
PropTypes.shape({
ariaLabel: PropTypes.string,
color: PropTypes.oneOf(["gold", "maroon", "gray", "dark"]),
icon: PropTypes.arrayOf(PropTypes.string),
href: PropTypes.string,
label: PropTypes.string,
onClick: PropTypes.func,
size: PropTypes.oneOf(["default", "small", "xsmall"]),
target: PropTypes.oneOf(["_blank", "_self", "_top", "_parent"]),
})
),
linkLabel: PropTypes.string,
linkUrl: PropTypes.string,
tags: PropTypes.arrayOf(
PropTypes.shape({
ariaLabel: PropTypes.string,
color: PropTypes.oneOf(["white", "gray", "dark"]),
href: PropTypes.string,
label: PropTypes.string,
onClick: PropTypes.func,
})
),
showBorders: PropTypes.bool,
cardLink: PropTypes.string,
})
),
/**
* Number of columns for multiple cards layout (0, 2, 3, or 4)
*/
columns: PropTypes.oneOf(["0", "2", "3", "4"]),
/**
* Vertical or normal layout
*/
layout: PropTypes.oneOf(["vertical", "auto"])
};

/*
Expand Down
131 changes: 130 additions & 1 deletion packages/unity-react-core/src/components/Card/Card.stories.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { imageAny } from "@asu/shared";
import classNames from "classnames";
import React from "react";
const img1 = imageAny(); // Placeholder for an example image
const img1 = imageAny();

// @ts-ignore
import { Card } from "./Card";
Expand Down Expand Up @@ -328,3 +328,132 @@ AsuNewsStory.parameters = {
},
},
};

const MultipleCardsTemplate = args => (
<div className="container">
<div className={classNames("row", "row-spaced", "pt-2", "pb-2")}>
<div className={classNames("col", "col-12")}>
<Card {...args} />
</div>
</div>
</div>
);

export const MultipleCardsTwoColumns = MultipleCardsTemplate.bind({});
MultipleCardsTwoColumns.args = {
columns: "2",
cards: [
{
title: "First Card",
body: "This is the first card in a two-column layout.",
image: img1,
imageAltText: "First card image",
type: "default",
},
{
title: "Second Card",
body: "This is the second card in a two-column layout.",
image: img1,
imageAltText: "Second card image",
type: "default",
},
{
title: "Third Card",
body: "This is the third card in a two-column layout.",
image: img1,
imageAltText: "Third card image",
type: "default",
},
{
title: "Fourth Card",
body: "This is the fourth card in a two-column layout.",
image: img1,
imageAltText: "Fourth card image",
type: "default",
},
],
};

export const MultipleCardsFourColumns = MultipleCardsTemplate.bind({});
MultipleCardsFourColumns.args = {
columns: "4",
cards: [
{
title: "First Card",
body: "This is the first card in a four-column layout.",
image: img1,
imageAltText: "First card image",
type: "default",
},
{
title: "Second Card",
body: "This is the second card in a four-column layout.",
image: img1,
imageAltText: "Second card image",
type: "default",
},
{
title: "Third Card",
body: "This is the third card in a four-column layout.",
image: img1,
imageAltText: "Third card image",
type: "default",
},
{
title: "Fourth Card",
body: "This is the fourth card in a four-column layout.",
image: img1,
imageAltText: "Fourth card image",
type: "default",
},
],
};

export const MultipleCardsThreeColumns = MultipleCardsTemplate.bind({});
MultipleCardsThreeColumns.args = {
columns: "3",
cards: [
{
title: "First Card",
body: "This is the first card in a three-column layout.",
image: img1,
imageAltText: "First card image",
type: "default",
},
{
title: "Second Card",
body: "This is the second card in a three-column layout.",
image: img1,
imageAltText: "Second card image",
type: "default",
},
{
title: "Third Card",
body: "This is the third card in a three-column layout.",
image: img1,
imageAltText: "Third card image",
type: "default",
},
{
title: "Fourth Card",
body: "This is the fourth card in a three-column layout.",
image: img1,
imageAltText: "Fourth card image",
type: "default",
},
{
title: "Fifth Card",
body: "This is the fifth card in a three-column layout.",
image: img1,
imageAltText: "Fifth card image",
type: "default",
},
{
title: "Sixth Card",
body: "This is the sixth card in a three-column layout.",
image: img1,
imageAltText: "Sixth card image",
type: "default",
},
],
};
56 changes: 55 additions & 1 deletion packages/unity-react-core/src/components/Card/Card.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check
import { render, cleanup } from "@testing-library/react";
import React from "react";
import { expect, describe, it, afterEach, beforeEach, test } from "vitest";
import { expect, describe, it, afterEach, beforeEach, test, vi } from "vitest";

import { Card } from "./Card";

Expand Down Expand Up @@ -100,4 +100,58 @@ describe("#Card options", () => {
className
);
});

describe("Multiple Cards", () => {
const multipleCardsArgs = {
columns: "2",
cards: [
{
title: "First Card",
body: "First card body text",
image: "https://picsum.photos/300/200",
imageAltText: "First card image",
},
{
title: "Second Card",
body: "Second card body text",
image: "https://picsum.photos/300/200",
imageAltText: "Second card image",
},
],
};

beforeEach(() => {
component = renderCard(multipleCardsArgs);
});

it("should render multiple cards container", () => {
const parentContainer = component.container.querySelector(
".uds-card-arrangement"
);
const cardContainer = component.container.querySelector(
".uds-card-arrangement-card-container"
);
vi.waitFor(() => {
expect(parentContainer).toBeInTheDocument();
expect(cardContainer).toBeInTheDocument();
});
});

it("should render correct number of cards", () => {
const cards = component.container.querySelectorAll(".card");
expect(cards).toHaveLength(2);
});

it("should apply auto-arrangement class", () => {
const container = component.container.querySelector(".auto-arrangement");
expect(container).toBeInTheDocument();
});

it("should apply four-columns class when columns is 4", () => {
const fourColumnArgs = { ...multipleCardsArgs, columns: "4" };
component = renderCard(fourColumnArgs);
const container = component.container.querySelector(".four-columns");
expect(container).toBeInTheDocument();
});
});
});
Loading