import { ImagePlus } from 'lucide-react'; import type { ButtonHTMLAttributes, LabelHTMLAttributes, ReactNode, } from 'react'; type PlatformUploadTileBaseProps = { label: ReactNode; hint?: ReactNode; icon?: ReactNode; disabled?: boolean; showLabel?: boolean; size?: 'square' | 'compact' | 'panel'; surface?: 'platform' | 'editorDark'; }; type PlatformUploadTileButtonProps = Omit< ButtonHTMLAttributes, 'children' | 'disabled' > & PlatformUploadTileBaseProps & { asChild?: false; }; type PlatformUploadTileLabelProps = Omit< LabelHTMLAttributes, 'children' > & PlatformUploadTileBaseProps & { asChild: 'label'; }; type PlatformUploadTileProps = | PlatformUploadTileButtonProps | PlatformUploadTileLabelProps; function getPlatformUploadTileClassName( size: 'square' | 'compact' | 'panel', surface: 'platform' | 'editorDark', className?: string, disabled?: boolean, ) { const surfaceClassName = { platform: 'border-[var(--platform-subpanel-border)] bg-[var(--platform-input-fill)] text-[var(--platform-text-soft)] hover:border-[var(--platform-surface-hover-border)] hover:text-[var(--platform-text-strong)]', editorDark: 'border-white/12 bg-black/20 text-zinc-300 hover:border-sky-300/45 hover:bg-white/8 hover:text-white', }[surface]; const sizeClassName = { square: 'h-[5.75rem] w-[5.75rem] items-center text-center', compact: 'h-12 w-full items-center text-center', panel: 'min-h-[7rem] w-full items-start px-4 py-4 text-left', }[size]; return [ 'flex flex-col justify-center rounded-xl border border-dashed transition', surfaceClassName, sizeClassName, disabled ? 'cursor-not-allowed opacity-55' : 'cursor-pointer', className, ] .filter(Boolean) .join(' '); } /** * 平台通用上传方块。 * 统一承载图片 / 附件上传入口的虚线方块、图标、主副文案和可访问语义。 */ export function PlatformUploadTile({ label, hint, icon = , disabled = false, showLabel = true, size = 'square', surface = 'platform', className, asChild, ...actionProps }: PlatformUploadTileProps) { const tileClassName = getPlatformUploadTileClassName( size, surface, className, disabled, ); const hasIcon = Boolean(icon); const labelClassName = size === 'panel' ? [hasIcon ? 'mt-2' : null, 'text-[11px] font-bold tracking-[0.14em]'] .filter(Boolean) .join(' ') : [hasIcon ? 'mt-2' : null, 'text-xs font-medium'] .filter(Boolean) .join(' '); const hintClassName = size === 'panel' ? 'mt-2 text-xs leading-5 opacity-80' : 'mt-0.5 text-[11px] opacity-80'; const content = ( <> {hasIcon ? icon : null} {label} {hint ? {hint} : null} ); if (asChild === 'label') { const { onClick, ...labelProps } = actionProps as LabelHTMLAttributes; return ( ); } const { type = 'button', ...buttonProps } = actionProps as ButtonHTMLAttributes; return ( ); }