调整 Agent 对话栏 Logo 与工作台布局 #183
@@ -307,6 +307,7 @@ export function WorkspaceLauncherShell({
|
||||
preview={activeProjectPreview}
|
||||
agentRuntimeSummaries={activeProjectAgentRuntimeSummaries}
|
||||
agentResults={activeProjectAgentResults}
|
||||
walletEntry={<AccountWalletBar controller={accountWallet} />}
|
||||
onPlay={() =>
|
||||
requestCurrentProjectPlay(currentProjectContext.projectPath)
|
||||
}
|
||||
|
||||
@@ -4923,11 +4923,14 @@ iframe.preview-frame {
|
||||
|
||||
/* GameAgent V1.0 project workbench */
|
||||
.game-project-workbench {
|
||||
width: calc(100vw - 72px);
|
||||
--game-workbench-stage-fill: #fffdfa;
|
||||
--game-workbench-agent-fill: #fbf7f2;
|
||||
width: calc(100vw - var(--launcher-sidebar-width));
|
||||
max-width: none;
|
||||
min-height: 0;
|
||||
gap: 10px;
|
||||
padding: 72px 8px 8px;
|
||||
gap: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
color: var(--platform-text-base);
|
||||
}
|
||||
@@ -4941,7 +4944,7 @@ iframe.preview-frame {
|
||||
z-index: 0;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(360px, 0.36fr);
|
||||
gap: 10px;
|
||||
gap: 0;
|
||||
height: clamp(560px, calc(100dvh - 206px), 780px);
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
@@ -4951,21 +4954,27 @@ iframe.preview-frame {
|
||||
.game-workbench-chat {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--platform-desktop-panel-border);
|
||||
border-radius: 16px;
|
||||
background: var(--platform-desktop-panel-fill);
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
border-left: 1px solid var(--platform-line-soft);
|
||||
background: var(--game-workbench-agent-fill);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.game-workbench-stage {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-rows: auto auto minmax(0, 1fr);
|
||||
box-shadow: var(--platform-panel-shadow);
|
||||
border-left: 0;
|
||||
background: var(--game-workbench-stage-fill);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.game-workbench-chat {
|
||||
border-color: var(--platform-line-soft);
|
||||
box-shadow: var(--platform-nav-active-shadow);
|
||||
.game-workbench-editor-shell {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: var(--game-workbench-stage-fill);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.game-workbench-stage[data-resource-view-state^='resources.asset-canvas'] {
|
||||
@@ -4985,8 +4994,7 @@ iframe.preview-frame {
|
||||
gap: 12px;
|
||||
min-height: 48px;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--platform-line-soft);
|
||||
background: var(--platform-desktop-topbar-fill);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.game-workbench-tabs,
|
||||
@@ -5004,6 +5012,27 @@ iframe.preview-frame {
|
||||
background: var(--platform-nav-fill);
|
||||
}
|
||||
|
||||
.game-resource-sort-tabs {
|
||||
flex-wrap: nowrap;
|
||||
gap: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.game-workbench-tabs.game-resource-sort-tabs button {
|
||||
min-height: 36px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.game-workbench-tabs.game-resource-sort-tabs button + button {
|
||||
border-left: 1px solid var(--platform-subpanel-border);
|
||||
}
|
||||
|
||||
.game-workbench-tabs.game-resource-sort-tabs button.is-active {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.game-workbench-tabs button,
|
||||
.game-workbench-view-actions button {
|
||||
display: inline-flex;
|
||||
@@ -5030,6 +5059,10 @@ iframe.preview-frame {
|
||||
box-shadow: 0 0 0 3px var(--platform-input-focus-ring);
|
||||
}
|
||||
|
||||
.game-workbench-tabs.game-resource-sort-tabs button:focus-visible {
|
||||
box-shadow: inset 0 0 0 3px var(--platform-input-focus-ring);
|
||||
}
|
||||
|
||||
.game-workbench-tabs button.is-active,
|
||||
.game-workbench-view-actions button.is-active {
|
||||
border-color: var(--platform-button-primary-border);
|
||||
@@ -6049,7 +6082,7 @@ iframe.preview-frame {
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
background: #fffdfa;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.game-run-preview {
|
||||
@@ -6176,12 +6209,12 @@ iframe.preview-frame {
|
||||
}
|
||||
|
||||
.game-workbench-chat > header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
padding: 12px 14px;
|
||||
border-bottom: 1px solid var(--platform-line-soft);
|
||||
background: var(--platform-subpanel-fill);
|
||||
padding: 4px 14px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.game-workbench-chat > header > div {
|
||||
@@ -6189,6 +6222,39 @@ iframe.preview-frame {
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.launcher-main:has(.game-project-workbench) > .launcher-account-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.game-workbench-chat-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
justify-items: center;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.game-workbench-chat-wallet {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.game-workbench-chat-wallet .launcher-account-bar {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.game-workbench-editor-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.game-workbench-editor-wallet .launcher-account-bar {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.game-workbench-approval-trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -6218,15 +6284,11 @@ iframe.preview-frame {
|
||||
}
|
||||
|
||||
.game-workbench-chat-avatar {
|
||||
display: grid;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
place-items: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
flex: 0 0 auto;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 5px 9px rgb(182 98 63 / 16%));
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-surface {
|
||||
@@ -6418,8 +6480,7 @@ iframe.preview-frame {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--platform-line-soft);
|
||||
background: var(--platform-desktop-panel-fill);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-composer textarea {
|
||||
@@ -6863,8 +6924,8 @@ iframe.preview-frame {
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.game-project-workbench {
|
||||
width: min(100%, calc(100vw - 76px));
|
||||
padding-top: 70px;
|
||||
width: min(100%, calc(100vw - var(--launcher-sidebar-width)));
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.game-workbench-layout {
|
||||
@@ -6878,6 +6939,11 @@ iframe.preview-frame {
|
||||
min-height: 560px;
|
||||
}
|
||||
|
||||
.game-workbench-chat {
|
||||
border-top: 1px solid var(--platform-line-soft);
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.game-workbench-toolbar,
|
||||
.game-workbench-view-actions {
|
||||
align-items: stretch;
|
||||
|
||||
@@ -44,6 +44,7 @@ import type {
|
||||
GameIterationVersion,
|
||||
ProjectResourceCanvasLayoutMode,
|
||||
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import PRODUCT_LOGO from '../../../../../packages/shared/src/icons/taonier-product-ip.png';
|
||||
import {
|
||||
type AssetCanvasCommitNotification,
|
||||
type AssetCanvasExitResult,
|
||||
@@ -287,6 +288,7 @@ export type ProjectDevelopmentViewProps = {
|
||||
agentRuntimeSummaries?: ProjectAgentRuntimeSummary[];
|
||||
agentResults?: ProjectAgentResultSummary[];
|
||||
supervisor: ReactNode;
|
||||
walletEntry?: ReactNode;
|
||||
onHomeOpen: () => void;
|
||||
onProjectsOpen: () => void;
|
||||
onPlay?: () => void;
|
||||
@@ -726,6 +728,7 @@ export default function ProjectDevelopmentView({
|
||||
agentRuntimeSummaries = emptyProjectAgentRuntimeSummaries,
|
||||
agentResults = emptyProjectAgentResults,
|
||||
supervisor,
|
||||
walletEntry,
|
||||
onManifestChange,
|
||||
onPlay,
|
||||
}: ProjectDevelopmentViewProps) {
|
||||
@@ -3107,7 +3110,7 @@ export default function ProjectDevelopmentView({
|
||||
>
|
||||
{mode === 'resources' && uiEditorRoute ? (
|
||||
<div
|
||||
className="h-full min-h-0 min-w-0 w-full overflow-hidden rounded-2xl border border-(--platform-desktop-panel-border) bg-(--platform-desktop-panel-fill) shadow-(--platform-panel-shadow)"
|
||||
className="game-workbench-editor-shell h-full min-h-0 min-w-0 w-full overflow-hidden"
|
||||
data-resource-view-state={resourceViewState}
|
||||
>
|
||||
<UiEditorPage
|
||||
@@ -3115,6 +3118,7 @@ export default function ProjectDevelopmentView({
|
||||
resourceId={uiEditorRoute.resourceId}
|
||||
projectId={manifest.projectId}
|
||||
resourceLabel={uiEditorRoute.resourceLabel}
|
||||
walletEntry={walletEntry}
|
||||
onBack={() => setUiEditorRoute(null)}
|
||||
/>
|
||||
</div>
|
||||
@@ -3208,15 +3212,6 @@ export default function ProjectDevelopmentView({
|
||||
<Sparkles size={15} aria-hidden="true" />
|
||||
新增 UI 设计
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={sortMode === 'dependency' ? 'is-active' : ''}
|
||||
aria-pressed={sortMode === 'dependency'}
|
||||
onClick={() => showResourceSortMode('dependency')}
|
||||
>
|
||||
<FolderTree size={15} aria-hidden="true" />
|
||||
按依赖
|
||||
</button>
|
||||
<span
|
||||
className="game-resource-reorder-status"
|
||||
role="status"
|
||||
@@ -3224,15 +3219,32 @@ export default function ProjectDevelopmentView({
|
||||
>
|
||||
{resourceLayoutSaving ? '保存中' : resourceLayoutNotice}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className={sortMode === 'type' ? 'is-active' : ''}
|
||||
aria-pressed={sortMode === 'type'}
|
||||
onClick={() => showResourceSortMode('type')}
|
||||
<div
|
||||
className="game-workbench-tabs game-resource-sort-tabs"
|
||||
role="group"
|
||||
aria-label="资源排列方式"
|
||||
>
|
||||
<ListFilter size={15} aria-hidden="true" />
|
||||
按类型
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={sortMode === 'dependency' ? 'is-active' : ''}
|
||||
aria-label="按依赖"
|
||||
aria-pressed={sortMode === 'dependency'}
|
||||
onClick={() => showResourceSortMode('dependency')}
|
||||
>
|
||||
<FolderTree size={15} aria-hidden="true" />
|
||||
依赖
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={sortMode === 'type' ? 'is-active' : ''}
|
||||
aria-label="按类型"
|
||||
aria-pressed={sortMode === 'type'}
|
||||
onClick={() => showResourceSortMode('type')}
|
||||
>
|
||||
<ListFilter size={15} aria-hidden="true" />
|
||||
类型
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -4015,13 +4027,20 @@ export default function ProjectDevelopmentView({
|
||||
|
||||
<aside className="game-workbench-chat" aria-label="陶泥儿 Agent 对话">
|
||||
<header>
|
||||
<span className="game-workbench-chat-avatar">陶</span>
|
||||
<div>
|
||||
<img
|
||||
className="game-workbench-chat-avatar"
|
||||
src={PRODUCT_LOGO}
|
||||
alt="陶泥儿"
|
||||
/>
|
||||
<div className="game-workbench-chat-title">
|
||||
<strong>与陶泥儿的对话</strong>
|
||||
<small>
|
||||
{professionalDagVisible ? '项目总控 Agent' : '智能创作'}
|
||||
</small>
|
||||
</div>
|
||||
{walletEntry ? (
|
||||
<div className="game-workbench-chat-wallet">{walletEntry}</div>
|
||||
) : null}
|
||||
{professionalDagVisible ? (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChevronLeft } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { type ReactNode, useMemo, useState } from 'react';
|
||||
|
||||
import { ThemedModal } from '../../components/modal/ThemedModal';
|
||||
import {
|
||||
@@ -27,6 +27,7 @@ export default function UiEditorPage({
|
||||
resourceId,
|
||||
projectId,
|
||||
resourceLabel,
|
||||
walletEntry,
|
||||
onBack,
|
||||
stateStore,
|
||||
}: {
|
||||
@@ -34,6 +35,7 @@ export default function UiEditorPage({
|
||||
resourceId?: string;
|
||||
projectId?: string;
|
||||
resourceLabel?: string;
|
||||
walletEntry?: ReactNode;
|
||||
onBack?: () => void;
|
||||
stateStore?: IUiDesignStateStore;
|
||||
}) {
|
||||
@@ -92,20 +94,25 @@ export default function UiEditorPage({
|
||||
返回资源
|
||||
</button>
|
||||
<strong className="text-sm">{resourceLabel ?? 'UI 设计'}</strong>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-lg bg-orange-600 px-3 py-1.5 text-sm font-semibold text-white disabled:opacity-60"
|
||||
disabled={
|
||||
session.save.isSaving ||
|
||||
session.save.isLoading ||
|
||||
Boolean(session.save.loadError) ||
|
||||
session.save.persistedRevision === null ||
|
||||
session.save.isLocked
|
||||
}
|
||||
onClick={() => requestSave()}
|
||||
>
|
||||
{session.save.isSaving ? '保存中…' : '保存'}
|
||||
</button>
|
||||
<div className="game-workbench-editor-actions">
|
||||
{walletEntry ? (
|
||||
<div className="game-workbench-editor-wallet">{walletEntry}</div>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-lg bg-orange-600 px-3 py-1.5 text-sm font-semibold text-white disabled:opacity-60"
|
||||
disabled={
|
||||
session.save.isSaving ||
|
||||
session.save.isLoading ||
|
||||
Boolean(session.save.loadError) ||
|
||||
session.save.persistedRevision === null ||
|
||||
session.save.isLocked
|
||||
}
|
||||
onClick={() => requestSave()}
|
||||
>
|
||||
{session.save.isSaving ? '保存中…' : '保存'}
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
) : null}
|
||||
{session.save.saveError ? (
|
||||
|
||||
@@ -3429,7 +3429,13 @@ export function registerProjectWorkbenchFoundationTests() {
|
||||
);
|
||||
|
||||
expect(styles).toMatch(
|
||||
/\.game-project-workbench\s*\{[^}]*width:\s*calc\(100vw - 72px\)[^}]*padding:\s*72px 8px 8px[^}]*overflow:\s*hidden/s,
|
||||
/\.game-project-workbench\s*\{[^}]*width:\s*calc\(100vw - var\(--launcher-sidebar-width\)\)[^}]*padding:\s*0[^}]*overflow:\s*hidden/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/\.launcher-main:has\(\.game-project-workbench\)\s*\{[^}]*padding-bottom:\s*0/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-toolbar\s*\{[^}]*padding:\s*8px 12px[^}]*background:\s*transparent/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/@media \(min-width: 761px\)[\s\S]*?\.game-project-workbench\s*\{[^}]*grid-template-rows:\s*minmax\(0, 1fr\) auto[^}]*height:\s*100dvh/,
|
||||
@@ -3444,8 +3450,12 @@ export function registerProjectWorkbenchFoundationTests() {
|
||||
/\.game-workbench-chat \.project-runtime-summary\s*\{[^}]*position:\s*sticky[^}]*top:\s*-10px/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-chat \.project-supervisor-composer\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 82px[^}]*z-index:\s*2[^}]*border-top:\s*1px solid var\(--platform-line-soft\)/s,
|
||||
/\.game-workbench-chat \.project-supervisor-composer\s*\{[^}]*grid-template-columns:\s*minmax\(0, 1fr\) 82px[^}]*z-index:\s*2[^}]*padding-top:\s*8px[^}]*background:\s*transparent/s,
|
||||
);
|
||||
const composerRule = styles.match(
|
||||
/\.game-workbench-chat \.project-supervisor-composer\s*\{([^}]*)\}/s,
|
||||
);
|
||||
expect(composerRule?.[1]).not.toContain('border-top:');
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-chat \.project-supervisor-composer button\s*\{[^}]*min-height:\s*72px[^}]*white-space:\s*nowrap/s,
|
||||
);
|
||||
@@ -3482,6 +3492,41 @@ export function registerProjectWorkbenchFoundationTests() {
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps the wallet entry available when the workbench opens the UI editor', () => {
|
||||
const styles = readFileSync(
|
||||
resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
|
||||
'utf8',
|
||||
);
|
||||
const projectDevelopmentSource = readFileSync(
|
||||
resolve(
|
||||
process.cwd(),
|
||||
'apps/ai-game-creator-shell/src/view/project-development/index.tsx',
|
||||
),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
expect(styles).toMatch(
|
||||
/\.launcher-main:has\(\.game-project-workbench\)\s*>\s*\.launcher-account-bar\s*\{[^}]*display:\s*none/s,
|
||||
);
|
||||
expect(projectDevelopmentSource).toMatch(
|
||||
/<UiEditorPage[\s\S]*?walletEntry=\{walletEntry\}[\s\S]*?\/>/,
|
||||
);
|
||||
expect(projectDevelopmentSource).toMatch(
|
||||
/<div className="game-workbench-chat-wallet">\{walletEntry\}<\/div>/,
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps resource sort tab keyboard focus inside the clipped segmented control', () => {
|
||||
const styles = readFileSync(
|
||||
resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
expect(styles).toMatch(
|
||||
/\.game-workbench-tabs\.game-resource-sort-tabs button:focus-visible\s*\{[^}]*box-shadow:\s*inset 0 0 0 3px var\(--platform-input-focus-ring\)/s,
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps workbench chat bubbles aligned without shrinking process cards', () => {
|
||||
const styles = readFileSync(
|
||||
resolve(process.cwd(), 'apps/ai-game-creator-shell/src/styles.css'),
|
||||
@@ -9200,7 +9245,8 @@ export function registerProjectSupervisorSurfaceTests() {
|
||||
projectPath,
|
||||
});
|
||||
let directTurnUpdateHandler:
|
||||
((event: { payload: Record<string, unknown> }) => void) | null = null;
|
||||
| ((event: { payload: Record<string, unknown> }) => void)
|
||||
| null = null;
|
||||
const listen = vi.fn(
|
||||
async (
|
||||
eventName: string,
|
||||
@@ -10157,7 +10203,8 @@ export function registerProjectAgentStatusTests() {
|
||||
},
|
||||
);
|
||||
let runtimeUpdateHandler:
|
||||
((event: { payload: Record<string, unknown> }) => void) | null = null;
|
||||
| ((event: { payload: Record<string, unknown> }) => void)
|
||||
| null = null;
|
||||
const listen = vi.fn(
|
||||
async (
|
||||
eventName: string,
|
||||
|
||||
@@ -146,6 +146,34 @@ async function renderLoadedSession(state: State) {
|
||||
}
|
||||
|
||||
describe('UiEditorPage', () => {
|
||||
it('keeps the wallet entry in the resource editor header', async () => {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)),
|
||||
save: vi.fn(),
|
||||
};
|
||||
|
||||
render(
|
||||
createElement(UiEditorPage, {
|
||||
projectPath: '/tmp/ui-editor-wallet',
|
||||
resourceId: 'ui-resource',
|
||||
stateStore,
|
||||
walletEntry: createElement(
|
||||
'button',
|
||||
{ type: 'button', 'aria-label': '打开账户资产' },
|
||||
'泥点',
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
const walletEntry = await screen.findByRole('button', {
|
||||
name: '打开账户资产',
|
||||
});
|
||||
expect(walletEntry.closest('header')).not.toBeNull();
|
||||
expect(
|
||||
screen.getAllByRole('button', { name: '打开账户资产' }),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('cancels image preview scopes when the resource changes and on unmount', async () => {
|
||||
vi.mocked(invoke)
|
||||
.mockReset()
|
||||
|
||||
@@ -108,6 +108,9 @@
|
||||
- 第一批共享 chrome 固定覆盖画布动作按钮、工具栏、工具分组和分隔符。按钮的默认、悬停、键盘焦点、选中、禁用和主次色语义由共享层表达;宿主只提供图标、文案、事件与业务禁用条件。
|
||||
- 主站账号、钱包、服务端项目、云端素材库和生成面板仍留在网站宿主;客户端本地项目、manifest、Runtime、审批、草稿、生成与正式提交仍留在 Tauri 宿主。共享视觉组件不得读取这些业务事实。
|
||||
- 客户端 UI 对齐采用“同视觉、同组件、保留四区布局”,不复制主站整页布局。资源总览、运行视图和 Supervisor 对话继续是 Game Agent 工作台独有语义。
|
||||
- 工作台四区作为同一应用工作面直接衔接,外层不使用卡片圆角或留白间距。中央主视窗与右侧 Supervisor 使用各自的平台区域底色,并以稳定的竖向分隔线明确边界;不通过外层圆角容器、阴影或区块间缝重新包装四区。
|
||||
- 右侧正式钱包入口属于客户端宿主 chrome,在普通项目工作台与 UI Editor 子路由中都必须持续可见、键盘可达且可操作,不得因进入素材编辑壳或隐藏全局 chrome 而丢失余额、充值和使用详情入口。
|
||||
- 资源总览的“资源依赖 / 资源类型”视图切换使用连通的分段按钮组,相邻选项共享边界并保持唯一选中语义。每个分段都必须有清晰的键盘焦点指示,焦点环不得被分段容器的圆角或 `overflow` 裁切。
|
||||
- 右侧 Supervisor 对话中,用户消息使用右对齐、最大宽度受限的主题暖色气泡,assistant 消息保持左对齐;消息换行不得产生水平溢出,执行过程卡继续占满消息区可用宽度。气泡正文在 light / dark 平台主题下均须满足 WCAG AA 普通文本 `4.5:1` 对比度。
|
||||
- 客户端正式产品仍只按最小 `1280×720` 横屏合同交付,并保留 `1280×800` 默认窗口与既有基线验收;更窄浏览器样式只负责不崩溃和开发兼容,不改成移动端创作工作台。
|
||||
- 普通用户界面不默认展示内部错误码或本机绝对路径,也不展示 External Editor Base URL 或 Developer API Key;官方服务地址由客户端构建固定,远端编辑自动使用当前陶泥儿登录态。仅独立 standalone game-chat release 或显式高级自定义模式在隔离配置页维护 External v1 URL/Key,确需诊断的信息进入受控详情或开发模式。
|
||||
@@ -567,6 +570,9 @@ type ProjectAgentMudPointAttribution = {
|
||||
4. 主站现有图片编辑器的按钮名称、tool selection、hover/focus/pressed/disabled 行为与工具栏位置不因共享抽取回归;网站账号、钱包、素材库、生成和导出逻辑不下沉共享层。
|
||||
5. 客户端生成、保存、取消、恢复、登录失效与余额不足只更换视觉承载,不改变 Host Port 调用、幂等身份、草稿 CAS、manifest/revision、Runtime 审批或钱包刷新语义。
|
||||
6. 阶段一、二冻结合同并让主站消费共享 chrome;2026-08-06 的阶段三至五已经完成客户端中央区、Supervisor 和 Agent Dock 的正式换肤、定向测试与 `1280×800` 验收。独立 Vite 没有登录会话时继续显示真实登录门禁,不为视觉测试增加绕过入口。
|
||||
7. 普通工作台和 UI Editor 子路由均不显示工作面外层圆角或区块留白;中央区与右侧 Supervisor 的区域底色可辨识,竖向分隔连续、无错位。
|
||||
8. 右侧正式钱包入口在普通工作台和 UI Editor 子路由都始终可见、键盘可达并能打开余额、充值与使用详情;路由切换不得使入口消失或失去交互。
|
||||
9. “资源依赖 / 资源类型”以连通分段按钮呈现,点击与键盘操作均只保留一个选中项;使用 Tab 定位和键盘切换时焦点指示清晰、完整,不被容器边界或 `overflow` 裁切。
|
||||
|
||||
## 8. 非目标
|
||||
|
||||
|
||||
Reference in New Issue
Block a user