为游戏发布页添加客户端引导组件

- 优化工具栏布局
- 属性化客户端入口组件,支持按钮文案、样式及窄屏选项配置
This commit is contained in:
2026-09-30 16:18:31 +08:00
parent c25fd47d16
commit 688d3b103a
2 changed files with 47 additions and 11 deletions
@@ -1,4 +1,8 @@
import { getPlatformActionButtonClassName } from '@genarrative/shared/components';
import {
getPlatformActionButtonClassName,
type PlatformActionButtonSize,
type PlatformActionButtonTone,
} from '@genarrative/shared/components';
import { Download, Monitor } from 'lucide-react';
import { useEffect, useState } from 'react';
@@ -10,6 +14,16 @@ import { UnifiedModal } from '../common/UnifiedModal';
const DOWNLOAD_ERROR = '暂时无法获取最新版本,请稍后重试';
type ClientDownloadEntryProps = {
/** 按钮文案,默认「下载客户端」。 */
label?: string;
tone?: PlatformActionButtonTone;
size?: PlatformActionButtonSize;
/** 窄屏只留图标:平台顶栏默认开启,页面级引导入口传 false 保留完整文案。 */
iconOnlyOnNarrowScreens?: boolean;
className?: string;
};
type DownloadState =
| { status: 'loading' }
| { status: 'ready'; release: ClientDownloadResponse }
@@ -22,7 +36,13 @@ function downloadLabel(download: ClientDownloadResponse['downloads'][number]) {
return `macOS(${download.architecture === 'aarch64' ? 'Apple Silicon' : 'Intel'})`;
}
export function ClientDownloadEntry() {
export function ClientDownloadEntry({
label = '下载客户端',
tone = 'secondary',
size = 'sm',
iconOnlyOnNarrowScreens = true,
className,
}: ClientDownloadEntryProps = {}) {
const [open, setOpen] = useState(false);
const [attempt, setAttempt] = useState(0);
const [state, setState] = useState<DownloadState>({ status: 'loading' });
@@ -72,19 +92,31 @@ export function ClientDownloadEntry() {
return (
<>
<PlatformActionButton
tone="secondary"
size="sm"
tone={tone}
size={size}
shape="pill"
aria-label="下载客户端"
title="下载客户端"
className="min-h-11 shrink-0 gap-0 whitespace-nowrap max-sm:h-11 max-sm:w-11 max-sm:px-0 sm:gap-2 sm:px-4"
aria-label={label}
title={label}
className={[
'shrink-0 whitespace-nowrap',
iconOnlyOnNarrowScreens
? 'min-h-11 gap-0 max-sm:h-11 max-sm:w-11 max-sm:px-0 sm:gap-2 sm:px-4'
: 'gap-2',
className,
]
.filter(Boolean)
.join(' ')}
onClick={() => {
setState({ status: 'loading' });
setOpen(true);
}}
>
<Download className="h-4 w-4 shrink-0" aria-hidden="true" />
<span className="hidden sm:inline">下载客户端</span>
<span
className={iconOnlyOnNarrowScreens ? 'hidden sm:inline' : undefined}
>
{label}
</span>
</PlatformActionButton>
<UnifiedModal
open={open}
@@ -29,6 +29,7 @@ import {
resolveGamePublishImagePreview,
uploadGamePublishImageAsset,
} from './gamePublishAssets';
import { GamePublishClientGuide } from './GamePublishClientGuide';
import {
clearPublishDraft,
type GamePublishDraft,
@@ -711,12 +712,12 @@ export function GamePublishPage({
<button type="button" className="game-back-button" onClick={onBack}>
<ArrowLeft /> 返回
</button>
<div className="game-toolbar">
<div className="game-toolbar__title">
<div className="game-toolbar [flex-wrap:nowrap] max-[720px]:[flex-wrap:wrap]">
<div className="game-toolbar__title [min-width:0]">
<span className="game-eyebrow">
{updateGameId ? '发布新版本' : '发布游戏'}
</span>
<h2>
<h2 className="[white-space:nowrap] max-[720px]:[white-space:normal]">
{updateGameId
? updateContext
? `为《${updateContext.title}》发布 v${updateContext.versionNumber + 1}`
@@ -724,6 +725,9 @@ export function GamePublishPage({
: '上传可在线游玩的网页游戏'}
</h2>
</div>
{!updateGameId ? (
<GamePublishClientGuide className="ml-auto max-[720px]:ml-0" />
) : null}
</div>
{error ? (