新增 PlatformDarkModalFooter 统一 dark modal footer 的布局壳 接入 NPC 弹窗、选择定制弹窗、任务更新弹层与物品详情 footer 补充组件级与弹窗集成测试并更新收口计划和共享决策记录
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
|
|
type PlatformDarkModalFooterLayout = 'actions' | 'content';
|
|
type PlatformDarkModalFooterPadding = 'compact' | 'roomy' | 'bottom';
|
|
type PlatformDarkModalFooterGap = 'sm' | 'md';
|
|
type PlatformDarkModalFooterAlign = 'start' | 'center' | 'end' | 'between';
|
|
|
|
type PlatformDarkModalFooterProps = ComponentPropsWithoutRef<'div'> & {
|
|
children: ReactNode;
|
|
bordered?: boolean;
|
|
layout?: PlatformDarkModalFooterLayout;
|
|
padding?: PlatformDarkModalFooterPadding;
|
|
gap?: PlatformDarkModalFooterGap;
|
|
wrap?: boolean;
|
|
align?: PlatformDarkModalFooterAlign;
|
|
contentClassName?: string;
|
|
};
|
|
|
|
const PADDING_CLASS: Record<PlatformDarkModalFooterPadding, string> = {
|
|
compact: 'px-4 py-3 sm:px-5 sm:py-4',
|
|
roomy: 'px-5 py-4',
|
|
bottom: 'px-5 pb-5',
|
|
};
|
|
|
|
const GAP_CLASS: Record<PlatformDarkModalFooterGap, string> = {
|
|
sm: 'gap-2',
|
|
md: 'gap-3',
|
|
};
|
|
|
|
const ALIGN_CLASS: Record<PlatformDarkModalFooterAlign, string> = {
|
|
start: 'justify-start',
|
|
center: 'justify-center',
|
|
end: 'justify-end',
|
|
between: 'justify-between',
|
|
};
|
|
|
|
/**
|
|
* 暗色 / 像素弹层底部 footer 骨架。
|
|
* 统一承接 border、padding 和常见的动作按钮排布,避免业务页重复手写同一套 chrome。
|
|
*/
|
|
export function PlatformDarkModalFooter({
|
|
children,
|
|
bordered = true,
|
|
layout = 'actions',
|
|
padding = 'compact',
|
|
gap = 'md',
|
|
wrap = false,
|
|
align = 'end',
|
|
className,
|
|
contentClassName,
|
|
...props
|
|
}: PlatformDarkModalFooterProps) {
|
|
const frameClassName = [
|
|
'platform-dark-modal-footer',
|
|
bordered ? 'border-t border-white/10' : null,
|
|
PADDING_CLASS[padding],
|
|
className ?? null,
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
|
|
if (layout === 'content') {
|
|
return (
|
|
<div className={frameClassName} {...props}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const actionsClassName = [
|
|
'platform-dark-modal-footer__actions',
|
|
'flex items-center',
|
|
ALIGN_CLASS[align],
|
|
GAP_CLASS[gap],
|
|
wrap ? 'flex-wrap' : null,
|
|
contentClassName ?? null,
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
|
|
return (
|
|
<div className={frameClassName} {...props}>
|
|
<div className={actionsClassName}>{children}</div>
|
|
</div>
|
|
);
|
|
}
|