商品グリッドリストブロック
ListProductsGridコンポーネントは、ReactとTypeScriptで構築された商品表示用の完全にカスタマイズ可能でアクセシブルなグリッドレイアウトです。モダンなデザインパターン、柔軟なカスタマイズオプション、タイトル、アイテム、カード用の構成可能なサブコンポーネントを備えた完全な商品リスティングインターフェースを提供します。
🚀 インストール
npm install @nodeblocks/frontend-list-products-grid-block@0.1.2
📖 使用方法
import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
- 基本的な使用方法
- 高度な使用方法
function ProductsGridExample() {
const data: ComponentProps<typeof ListProductsGrid.Items.GridCard>[] = [
{
chips: [{ label: '新着' }],
tags: [{ icon: 'shopping_bag', label: 'カテゴリ 1' }],
subtitleImageUrl: '',
summary: 'これは何かの要約です',
imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(),
subtitle: '商品カードサブタイトル 1',
title: '商品カードタイトル 1',
linkProps: {
href: '/products/1',
onNavigate: () => console.log('商品1にナビゲート中')
}
},
{
chips: [{ label: '新着' }],
tags: [{ icon: 'shopping_bag', label: 'カテゴリ 1' }],
linkProps: { href: '/my/product/card2', onNavigate: () => {} },
imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(),
subtitle: '商品カードサブタイトル 2',
title: '商品カードタイトル 2',
},
{
chips: [{ label: '新着' }],
tags: [{ icon: 'shopping_bag', label: ['カテゴリ 1', 'カテゴリ 2'] }],
linkProps: { href: '/my/product/card3', onNavigate: () => {} },
imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(),
subtitle: '商品カードサブタイトル 3',
title: '商品カードタイトル 3',
},
];
return (
<ListProductsGrid
listProductsGridTitle="私たちの商品"
subtitle="注目アイテム"
className="custom-grid">
<ListProductsGrid.Title />
<ListProductsGrid.Items>
{data.map((props, i) => (
<ListProductsGrid.Items.GridCard key={i} {...props} />
))}
</ListProductsGrid.Items>
</ListProductsGrid>
);
}
function CustomProductsGrid() {
const categories = [
{
name: '電子機器',
icon: '💻',
products: [
{
title: 'ゲーミングノートPC',
price: '¥199,800',
rating: 4.8,
image: 'https://unsplash.it/300?random&electronics=1',
badge: 'ベストセラー'
},
{
title: 'ワイヤレスヘッドホン',
price: '¥49,800',
rating: 4.6,
image: 'https://unsplash.it/300?random&electronics=2',
badge: '新着'
}
]
},
{
name: 'ファッション',
icon: '👕',
products: [
{
title: 'デザイナージャケット',
price: '¥29,800',
rating: 4.9,
image: 'https://unsplash.it/300?random&fashion=1',
badge: 'トレンド'
},
{
title: 'プレミアムスニーカー',
price: '¥19,800',
rating: 4.7,
image: 'https://unsplash.it/300?random&fashion=2',
badge: '限定'
}
]
}
];
return (
<ListProductsGrid
listProductsGridTitle="商品カテゴリ"
subtitle="カテゴリ別ショッピング"
className="category-grid">
{({ defaultBlocks, defaultBlockOrder }) => ({
blocks: {
title: defaultBlocks.title,
// カテゴリベースレイアウトでアイテムセクションを完全オーバーライド
items: (
<div style={{
display: 'grid',
gap: '32px'
}}>
{categories.map((category, categoryIndex) => (
<div key={categoryIndex} style={{
background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
borderRadius: '20px',
padding: '32px',
color: 'white'
}}>
<div style={{
display: 'flex',
alignItems: 'center',
marginBottom: '24px',
gap: '16px'
}}>
<span style={{ fontSize: '32px' }}>{category.icon}</span>
<h2 style={{
fontSize: '28px',
fontWeight: 'bold',
margin: 0
}}>
{category.name}
</h2>
</div>
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
gap: '20px'
}}>
{category.products.map((product, productIndex) => (
<div key={productIndex} style={{
background: 'rgba(255,255,255,0.15)',
borderRadius: '16px',
padding: '20px',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255,255,255,0.2)',
transition: 'all 0.3s ease',
cursor: 'pointer'
}}
onMouseOver={(e) => {
e.currentTarget.style.transform = 'translateY(-8px)';
e.currentTarget.style.boxShadow = '0 20px 40px rgba(0,0,0,0.2)';
}}
onMouseOut={(e) => {
e.currentTarget.style.transform = 'translateY(0)';
e.currentTarget.style.boxShadow = 'none';
}}>
<div style={{
position: 'relative',
marginBottom: '16px',
borderRadius: '12px',
overflow: 'hidden',
height: '200px'
}}>
<img
src={product.image}
alt={product.title}
style={{
width: '100%',
height: '100%',
objectFit: 'cover'
}}
/>
<div style={{
position: 'absolute',
top: '12px',
right: '12px',
background: 'rgba(255,255,255,0.9)',
color: '#333',
padding: '6px 12px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '600'
}}>
{product.badge}
</div>
</div>
<h3 style={{
fontSize: '18px',
fontWeight: '600',
marginBottom: '8px',
margin: '0 0 8px 0'
}}>
{product.title}
</h3>
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '16px'
}}>
<span style={{
fontSize: '20px',
fontWeight: 'bold',
color: '#fff'
}}>
{product.price}
</span>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '4px'
}}>
<span>⭐</span>
<span style={{ fontSize: '14px' }}>
{product.rating}
</span>
</div>
</div>
<button style={{
width: '100%',
background: 'rgba(255,255,255,0.2)',
border: '1px solid rgba(255,255,255,0.3)',
borderRadius: '8px',
padding: '12px',
color: 'white',
fontSize: '14px',
fontWeight: '600',
cursor: 'pointer',
transition: 'all 0.3s ease'
}}
onMouseOver={(e) => {
e.target.style.background = 'rgba(255,255,255,0.3)';
}}
onMouseOut={(e) => {
e.target.style.background = 'rgba(255,255,255,0.2)';
}}>
カートに追加
</button>
</div>
))}
</div>
<div style={{
textAlign: 'center',
marginTop: '24px'
}}>
<button style={{
background: 'rgba(255,255,255,0.2)',
border: '2px solid rgba(255,255,255,0.3)',
borderRadius: '25px',
padding: '12px 32px',
color: 'white',
fontSize: '16px',
fontWeight: '600',
cursor: 'pointer',
backdropFilter: 'blur(10px)',
transition: 'all 0.3s ease'
}}
onMouseOver={(e) => {
e.target.style.background = 'rgba(255,255,255,0.3)';
e.target.style.transform = 'translateY(-2px)';
}}
onMouseOut={(e) => {
e.target.style.background = 'rgba(255,255,255,0.2)';
e.target.style.transform = 'translateY(0)';
}}>
すべての{category.name}を見る →
</button>
</div>
</div>
))}
</div>
)
},
blockOrder: ['title', 'items']
})}
</ListProductsGrid>
);
}
🔧 プロパティリファレンス
メインコンポーネントのプロパティ
メイン ListProductsGrid コンポーネントは、HTML div 要素のすべてのプロパティを継承し(children は除く、これはオーバーライドされる)、以下を追加します:
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
listProductsGridTitle | ReactNode | undefined | 商品リストのメインタイトル |
subtitle | string | undefined | メインタイトルの上に表示されるセカンダリタイトル |
className | string | undefined | グリッドコンテナスタイリング用の追加CSSクラス名 |
children | BlocksOverride | undefined | デフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント |
サブコンポーネント
ListProductsGridコンポーネントは複数のサブコンポーネントを提供します。すべてのサブコンポーネントは、メインコンポーネントのコンテキストからデフォルト値を受け取り、プロパティを通じてこれらの値をオーバーライドできます。
ListProductsGrid.Title
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
listProductsGridTitle | ReactNode | コンテキストから | メインタイトルとして表示するコンテンツ |
subtitle | string | コンテキストから | サブタイトルとして表示するコンテンツ |
direction | enum | "column" | アクションボタンのフレックス方向 |
alignItems | enum | "stretch" | コンテナ内のアイテムの整列 |
gapSize | enum | "S" | コンテナ内のアイテム間のギャップ |
children | ReactNode | デフォルトタイトルレイアウト | デフォルトタイトルレイアウトをオーバーライドするカスタムコンテンツ |
className | string | undefined | タイトルコンテナスタイリング用の追加CSSクラス名 |
ListProductsGrid.Items
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
direction | enum | "column" | アクションボタンのフレックス方向 |
alignItems | enum | "stretch" | コンテナ内のアイテムの整列 |
gapSize | enum | "S" | コンテナ内のアイテム間のギャップ |
children | ReactNode | デフォルトタイトルレイアウト | デフォルトアイテムカードレイアウトをオーバーライドするカスタムコンテンツ |
className | string | undefined | アイテムコンテナスタイリング用の追加CSSクラス名 |
ListProductsGrid.Items.GridCard
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
title | string | undefined | カードに表示されるメインタイトル |
subtitle | string | undefined | タイトル下に表示されるセカンダリテキスト |
summary | string | undefined | 簡潔な説明や要約テキスト |
imageUrl | string | undefined | カードに表示されるメイン画像のURL |
subtitleImageUrl | string | undefined | サブタイトル横に表示される小さな画像のURL |
chips | Array<{label: string}> | undefined | バッジとして表示するチップオブジェクトの配列 |
tags | Array<{icon: enum, label: string | string[]}> | undefined | アイコンとラベルを持つタグオブジェクトの配列 |
linkProps | {href: string, onNavigate: () => void} | undefined | カードをクリック可能にするナビゲーションプロパティ |
className | string | undefined | カードスタイリング用の追加CSSクラス名 |
children | ReactNode | undefined | カード内に表示するカスタムコンテンツ(デフォルトレイアウトをオーバーライド) |
🔧 TypeScript サポート
包括的な型定義による完全なTypeScriptサポート:
import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
import {ComponentProps} from 'react';
// デフォルトグリッドカードデータ構造
interface DefaultGridCardData {
title?: string;
subtitle?: string;
summary?: string;
imageUrl?: string;
subtitleImageUrl?: string;
chips?: Array<{label: string}>;
tags?: Array<{icon: string, label: string | string[]}>;
linkProps?: {href: string, onNavigate: () => void};
}
// カスタムフィールドで拡張
interface CustomGridCardData extends DefaultGridCardData {
category?: string;
price?: number;
rating?: number;
customField?: string;
}
const MyProductsGrid = () => {
const products: ComponentProps<typeof ListProductsGrid.Items.GridCard>[] = [
{
title: '商品 1',
subtitle: 'プレミアム品質',
summary: 'これは商品1の詳細説明です',
imageUrl: 'https://example.com/product1.jpg',
chips: [{ label: '新着' }, { label: '注目' }],
tags: [
{ icon: 'shopping_bag', label: '電子機器' },
{ icon: 'star', label: ['ベストセラー', '高評価'] }
],
linkProps: {
href: '/products/1',
onNavigate: () => console.log('商品1にナビゲート中')
}
},
// ... その他の商品
];
return (
<ListProductsGrid
listProductsGridTitle="私たちの商品"
subtitle="注目コレクション"
className="custom-grid">
<ListProductsGrid.Title />
<ListProductsGrid.Items>
{products.map((props, index) => (
<ListProductsGrid.Items.GridCard key={index} {...props} />
))}
</ListProductsGrid.Items>
</ListProductsGrid>
);
};
React、TypeScript、モダンなウェブ標準を使用して❤️で構築されました。