Files
Genarrative/packages/shared/src/components/PlatformStatGrid.tsx
T
kdletters c5200c7d45
Project CI / Backend tests (push) Successful in 8m31s
Project CI / Repository checks (push) Successful in 14m14s
Project CI / Frontend tests (push) Successful in 13m2s
Project CI / Native shell tests (push) Successful in 21m30s
补齐共享 UI 组件库与展示页交互 (#202)
## 变更内容

- 新增基于 shadcn open-code 模式的共享 UI canonical 组件、样式与导出。
- 新增 `/components` 共享组件展示页,并覆盖平台组件、Token、状态和移动端布局。
- 补齐平台展示页的筛选、排序、上传预览、标签、开关和异步状态交互。
- 修复排序导致预览主题变化、筛选弹窗误关闭和入口状态不更新的问题。
- 同步网站与客户端构建别名、依赖、路由测试和项目文档。

## 验证

- `npm run test -- src/components/shared-components/SharedComponentsShowcasePage.test.tsx`
- `npm run typecheck`
- `npm run check:encoding`
- `npm run build:raw`
- `git diff --check`
- pre-push 门禁通过

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/202
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
2026-08-31 14:10:44 +08:00

159 lines
3.9 KiB
TypeScript

import type { ReactNode } from 'react';
export type PlatformStatGridColumns = 'two' | 'three' | 'four' | 'twoToFour';
export type PlatformStatGridDensity = 'compact' | 'default';
export type PlatformStatGridOrder = 'valueFirst' | 'labelFirst';
export type PlatformStatGridSurface = 'soft' | 'plain';
export type PlatformStatGridTextAlign = 'left' | 'center';
export type PlatformStatGridItem = {
label?: ReactNode;
value: ReactNode;
key?: string;
};
export 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>
);
}