100 lines
4.5 KiB
TypeScript
100 lines
4.5 KiB
TypeScript
import { ArrowRight } from 'lucide-react';
|
|
|
|
import { NEW_WORK_ENTRY_CONFIG } from '../../config/newWorkEntryConfig';
|
|
import {
|
|
getVisiblePlatformCreationTypes,
|
|
type PlatformCreationTypeId,
|
|
} from '../platform-entry/platformEntryCreationTypes';
|
|
|
|
type CustomWorldCreationStartCardProps = {
|
|
busy?: boolean;
|
|
error?: string | null;
|
|
onCreateType: (type: PlatformCreationTypeId) => void;
|
|
};
|
|
|
|
export function CustomWorldCreationStartCard({
|
|
busy = false,
|
|
error = null,
|
|
onCreateType,
|
|
}: CustomWorldCreationStartCardProps) {
|
|
// 创作首页首屏卡带与创作类型弹层保持同一份展示口径,
|
|
// 避免某个玩法只在其中一个入口被隐藏而出现状态漂移。
|
|
const visibleCreationTypes = getVisiblePlatformCreationTypes();
|
|
|
|
return (
|
|
// 移动端限制模块高度,模板入口改为横向滚动,避免挤占作品列表首屏空间。
|
|
<div className="platform-surface platform-surface--hero relative max-h-[33svh] overflow-hidden px-3 py-3 sm:max-h-none sm:px-5 sm:py-5 xl:px-5 xl:py-4">
|
|
<div className="absolute inset-0 bg-[var(--platform-hero-overlay-strong)]" />
|
|
<div className="relative z-10 space-y-2.5 sm:space-y-4 xl:space-y-3">
|
|
<div className="flex items-center justify-between gap-3 xl:items-end">
|
|
<div className="text-xl font-black leading-none text-white sm:text-3xl xl:text-2xl">
|
|
{NEW_WORK_ENTRY_CONFIG.startCard.title}
|
|
</div>
|
|
<div className="hidden text-sm leading-6 text-zinc-200/88 sm:block xl:text-xs xl:leading-5">
|
|
{NEW_WORK_ENTRY_CONFIG.startCard.description}
|
|
</div>
|
|
<span className="platform-pill platform-pill--neutral shrink-0 border-white/25 bg-white/14 px-2.5 text-xs text-white sm:hidden">
|
|
{busy
|
|
? NEW_WORK_ENTRY_CONFIG.startCard.busyBadge
|
|
: NEW_WORK_ENTRY_CONFIG.startCard.idleBadge}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="-mx-1 flex snap-x gap-2 overflow-x-auto px-1 pb-1 scrollbar-hide sm:mx-0 sm:grid sm:gap-3 sm:overflow-visible sm:px-0 sm:pb-0 sm:grid-cols-2 xl:grid-cols-6 xl:gap-2.5">
|
|
{visibleCreationTypes.map((item) => {
|
|
const disabled = item.locked || busy;
|
|
|
|
return (
|
|
<button
|
|
key={item.id}
|
|
type="button"
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
onCreateType(item.id);
|
|
}}
|
|
className={`platform-interactive-card relative flex min-h-[4rem] w-[11.25rem] shrink-0 snap-start flex-col overflow-hidden rounded-[1.15rem] border px-3 py-2.5 text-left transition sm:min-h-[8.5rem] sm:w-auto sm:rounded-[1.5rem] sm:px-4 sm:py-4 xl:min-h-[6.4rem] xl:px-3.5 xl:py-3 ${
|
|
item.locked
|
|
? 'cursor-not-allowed border-white/10 bg-white/8 text-zinc-300/70'
|
|
: 'border-white/18 bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.24),transparent_36%),linear-gradient(135deg,rgba(255,255,255,0.18),rgba(255,255,255,0.08))] text-white'
|
|
} ${busy && !item.locked ? 'opacity-70' : ''}`}
|
|
>
|
|
<div className="flex min-h-5 items-center justify-end gap-2 sm:items-start sm:gap-3">
|
|
{item.locked ? (
|
|
<span className="platform-pill platform-pill--neutral px-2.5 text-xs text-[var(--platform-text-soft)] sm:px-3 sm:text-sm">
|
|
{item.badge}
|
|
</span>
|
|
) : null}
|
|
{item.locked ? (
|
|
<span className="text-base leading-none text-white/40">·</span>
|
|
) : (
|
|
<ArrowRight className="h-4 w-4 text-white/80" />
|
|
)}
|
|
</div>
|
|
|
|
<div className="mt-auto pt-1.5 sm:pt-4 xl:pt-2">
|
|
<div className="truncate text-base font-black leading-tight text-inherit sm:text-lg xl:text-base">
|
|
{item.title}
|
|
</div>
|
|
<div
|
|
className={`mt-1 truncate text-xs sm:mt-2 sm:text-sm xl:mt-1 xl:text-xs ${
|
|
item.locked ? 'text-zinc-400' : 'text-zinc-200/82'
|
|
}`}
|
|
>
|
|
{item.subtitle}
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{error ? (
|
|
<div className="platform-banner platform-banner--danger rounded-[1rem] px-3 py-2 text-sm leading-5 sm:rounded-[1.25rem] sm:leading-6">
|
|
{error}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|