GitHub's design system implemented as React components for building consistent user interfaces.
1.2k stars
Product Description
$9.99
$12.99
import React, { useState } from 'react';
import styled, { css } from 'styled-components';
// ============================================================================
// Types
// ============================================================================
interface ProductColor {
id: string;
imageUrl: string;
alt?: string;
}
interface Product {
id: string;
name: string;
description: string;
price: number;
salePrice?: number;
thumbnailUrl: string;
thumbnailAlt?: string;
detailUrl: string;
colors: ProductColor[];
}
interface ProductCardProps {
product: Product;
className?: string;
onColorSelect?: (colorId: string) => void;
}
// ============================================================================
// Styled Components
// ============================================================================
const Card = styled.article`
background-color: #ffffff;
border: 1px solid #e0e0e0;
padding: 1rem;
margin-bottom: 1.5rem;
border-radius: 4px;
transition: box-shadow 0.2s ease;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
`;
const ThumbnailLink = styled.a`
display: block;
position: relative;
overflow: hidden;
border-radius: 2px;
img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 1 / 1;
object-fit: cover;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.02);
}
}
`;
const Title = styled.h2`
font-family: 'Open Sans', sans-serif;
font-size: 0.9rem;
font-weight: 600;
line-height: 1.45rem;
margin-top: 1rem;
margin-bottom: 0;
a {
color: #1a1a1a;
text-decoration: none;
transition: color 0.2s ease;
&:hover {
color: #0066cc;
}
}
`;
const Description = styled.span`
color: #555555;
display: block;
font-family: 'Open Sans', sans-serif;
font-size: 0.85rem;
margin-top: 0.15rem;
`;
const PriceRow = styled.div`
display: flex;
align-items: baseline;
gap: 0.3rem;
margin-top: 0.8rem;
flex-wrap: wrap;
`;
const Price = styled.span<{ $isOnSale: boolean }>`
color: ${({ $isOnSale }) => ($isOnSale ? '#1a1a1a' : '#1a1a1a')};
display: inline-block;
font-size: 0.85rem;
font-weight: 600;
${({ $isOnSale }) =>
$isOnSale &&
css`
color: #cc0000;
`}
`;
const SalePrice = styled.span`
color: #888888;
display: inline-block;
font-size: 0.85rem;
text-decoration: line-through;
`;
const ColorsContainer = styled.div`
display: flex;
gap: 0.4rem;
margin-top: 0.8rem;
flex-wrap: wrap;
`;
const ColorButton = styled.button<{ $isSelected: boolean }>`
display: inline-flex;
align-items: center;
justify-content: center;
height: 30px;
width: 30px;
padding: 0;
border: 2px solid ${({ $isSelected }) => ($isSelected ? '#0066cc' : '#e0e0e0')};
border-radius: 50%;
background: transparent;
cursor: pointer;
transition: all 0.2s ease;
overflow: hidden;
&:hover {
border-color: ${({ $isSelected }) => ($isSelected ? '#0066cc' : '#999999')};
transform: scale(1.05);
}
&:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
`;
// ============================================================================
// Component
// ============================================================================
export const ProductCard: React.FC
= ({
product,
className,
onColorSelect,
}) => {
const [selectedColorId, setSelectedColorId] = useState(
product.colors.length > 0 ? product.colors[0].id : null
);
const isOnSale = product.salePrice !== undefined && product.salePrice < product.price;
const handleColorClick = (colorId: string) => {
setSelectedColorId(colorId);
onColorSelect?.(colorId);
};
return (
{/* Thumbnail */}
{/* Title */}
{product.name}
{/* Description */}
{product.description}
{/* Price */}
${product.price.toFixed(2)}
{isOnSale && (
${product.salePrice!.toFixed(2)}
)}
{/* Color Options */}
{product.colors.length > 0 && (
{product.colors.map((color) => {
const isSelected = selectedColorId === color.id;
return (
handleColorClick(color.id)}
role="radio"
aria-checked={isSelected}
aria-label={color.alt || `Color option`}
type="button"
>
);
})}
)}
);
};
// ============================================================================
// Default Export
// ============================================================================
export default ProductCard;
// ============================================================================
// Example Usage
// ============================================================================
/*
import React from 'react';
import { ProductCard } from './ProductCard';
const EXAMPLE_PRODUCT: Product = {
id: 'prod-001',
name: 'Classic T-Shirt',
description: 'Comfortable 100% cotton t-shirt',
price: 12.99,
salePrice: 9.99,
thumbnailUrl: 'https://placehold.it/180x180',
thumbnailAlt: 'Classic T-Shirt',
detailUrl: '/product/classic-t-shirt',
colors: [
{ id: 'red', imageUrl: 'https://placehold.it/30x30/ff0000/ffffff' },
{ id: 'blue', imageUrl: 'https://placehold.it/30x30/0066cc/ffffff' },
{ id: 'green', imageUrl: 'https://placehold.it/30x30/00cc66/ffffff' },
{ id: 'black', imageUrl: 'https://placehold.it/30x30/222222/ffffff' },
],
};
function App() {
return (
console.log('Selected color:', colorId)}
/>
);
}
*/