收起首页项目操作

首页最近项目卡片改为只读展示。

刷新、清空、显示和移除操作保留在项目页。

更新启动器项目操作回归测试。
This commit is contained in:
AIGameCreator App
2026-07-08 11:21:56 +08:00
parent 18b834af36
commit b1cbda97b0
3 changed files with 50 additions and 72 deletions
+13 -36
View File
@@ -2301,16 +2301,6 @@ export function WorkspaceLauncher({
<p className="launcher-project-status">{status}</p>
</div>
<div className="launcher-project-list-actions">
<button
type="button"
disabled={recentWorkspaceRefreshing}
onClick={handleRecentWorkspaceRefresh}
>
{recentWorkspaceRefreshing ? '刷新中' : '刷新'}
</button>
<button type="button" onClick={handleRecentWorkspaceClear}>
</button>
<button
type="button"
onClick={() => setLauncherView('projects')}
@@ -2325,38 +2315,13 @@ export function WorkspaceLauncher({
className="launcher-project-card"
key={project.path}
>
<button
type="button"
<div
className="launcher-project-card-main"
disabled={!project.canOpen}
onClick={() => {
setProjectPath(project.path);
void openProject(project.path, 'open');
}}
>
<span>{project.name.slice(0, 2)}</span>
<strong>{project.name}</strong>
<small>{project.path}</small>
<small>{project.status}</small>
</button>
<div className="launcher-project-card-actions">
<button
type="button"
aria-label={`显示 ${project.path}`}
disabled={!project.canReveal}
onClick={() => {
void handleRevealProjectDirectory(project.path);
}}
>
</button>
<button
type="button"
aria-label={`移除 ${project.path}`}
onClick={() => handleRecentWorkspaceRemove(project.path)}
>
</button>
</div>
</article>
))}
@@ -2378,6 +2343,18 @@ export function WorkspaceLauncher({
<h1></h1>
<p>{recentWorkspaceRefreshing ? '正在检查项目状态' : status}</p>
</div>
<div className="launcher-project-list-actions">
<button
type="button"
disabled={recentWorkspaceRefreshing}
onClick={handleRecentWorkspaceRefresh}
>
{recentWorkspaceRefreshing ? '刷新中' : '刷新'}
</button>
<button type="button" onClick={handleRecentWorkspaceClear}>
</button>
</div>
</header>
<form className="launcher-project-form" onSubmit={handleSubmit}>
<label>
+1 -33
View File
@@ -536,12 +536,10 @@ textarea {
.launcher-project-card {
display: grid;
gap: 8px;
min-width: 0;
}
.launcher-project-card > div,
.launcher-project-card > button {
.launcher-project-card > div {
position: relative;
height: 116px;
overflow: hidden;
@@ -550,15 +548,6 @@ textarea {
background: #f7f7f7;
}
.launcher-project-card > button {
cursor: pointer;
}
.launcher-project-card > button:disabled {
cursor: default;
opacity: 0.62;
}
.launcher-project-card-main {
display: grid;
align-content: start;
@@ -599,27 +588,6 @@ textarea {
white-space: nowrap;
}
.launcher-project-card-actions {
display: flex;
gap: 6px;
}
.launcher-project-card-actions button {
flex: 1;
min-width: 0;
height: 28px;
border: 1px solid #d8dde5;
border-radius: 8px;
background: #fff;
color: #555;
font-size: 12px;
}
.launcher-project-card-actions button:disabled {
color: #aaa;
cursor: default;
}
.launcher-project-create > button {
display: grid;
border-style: dashed;
@@ -1109,6 +1109,16 @@ describe('AI 游戏创作 App 界面边界', () => {
expect(invoke).not.toHaveBeenCalledWith('inspect_local_project_directory', {
projectPath: 'relative-game',
});
expect(
screen.queryByRole('button', { name: '移除 /tmp/recent-one' }),
).toBeNull();
expect(
screen.queryByRole('button', { name: '显示 /tmp/recent-one' }),
).toBeNull();
expect(screen.queryByRole('button', { name: '刷新' })).toBeNull();
expect(screen.queryByRole('button', { name: '清空' })).toBeNull();
fireEvent.click(screen.getByRole('button', { name: '项目' }));
fireEvent.click(
screen.getByRole('button', { name: '移除 /tmp/recent-one' }),
);
@@ -1121,8 +1131,7 @@ describe('AI 游戏创作 App 界面边界', () => {
);
fireEvent.click(screen.getByRole('button', { name: '清空' }));
expect(screen.queryByLabelText('最近项目')).toBeNull();
expect(screen.getByText('欢迎使用 AI 游戏创作')).not.toBeNull();
expect(screen.getByText('暂无项目')).not.toBeNull();
expect(window.localStorage.length).toBe(0);
});
@@ -1157,6 +1166,10 @@ describe('AI 游戏创作 App 界面边界', () => {
renderLauncherAt('/?launcher');
expect(await screen.findByText('最近的项目')).not.toBeNull();
expect(
screen.queryByRole('button', { name: '显示 /tmp/recent-one' }),
).toBeNull();
fireEvent.click(screen.getByRole('button', { name: '项目' }));
fireEvent.click(
screen.getByRole('button', { name: '显示 /tmp/recent-one' }),
);
@@ -1298,6 +1311,16 @@ describe('AI 游戏创作 App 界面边界', () => {
expect(screen.getByText('检查失败')).not.toBeNull();
expect(screen.getByText('厨房突围')).not.toBeNull();
expect(screen.getByText('run: done · preview-running')).not.toBeNull();
expect(screen.getByText('missing-game').closest('button')).toBeNull();
expect(
screen.queryByRole('button', { name: '显示 /tmp/missing-game' }),
).toBeNull();
expect(
screen.queryByRole('button', { name: '移除 /tmp/missing-game' }),
).toBeNull();
fireEvent.click(screen.getByRole('button', { name: '项目' }));
const missingOpenButton = screen
.getByText('missing-game')
.closest('button') as HTMLButtonElement;
@@ -1413,6 +1436,11 @@ describe('AI 游戏创作 App 界面边界', () => {
renderLauncherAt('/?launcher');
expect(await screen.findByText('未找到')).not.toBeNull();
expect(screen.queryByRole('button', { name: '刷新' })).toBeNull();
expect(screen.getByText('refreshable-game').closest('button')).toBeNull();
fireEvent.click(screen.getByRole('button', { name: '项目' }));
expect(
(
screen
@@ -1492,6 +1520,11 @@ describe('AI 游戏创作 App 界面边界', () => {
renderLauncherAt('/?launcher');
expect(await screen.findByText('检查中')).not.toBeNull();
expect(
screen.queryByRole('button', { name: '移除 /tmp/slow-refresh-game' }),
).toBeNull();
fireEvent.click(screen.getByRole('button', { name: '项目' }));
fireEvent.click(
screen.getByRole('button', { name: '移除 /tmp/slow-refresh-game' }),
);
@@ -1512,7 +1545,7 @@ describe('AI 游戏创作 App 界面边界', () => {
expect(screen.queryByText('/tmp/slow-refresh-game')).toBeNull();
expect(screen.queryByText('慢速刷新旧项目')).toBeNull();
expect(screen.queryByText('run: done · late')).toBeNull();
expect(screen.getByText('欢迎使用 AI 游戏创作')).not.toBeNull();
expect(screen.getByText('暂无项目')).not.toBeNull();
});
it('keeps the typed project path when native directory picking is cancelled', async () => {