Files
Genarrative/src/components/common/PlatformStatGrid.tsx
kdletters 1ad25e30f8 收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件
迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome
补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
2026-06-10 10:24:18 +08:00

159 lines
3.8 KiB
TypeScript

import type { ReactNode } from 'react';
type PlatformStatGridColumns = 'two' | 'three' | 'four' | 'twoToFour';
type PlatformStatGridDensity = 'compact' | 'default';
type PlatformStatGridOrder = 'valueFirst' | 'labelFirst';
type PlatformStatGridSurface = 'soft' | 'plain';
type PlatformStatGridTextAlign = 'left' | 'center';
export type PlatformStatGridItem = {
label?: ReactNode;
value: ReactNode;
key?: string;
};
type PlatformStatGridProps = {
items: readonly PlatformStatGridItem[];
columns?: PlatformStatGridColumns;
density?: PlatformStatGridDensity;
order?: PlatformStatGridOrder;
surface?: PlatformStatGridSurface;
textAlign?: PlatformStatGridTextAlign;
className?: string;
itemClassName?:
| string
| ((item: PlatformStatGridItem, index: number) => string | null);
};
const PLATFORM_STAT_GRID_COLUMNS_CLASS: Record<
PlatformStatGridColumns,
string
> = {
two: 'grid-cols-2',
three: 'grid-cols-3',
four: 'grid-cols-4',
twoToFour: 'grid-cols-2 sm:grid-cols-4',
};
const PLATFORM_STAT_GRID_DENSITY_CLASS: Record<
PlatformStatGridDensity,
{ item: string; value: string; label: string }
> = {
compact: {
item: 'rounded-[1rem] px-2 py-2',
value: 'text-sm font-black',
label: 'mt-1 text-[0.68rem] font-bold tracking-[0.14em]',
},
default: {
item: 'rounded-[1rem] px-3 py-3',
value: 'text-lg font-black',
label: 'mt-1 text-[11px] font-bold tracking-[0.14em]',
},
};
const PLATFORM_STAT_GRID_SURFACE_CLASS: Record<
PlatformStatGridSurface,
string
> = {
soft: 'bg-white/76',
plain: 'border border-[var(--platform-subpanel-border)] bg-white/68',
};
const PLATFORM_STAT_GRID_TEXT_ALIGN_CLASS: Record<
PlatformStatGridTextAlign,
string
> = {
left: 'text-left',
center: 'text-center',
};
/**
* 平台统计小卡网格。
* 统一承接结果页里的“数值 / 标签”或轻量状态 chip 布局。
*/
export function PlatformStatGrid({
items,
columns = 'three',
density = 'default',
order = 'valueFirst',
surface = 'soft',
textAlign = 'center',
className,
itemClassName,
}: PlatformStatGridProps) {
const densityClass = PLATFORM_STAT_GRID_DENSITY_CLASS[density];
return (
<div
className={[
'grid gap-2',
PLATFORM_STAT_GRID_COLUMNS_CLASS[columns],
PLATFORM_STAT_GRID_TEXT_ALIGN_CLASS[textAlign],
className,
]
.filter(Boolean)
.join(' ')}
>
{items.map((item, index) => {
const extraClassName =
typeof itemClassName === 'function'
? itemClassName(item, index)
: itemClassName;
const key =
item.key ??
(typeof item.label === 'string'
? item.label
: typeof item.value === 'string'
? item.value
: index);
const valueNode = (
<div
className={[
densityClass.value,
'text-[var(--platform-text-strong)]',
].join(' ')}
>
{item.value}
</div>
);
const labelNode = item.label ? (
<div
className={[
densityClass.label,
'text-[var(--platform-text-soft)]',
].join(' ')}
>
{item.label}
</div>
) : null;
return (
<div
key={key}
className={[
densityClass.item,
PLATFORM_STAT_GRID_SURFACE_CLASS[surface],
extraClassName,
]
.filter(Boolean)
.join(' ')}
>
{order === 'labelFirst' ? (
<>
{labelNode}
{valueNode}
</>
) : (
<>
{valueNode}
{labelNode}
</>
)}
</div>
);
})}
</div>
);
}