53 lines
1.3 KiB
TypeScript
53 lines
1.3 KiB
TypeScript
import type { CSSProperties, ReactNode } from 'react'
|
|
import styles from './Grid.module.css'
|
|
|
|
/**
|
|
* 网格:给「卡片列表」用的一致布局。
|
|
*
|
|
* 列数走 CSS 变量,断点收在组件里——页面不用再各写一份媒体查询。
|
|
* 默认窄屏退化:≤1100px 取一半(至少 2 列),≤720px 收成一列。
|
|
*/
|
|
export type GridGap = 'sm' | 'md' | 'lg'
|
|
|
|
export type GridProps = {
|
|
/** 宽屏列数 */
|
|
columns?: number
|
|
/** 中等屏列数,默认一半(至少 2) */
|
|
tabletColumns?: number
|
|
/** 窄屏列数,默认 1 */
|
|
mobileColumns?: number
|
|
gap?: GridGap
|
|
/** 用 ul 渲染(配合 li 列表项,保持语义) */
|
|
as?: 'div' | 'ul'
|
|
role?: string
|
|
className?: string
|
|
style?: CSSProperties
|
|
children?: ReactNode
|
|
}
|
|
|
|
export function Grid({
|
|
columns = 4,
|
|
tabletColumns,
|
|
mobileColumns = 1,
|
|
gap = 'md',
|
|
as: Tag = 'div',
|
|
role,
|
|
className,
|
|
style,
|
|
children,
|
|
}: GridProps) {
|
|
const vars: Record<string, string> = {
|
|
'--su-grid-cols': String(columns),
|
|
'--su-grid-cols-tablet': String(tabletColumns ?? Math.max(2, Math.ceil(columns / 2))),
|
|
'--su-grid-cols-mobile': String(mobileColumns),
|
|
}
|
|
|
|
const classes = [styles.root, styles[gap], className].filter(Boolean).join(' ')
|
|
|
|
return (
|
|
<Tag className={classes} style={{ ...vars, ...style }} role={role}>
|
|
{children}
|
|
</Tag>
|
|
)
|
|
}
|