expo-popcore-app/components/blocks/home/TemplateGrid.tsx

94 lines
2.4 KiB
TypeScript

import React, { useState, memo } from 'react'
import { View, StyleSheet, LayoutChangeEvent } from 'react-native'
import type { CategoryTemplate } from '@repo/sdk'
import { TemplateCard } from './TemplateCard'
export type Template = CategoryTemplate
export interface TemplateGridProps {
templates: CategoryTemplate[]
onTemplatePress: (id: string) => void
numColumns?: number
horizontalPadding?: number
cardGap?: number
}
/**
* 计算卡片宽度
* @param gridWidth 网格容器宽度
* @param horizontalPadding 水平内边距
* @param cardGap 卡片间距
* @param numColumns 列数
* @returns 卡片宽度
*/
export function calculateCardWidth(
gridWidth: number,
horizontalPadding: number,
cardGap: number,
numColumns: number
): number {
return (gridWidth - horizontalPadding * 2 - cardGap * (numColumns - 1)) / numColumns
}
const TemplateGridComponent: React.FC<TemplateGridProps> = ({
templates,
onTemplatePress,
numColumns = 3,
horizontalPadding = 16,
cardGap = 5,
}) => {
const [gridWidth, setGridWidth] = useState(0)
// 过滤掉没有 id 的模板
const validTemplates = templates.filter((template): template is CategoryTemplate & { id: string } =>
!!template.id
)
// 空数据时返回 null
if (!validTemplates || validTemplates.length === 0) {
return null
}
const handleLayout = (e: LayoutChangeEvent) => {
setGridWidth(e.nativeEvent.layout.width)
}
const cardWidth = calculateCardWidth(gridWidth, horizontalPadding, cardGap, numColumns)
return (
<View
style={[styles.gridContainer, { paddingHorizontal: horizontalPadding }]}
onLayout={handleLayout}
>
<View style={[styles.grid, { gap: cardGap }]}>
{validTemplates.map((template) => (
<TemplateCard
key={template.id}
id={template.id}
title={template.title}
previewUrl={template.previewUrl}
webpPreviewUrl={template.webpPreviewUrl}
coverImageUrl={template.coverImageUrl}
aspectRatio={template.aspectRatio}
cardWidth={cardWidth}
onPress={onTemplatePress}
testID={`template-card-${template.id}`}
/>
))}
</View>
</View>
)
}
export const TemplateGrid = memo(TemplateGridComponent)
const styles = StyleSheet.create({
gridContainer: {
flex: 1,
},
grid: {
flexDirection: 'row',
flexWrap: 'wrap',
},
})