新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
|
|
import { PlatformMediaFrame } from './PlatformMediaFrame';
|
|
|
|
type PlatformMediaTileGridColumns = 'five' | 'six';
|
|
type PlatformMediaTileGridGap = 'xs' | 'sm';
|
|
type PlatformMediaTileGridAspect = 'auto' | 'square';
|
|
type PlatformMediaTileSurface = 'white' | 'slate' | 'bare';
|
|
type PlatformMediaTileGridSurface = 'none' | 'soft';
|
|
|
|
export type PlatformMediaTileGridItem = {
|
|
id: string;
|
|
src?: string | null;
|
|
alt?: string;
|
|
refreshKey?: string | number | null;
|
|
fallbackLabel?: string;
|
|
fallbackContent?: ReactNode;
|
|
testId?: string;
|
|
className?: string;
|
|
imageClassName?: string;
|
|
fallbackClassName?: string;
|
|
};
|
|
|
|
type PlatformMediaTileGridProps = {
|
|
items: PlatformMediaTileGridItem[];
|
|
columns?: PlatformMediaTileGridColumns;
|
|
gap?: PlatformMediaTileGridGap;
|
|
aspect?: PlatformMediaTileGridAspect;
|
|
surface?: PlatformMediaTileGridSurface;
|
|
tileSurface?: PlatformMediaTileSurface;
|
|
fallbackLabel?: string;
|
|
imageClassName?: string;
|
|
fallbackClassName?: string;
|
|
className?: string;
|
|
tileClassName?: string;
|
|
};
|
|
|
|
const PLATFORM_MEDIA_TILE_GRID_COLUMNS_CLASS: Record<
|
|
PlatformMediaTileGridColumns,
|
|
string
|
|
> = {
|
|
five: 'grid-cols-5',
|
|
six: 'grid-cols-6',
|
|
};
|
|
|
|
const PLATFORM_MEDIA_TILE_GRID_GAP_CLASS: Record<
|
|
PlatformMediaTileGridGap,
|
|
string
|
|
> = {
|
|
sm: 'gap-1.5',
|
|
xs: 'gap-1',
|
|
};
|
|
|
|
const PLATFORM_MEDIA_TILE_GRID_SURFACE_CLASS: Record<
|
|
PlatformMediaTileGridSurface,
|
|
string
|
|
> = {
|
|
none: '',
|
|
soft: 'bg-white/78 p-2',
|
|
};
|
|
|
|
const PLATFORM_MEDIA_TILE_SURFACE_CLASS: Record<
|
|
PlatformMediaTileSurface,
|
|
string
|
|
> = {
|
|
bare: 'border border-white/80',
|
|
slate: 'border border-white/80 bg-slate-50',
|
|
white: 'border border-white/80 bg-white shadow-sm',
|
|
};
|
|
|
|
/**
|
|
* 平台媒体缩略格网格。
|
|
* 统一承接结果页里同尺寸素材 tile 的网格、圆角、边框和图片/fallback 框。
|
|
*/
|
|
export function PlatformMediaTileGrid({
|
|
items,
|
|
columns = 'six',
|
|
gap = 'sm',
|
|
aspect = 'auto',
|
|
surface = 'none',
|
|
tileSurface = 'white',
|
|
fallbackLabel = '素材',
|
|
imageClassName = 'h-full w-full object-cover',
|
|
fallbackClassName = 'tracking-normal text-[var(--platform-text-soft)]',
|
|
className,
|
|
tileClassName,
|
|
}: PlatformMediaTileGridProps) {
|
|
return (
|
|
<div
|
|
className={[
|
|
'platform-media-tile-grid grid',
|
|
PLATFORM_MEDIA_TILE_GRID_COLUMNS_CLASS[columns],
|
|
PLATFORM_MEDIA_TILE_GRID_GAP_CLASS[gap],
|
|
PLATFORM_MEDIA_TILE_GRID_SURFACE_CLASS[surface],
|
|
aspect === 'square' ? 'aspect-[1/1]' : '',
|
|
className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
>
|
|
{items.map((item) => (
|
|
<PlatformMediaFrame
|
|
key={item.id}
|
|
src={item.src}
|
|
alt={item.alt ?? ''}
|
|
refreshKey={item.refreshKey}
|
|
fallbackLabel={item.fallbackLabel ?? fallbackLabel}
|
|
fallbackContent={item.fallbackContent}
|
|
aspect="square"
|
|
surface="none"
|
|
data-testid={item.testId}
|
|
imageClassName={item.imageClassName ?? imageClassName}
|
|
fallbackClassName={item.fallbackClassName ?? fallbackClassName}
|
|
className={[
|
|
'platform-media-tile-grid__item min-h-0 rounded-[0.45rem]',
|
|
PLATFORM_MEDIA_TILE_SURFACE_CLASS[tileSurface],
|
|
tileClassName,
|
|
item.className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|