story-az-card-kit
Version:
A flexible and customizable story card component with multiple layouts
107 lines (96 loc) • 2.57 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
const StoryCard = ({
title,
description,
image,
author,
date,
tags = [],
layout = 'vertical',
theme = 'default',
onClick,
className = '',
children,
...props
}) => {
const baseClass = 'story-card';
const layoutClass = `story-card--${layout}`;
const themeClass = `story-card--${theme}`;
const cardClasses = [
baseClass,
layoutClass,
themeClass,
className
].filter(Boolean).join(' ');
const handleClick = (e) => {
if (onClick) {
onClick(e, { title, description, image, author, date, tags });
}
};
return (
<div
className={cardClasses}
onClick={handleClick}
role="button"
tabIndex={onClick ? 0 : undefined}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick(e);
}
}}
{...props}
>
{image && (
<div className="story-card__image">
<img src={image} alt={title} loading="lazy" />
</div>
)}
<div className="story-card__content">
{title && (
<h3 className="story-card__title">{title}</h3>
)}
{description && (
<p className="story-card__description">{description}</p>
)}
{(author || date) && (
<div className="story-card__meta">
{author && (
<span className="story-card__author">{author}</span>
)}
{date && (
<time className="story-card__date" dateTime={date}>
{new Date(date).toLocaleDateString()}
</time>
)}
</div>
)}
{tags.length > 0 && (
<div className="story-card__tags">
{tags.map((tag, index) => (
<span key={index} className="story-card__tag">
{tag}
</span>
))}
</div>
)}
{children}
</div>
</div>
);
};
StoryCard.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
author: PropTypes.string,
date: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.string),
layout: PropTypes.oneOf(['vertical', 'horizontal', 'grid', 'masonry', 'carousel', 'flip']),
theme: PropTypes.oneOf(['default', 'dark', 'minimal', 'elegant', 'modern']),
onClick: PropTypes.func,
className: PropTypes.string,
children: PropTypes.node
};
export default StoryCard;