收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
89
src/components/common/PlatformIconButton.tsx
Normal file
89
src/components/common/PlatformIconButton.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import type {
|
||||
ButtonHTMLAttributes,
|
||||
LabelHTMLAttributes,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
|
||||
type PlatformIconButtonBaseProps = {
|
||||
label: string;
|
||||
icon: ReactNode;
|
||||
children?: ReactNode;
|
||||
variant?: 'platformIcon' | 'surfaceFloating' | 'darkMini';
|
||||
};
|
||||
|
||||
type PlatformIconButtonButtonProps = Omit<
|
||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
'aria-label' | 'children'
|
||||
> &
|
||||
PlatformIconButtonBaseProps & {
|
||||
asChild?: false;
|
||||
};
|
||||
|
||||
type PlatformIconButtonLabelProps = Omit<
|
||||
LabelHTMLAttributes<HTMLLabelElement>,
|
||||
'aria-label' | 'children'
|
||||
> &
|
||||
PlatformIconButtonBaseProps & {
|
||||
asChild: 'label';
|
||||
};
|
||||
|
||||
type PlatformIconButtonProps =
|
||||
| PlatformIconButtonButtonProps
|
||||
| PlatformIconButtonLabelProps;
|
||||
|
||||
/**
|
||||
* 平台通用图标动作按钮。
|
||||
* 统一承接纯图标动作、图标上传 label 和带短标签的浮动图标动作。
|
||||
*/
|
||||
export function PlatformIconButton({
|
||||
label,
|
||||
icon,
|
||||
children,
|
||||
variant = 'platformIcon',
|
||||
title,
|
||||
className,
|
||||
asChild,
|
||||
...actionProps
|
||||
}: PlatformIconButtonProps) {
|
||||
const variantClassName = {
|
||||
platformIcon: 'platform-icon-button',
|
||||
surfaceFloating:
|
||||
'inline-flex items-center justify-center rounded-full border border-white/80 bg-white/94 text-[var(--platform-text-strong)] shadow-sm backdrop-blur transition hover:text-[var(--platform-accent)] disabled:cursor-not-allowed disabled:opacity-55',
|
||||
darkMini:
|
||||
'inline-flex items-center justify-center rounded-full border border-white/16 bg-black/55 text-white transition-colors hover:bg-black/70 disabled:cursor-not-allowed disabled:opacity-55',
|
||||
}[variant];
|
||||
|
||||
const actionClassName = [variantClassName, className]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
if (asChild === 'label') {
|
||||
return (
|
||||
<label
|
||||
{...(actionProps as LabelHTMLAttributes<HTMLLabelElement>)}
|
||||
title={title}
|
||||
className={actionClassName}
|
||||
>
|
||||
<span className="sr-only">{label}</span>
|
||||
{icon}
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
const { type = 'button', ...buttonProps } =
|
||||
actionProps as ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
return (
|
||||
<button
|
||||
{...buttonProps}
|
||||
type={type}
|
||||
aria-label={label}
|
||||
title={title}
|
||||
className={actionClassName}
|
||||
>
|
||||
{icon}
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user