新增 PlatformToolModalShell 承接白底工具弹窗壳层和固定可访问名称 新增 PlatformSegmentedTabPresets 沉淀频道下划线、创作 pill rail 与二列 option segment 迁移拼图、抓大鹅、历史素材弹窗和首页 / 作品架 / 充值切换的重复组件写法 同步 PlatformUiKit 文档和 Hermes 决策记录
183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
import {
|
||
PlatformSegmentedTabs,
|
||
type PlatformSegmentedTabItem,
|
||
} from './PlatformSegmentedTabs';
|
||
|
||
type PlatformSegmentedTabPresetProps<TId extends string> = {
|
||
items: readonly PlatformSegmentedTabItem<TId>[];
|
||
activeId: TId;
|
||
onChange: (id: TId) => void;
|
||
ariaLabel?: string;
|
||
className?: string;
|
||
};
|
||
|
||
export type PlatformUnderlineTabRailVariant = 'channel' | 'ranking';
|
||
|
||
const PLATFORM_UNDERLINE_TAB_RAIL_CLASS: Record<
|
||
PlatformUnderlineTabRailVariant,
|
||
string
|
||
> = {
|
||
channel: 'platform-mobile-home-channelbar pb-1',
|
||
ranking: 'platform-ranking-tabs pb-1',
|
||
};
|
||
|
||
const PLATFORM_UNDERLINE_TAB_ITEM_CLASS: Record<
|
||
PlatformUnderlineTabRailVariant,
|
||
{ base: string; active: string }
|
||
> = {
|
||
channel: {
|
||
base: 'platform-mobile-home-channel shrink-0 !min-h-8 !rounded-none !border-0 !bg-transparent !px-0 !shadow-none hover:!bg-transparent',
|
||
active: 'platform-mobile-home-channel--active',
|
||
},
|
||
ranking: {
|
||
base: 'platform-ranking-tab shrink-0 !min-h-[2.35rem] !rounded-none !border-0 !bg-transparent !px-[0.15rem] !shadow-none hover:!bg-transparent',
|
||
active: 'platform-ranking-tab--active',
|
||
},
|
||
};
|
||
|
||
export type PlatformOptionSegmentVariant = 'categoryFilter' | 'profile';
|
||
|
||
const PLATFORM_OPTION_SEGMENT_CLASS: Record<
|
||
PlatformOptionSegmentVariant,
|
||
{
|
||
rail: string;
|
||
active: string;
|
||
idle: string;
|
||
}
|
||
> = {
|
||
categoryFilter: {
|
||
rail: 'platform-category-filter-dialog__options',
|
||
active:
|
||
'platform-category-filter-dialog__option--active !border-[var(--platform-cool-border)] !bg-[var(--platform-cool-bg)] !text-[var(--platform-cool-text)]',
|
||
idle:
|
||
'platform-category-filter-dialog__option !min-h-[2.35rem] !rounded-[0.78rem] !border !border-[var(--platform-subpanel-border)] !bg-[var(--platform-subpanel-fill)] !px-3 !text-[0.88rem] !font-black !text-[var(--platform-text-base)] !shadow-none hover:!bg-[var(--platform-subpanel-fill)]',
|
||
},
|
||
profile: {
|
||
rail: '',
|
||
active:
|
||
'!border-[var(--platform-cool-border)] !bg-[var(--platform-cool-bg)] !text-[var(--platform-cool-text)]',
|
||
idle:
|
||
'w-full !min-h-[2.25rem] !rounded-[0.78rem] !border !border-[var(--platform-subpanel-border)] !bg-[rgba(255,255,255,0.04)] !px-3 !text-sm !font-extrabold !text-[var(--platform-text-base)] !shadow-none hover:!bg-[rgba(255,255,255,0.08)]',
|
||
},
|
||
};
|
||
|
||
/**
|
||
* 统一首页、作品架这类横向文字 rail,只沉淀稳定的滚动与下划线皮肤。
|
||
*/
|
||
export function PlatformUnderlineTabRail<TId extends string>({
|
||
items,
|
||
activeId,
|
||
onChange,
|
||
ariaLabel,
|
||
className,
|
||
variant = 'channel',
|
||
}: PlatformSegmentedTabPresetProps<TId> & {
|
||
variant?: PlatformUnderlineTabRailVariant;
|
||
}) {
|
||
return (
|
||
<PlatformSegmentedTabs
|
||
items={items}
|
||
activeId={activeId}
|
||
onChange={onChange}
|
||
layout="scroll"
|
||
gap="md"
|
||
frame="bare"
|
||
surface="transparent"
|
||
size="sm"
|
||
tone="neutral"
|
||
semantics="tabs"
|
||
ariaLabel={ariaLabel}
|
||
className={[PLATFORM_UNDERLINE_TAB_RAIL_CLASS[variant], className]
|
||
.filter(Boolean)
|
||
.join(' ')}
|
||
itemClassName={(_, active) =>
|
||
[
|
||
PLATFORM_UNDERLINE_TAB_ITEM_CLASS[variant].base,
|
||
active ? PLATFORM_UNDERLINE_TAB_ITEM_CLASS[variant].active : null,
|
||
]
|
||
.filter(Boolean)
|
||
.join(' ')
|
||
}
|
||
/>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 统一二列按钮式切换,只负责稳定的视觉 preset,不承接业务语义。
|
||
*/
|
||
export function PlatformOptionSegment<TId extends string>({
|
||
items,
|
||
activeId,
|
||
onChange,
|
||
ariaLabel,
|
||
className,
|
||
variant,
|
||
}: PlatformSegmentedTabPresetProps<TId> & {
|
||
variant: PlatformOptionSegmentVariant;
|
||
}) {
|
||
return (
|
||
<PlatformSegmentedTabs
|
||
items={items}
|
||
activeId={activeId}
|
||
onChange={onChange}
|
||
columns="two"
|
||
layout="grid"
|
||
gap={variant === 'profile' ? 'sm' : 'md'}
|
||
frame="bare"
|
||
surface="transparent"
|
||
size="sm"
|
||
semantics={variant === 'profile' ? 'tabs' : 'segment'}
|
||
ariaLabel={ariaLabel}
|
||
className={[PLATFORM_OPTION_SEGMENT_CLASS[variant].rail, className]
|
||
.filter(Boolean)
|
||
.join(' ')}
|
||
itemClassName={(_, active) =>
|
||
[
|
||
PLATFORM_OPTION_SEGMENT_CLASS[variant].idle,
|
||
active ? PLATFORM_OPTION_SEGMENT_CLASS[variant].active : null,
|
||
]
|
||
.filter(Boolean)
|
||
.join(' ')
|
||
}
|
||
/>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 创作入口使用的轻量 pill rail,保留 snap 与下划线的组合语义。
|
||
*/
|
||
export function PlatformPillTabRail<TId extends string>({
|
||
items,
|
||
activeId,
|
||
onChange,
|
||
ariaLabel,
|
||
className,
|
||
}: PlatformSegmentedTabPresetProps<TId>) {
|
||
return (
|
||
<PlatformSegmentedTabs
|
||
items={items}
|
||
activeId={activeId}
|
||
onChange={onChange}
|
||
layout="scroll"
|
||
gap="md"
|
||
frame="bare"
|
||
surface="transparent"
|
||
size="sm"
|
||
tone="neutral"
|
||
semantics="tabs"
|
||
ariaLabel={ariaLabel}
|
||
className={['-mx-0.5 snap-x px-0.5 pb-1 scroll-px-2 sm:!gap-3', className]
|
||
.filter(Boolean)
|
||
.join(' ')}
|
||
itemClassName={(_, active) =>
|
||
[
|
||
"relative shrink-0 snap-start !min-h-8 !rounded-full !border-0 !bg-transparent !px-2.5 !text-xs !font-black !shadow-none sm:!min-h-9 sm:!px-3.5 sm:!text-sm",
|
||
active
|
||
? "!text-[#6f2f21] after:absolute after:bottom-0 after:left-3 after:right-3 after:h-1 after:rounded-full after:bg-[#d9793f] after:content-['']"
|
||
: '!text-[#7a6558] hover:!bg-transparent hover:!text-[#6f2f21]',
|
||
].join(' ')
|
||
}
|
||
/>
|
||
);
|
||
}
|