Skip to content

Commit

Permalink
create CardOverlay, create links, update storybook settings
Browse files Browse the repository at this point in the history
  • Loading branch information
alfjrl committed Feb 5, 2025
1 parent 9884643 commit a5a7e6f
Show file tree
Hide file tree
Showing 18 changed files with 574 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .storybook/UmdLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default create({
base: "light",
brandTitle: "Unversity Libraries",
brandUrl: "https://lib.umd.edu",
brandImage: "/lib_logo.svg",
// brandImage: "/lib_logo.svg",
brandImage: "https://www.lib.umd.edu/sites/default/files/2021-06/logo.svg",
brandTarget: "_self",
});
12 changes: 12 additions & 0 deletions app/globals.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/buttons/ButtonPrimary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const cn = (...classes) => {
};

const BASE_BUTTON_CLASSES =
"t-body-small t-interactive-sub button--primary c-content-interactive-primary c-bg-interactive-primary ani-background";
"button--primary t-body-small t-interactive-sub c-content-interactive-primary c-bg-interactive-primary ani-background";

const ButtonPrimary = forwardRef(({ children, className, ...props }, ref) => {
const buttonClasses = cn(BASE_BUTTON_CLASSES, className);
Expand Down
2 changes: 1 addition & 1 deletion components/buttons/ButtonSecondary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const cn = (...classes) => {
};

const BASE_BUTTON_CLASSES =
"t-body-small t-interactive-sub button--secondary c-content-primary c-underline-primary ani-underline";
"button--secondary t-body-small t-interactive-sub c-content-primary c-underline-primary ani-underline";

const ButtonSecondary = forwardRef(({ children, className, ...props }, ref) => {
const buttonClasses = cn(BASE_BUTTON_CLASSES, className);
Expand Down
Empty file.
42 changes: 42 additions & 0 deletions components/cards/CardStandard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.card--image img {
aspect-ratio: 5/4;
object-fit: cover;
object-position: center;
width: 100%;
height: 100%;
}

.card--content {
flex-grow: 1;

display: flex;
flex-direction: column;
}

.card--details {
margin-bottom: auto;
}

.card--title,
a {
width: fit-content;
}

.card--overlay {
min-height: 334px;

width: fit-content;

display: flex;
flex-direction: column;
}

.card--overlay img {
display: none;
}

@media (min-width: 768px) {
.card--overlay {
min-height: 456px;
}
}
66 changes: 66 additions & 0 deletions components/cards/CardStandard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { forwardRef } from "react";
import "./CardStandard.css";

import ButtonSecondary from "../buttons/ButtonSecondary";
import LinkTitle from "../links/LinkTitle";

const cn = (...classes) => {
return classes.filter(Boolean).join(" ");
};

const BASE_CARD_CLASSES = "card-standard";

const CardStandard = forwardRef(
(
{
title,
eyebrow,
description,
date,
link,
variant = "standard",
className,
...props
},
ref
) => {
const cardClasses = cn(BASE_CARD_CLASSES, className);

return (
<div role="contentinfo" ref={ref} className={cardClasses} {...props}>
<div className="card--image">
<img src="https://picsum.photos/1600/900" alt="Example Image" />
</div>
<div className="card--content s-box-small-v s-box-small-h">
<div className="card--title">
<div className="card--eyebrow t-eyebrow s-stack-small">
<p>{eyebrow}</p>
</div>

<h3 className="card--headline s-stack-default">
<LinkTitle>{title}</LinkTitle>
{/* <Link variant="title">{title}</Link>
<a class="link--title c-content-primary c-underline-secondary ani-underline t-title-medium">
{title}
</a> */}
</h3>
</div>
<div className="card--details">
<div className="card--text t-body-small c-content-secondary s-stack-default">
<p>{description}</p>
</div>

<div className="card--date t-label c-content-tertiary s-stack-large">
<time dateTime="2025-01-28">{date}</time>
</div>
</div>
<ButtonSecondary>{link}</ButtonSecondary>
</div>
</div>
);
}
);

CardStandard.displayName = "Card - Standard";

export default CardStandard;
127 changes: 127 additions & 0 deletions components/cards/CardStandard.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import {
Meta,
Canvas,
Title,
Subtitle,
Description,
Primary,
Controls,
Stories,
ArgTypes,
Source,
} from "@storybook/blocks";

import * as CardStandardStories from "./CardStandard.stories";

<Meta of={CardStandardStories} />

<Title />
<Subtitle />
<Description />
<Primary />
<Controls />

### Note

The main difference between standard and overlay cards is whether they have images or not. Here using the CSS to hide the image in overlay card to reduce the difference in twig, but it might have better solution when implementing it.

### Text Fields

<table>
<tr>
<td>Field</td>
<td>Requirement</td>
<td>Description</td>
</tr>
<tr>
<td>Eyebrow</td>
<td>Optional</td>
<td>A short description or category.</td>
</tr>
<tr>
<td>Title</td>
<td>Required</td>
<td>The title of the card.</td>
</tr>
<tr>
<td>Description</td>
<td>Optional</td>
<td>A short description of the card.</td>
</tr>
<tr>
<td>Date</td>
<td>Optional</td>
<td>The date of the card.</td>
</tr>
<tr>
<td>CTA</td>
<td>Optional</td>
<td>The text for the call to action button.</td>
</tr>
</table>

- **Eyebrow**: [Optional] A short description or category.
- **Title**: [Required] The title of the card.
- **Description**: [Required] A short description of the card.
- **Date**: [Optional] The date of the card.
- **CTA Text**: [Optional] The text for the call to action button.

### Twig

#### Standard Card

```twig
{% set classes = [
'c-bg-primary',
'c-content-primary',
'card--standard',
] %}
<div{{ attributes.addClass(classes) }} role="contentinfo">
{% if image %}
<div class="card--image">
{{ image }}
</div>
{% endif %}
<div class="card--content s-box-small-v s-box-small-h">
<div class="card--title">
{% if eyebrow %}
<div class="card--eyebrow t-eyebrow s-stack-small">
<p>{{ eyebrow }}</p>
</div>
{% endif %}
{% if title %}
<h3 class="card--headline t-title-medium c-underline-secondary ani-underline s-stack-default">
<a href="{{ url }}">
<span class="sr-only">{{ title }}</span>
<span aria-hidden="true">{{ title }}</span>
</a>
</h3>
{% endif %}
</div>
<div class="card--details">
{% if description %}
<div class="card--text t-body-small c-content-secondary s-stack-default">
<p>{{ description }}</p>
</div>
{% endif %}
{% if date %}
<div class="card--date t-label c-content-tertiary s-stack-large">
<time datetime="{{ date|date('Y-m-d') }}">{{ date|date('F j, Y') }}</time>
</div>
{% endif %}
</div>
{% if cta_text %}
<a href="{{ url }}" class="t-body-small t-interactive-sub button--secondary c-content-primary c-underline-primary ani-underline">
<div class="i-chevron"></div>
{{ cta_text }}
</a>
{% endif %}
</div>
</div>
```
74 changes: 74 additions & 0 deletions components/cards/CardStandard.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import CardStandard from "./CardStandard";

export default {
title: "Component/Cards/Standard",
component: CardStandard,
parameters: {
layout: "centered",
viewport: {
viewports: {
mobile: {
name: "Mobile",
styles: {
width: "390px",
height: "844px",
},
},
tablet: {
name: "Tablet",
styles: {
width: "768px",
height: "1024px",
},
},
laptop: {
name: "Laptop",
styles: {
width: "1024px",
height: "768px",
},
},
desktop: {
name: "Desktop",
styles: {
width: "1680px",
height: "900px",
},
},
},
},
},
argTypes: {
title: {
control: "text",
description: "The title in the card",
},
eyebrow: {
control: "text",
description: "The optional eyebrow above title",
},
description: {
control: "text",
description: "The content inside the card",
},
date: {
control: "text",
description: "The optional date information under card description",
},
link: {
control: "text",
description: "The optional link",
},
},
};

export const Standard = {
args: {
title: "Digital Collections",
eyebrow: "Optional Tagline",
description:
"Access digitized material, including photographs, archives and manuscripts, film and audio, and more from our specialized collections.",
date: "September 31, 2023",
link: "Explore Digital Collections",
},
};
25 changes: 25 additions & 0 deletions components/links/LinkBody.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { forwardRef } from "react";

// Utility function to merge classnames
const cn = (...classes) => {
return classes.filter(Boolean).join(" ");
};

const BASE_LINK_CLASSES =
"link--body c-content-interactive-secondary d-underline t-body-medium";

const LinkBody = forwardRef(
({ children, className, variant = "title", ...props }, ref) => {
const linkClasses = cn(BASE_LINK_CLASSES, className);

return (
<a ref={ref} className={linkClasses} {...props}>
{children}
</a>
);
}
);

LinkBody.displayName = "Link - Body";

export default LinkBody;
Loading

0 comments on commit a5a7e6f

Please sign in to comment.