story-az-card-kit
Version:
A flexible and customizable story card component with multiple layouts
76 lines (66 loc) • 1.94 kB
JavaScript
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import StoryCard from '../components/StoryCard';
const MasonryCard = ({
stories = [],
columns = 3,
gap = 'medium',
theme = 'default',
onCardClick,
className = '',
children,
...props
}) => {
const masonryRef = useRef(null);
useEffect(() => {
const masonry = masonryRef.current;
if (!masonry) return;
const resizeObserver = new ResizeObserver(() => {
// Trigger reflow for masonry layout
masonry.style.opacity = '0.99';
setTimeout(() => {
masonry.style.opacity = '1';
}, 10);
});
resizeObserver.observe(masonry);
return () => {
resizeObserver.disconnect();
};
}, []);
const masonryClass = `story-card-masonry story-card-masonry--${columns}-cols story-card-masonry--gap-${gap}`;
const masonryClasses = [
masonryClass,
className
].filter(Boolean).join(' ');
return (
<div ref={masonryRef} className={masonryClasses} {...props}>
{stories.map((story, index) => (
<div key={index} className="story-card-masonry__item">
<StoryCard
{...story}
theme={theme}
onClick={onCardClick ? (e, data) => onCardClick(e, data, index) : undefined}
/>
</div>
))}
{children}
</div>
);
};
MasonryCard.propTypes = {
stories: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
author: PropTypes.string,
date: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.string)
})),
columns: PropTypes.oneOf([2, 3, 4, 5]),
gap: PropTypes.oneOf(['small', 'medium', 'large']),
theme: PropTypes.oneOf(['default', 'dark', 'minimal', 'elegant', 'modern']),
onCardClick: PropTypes.func,
className: PropTypes.string,
children: PropTypes.node
};
export default MasonryCard;