Files
Genarrative/src/components/common/PlatformSegmentedTabPresets.tsx
kdletters ffcffef6d2 继续收口工具弹窗与分段切换预设
新增 PlatformToolModalShell 承接白底工具弹窗壳层和固定可访问名称

新增 PlatformSegmentedTabPresets 沉淀频道下划线、创作 pill rail 与二列 option segment

迁移拼图、抓大鹅、历史素材弹窗和首页 / 作品架 / 充值切换的重复组件写法

同步 PlatformUiKit 文档和 Hermes 决策记录
2026-06-11 16:32:56 +08:00

183 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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(' ')
}
/>
);
}