优化 Agent 对话与运行入口
优化 Agent 消息排版与悬浮输入框 隐藏资源管理搜索框并调整运行入口 恢复运行视窗播放按钮位置与箭头样式
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Send } from 'lucide-react';
|
||||
import { ArrowUp } from 'lucide-react';
|
||||
import type {
|
||||
ComponentProps,
|
||||
Dispatch,
|
||||
@@ -210,14 +210,7 @@ export function ProjectSupervisorView({
|
||||
type="submit"
|
||||
disabled={runtimePanelProps.controlBusy || needsUserInput}
|
||||
>
|
||||
<Send size={16} aria-hidden="true" />
|
||||
<span>
|
||||
{needsUserInput
|
||||
? '等待回答'
|
||||
: runtimePanelProps.controlBusy
|
||||
? '思考中'
|
||||
: '发送'}
|
||||
</span>
|
||||
<ArrowUp size={16} aria-hidden="true" />
|
||||
</button>
|
||||
</form>
|
||||
<small className="project-supervisor-workspace-status">
|
||||
|
||||
@@ -5087,7 +5087,6 @@ iframe.preview-frame {
|
||||
}
|
||||
|
||||
.game-workbench-toolbar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -5184,9 +5183,6 @@ iframe.preview-frame {
|
||||
}
|
||||
|
||||
.game-workbench-view-actions .game-workbench-play-button {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-color: var(--platform-button-primary-border);
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
@@ -6601,6 +6597,7 @@ iframe.preview-frame {
|
||||
align-content: start;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
min-height: 156px;
|
||||
padding: 12px;
|
||||
border: 1px solid #eadbd4;
|
||||
border-radius: 12px;
|
||||
@@ -6744,12 +6741,260 @@ iframe.preview-frame {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.game-workbench-chat-avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
.game-workbench-chat .supervisor-chat-only-runtime-controls {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.supervisor-chat-only-runtime-controls
|
||||
.pending-command {
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 10px;
|
||||
background: var(--platform-warm-bg);
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.supervisor-chat-only-runtime-controls
|
||||
.pending-command
|
||||
> span {
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
color: var(--platform-text-strong);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.supervisor-chat-only-runtime-controls
|
||||
.pending-command
|
||||
> span
|
||||
small {
|
||||
color: var(--platform-text-soft);
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.game-workbench-chat .pending-command-actions button {
|
||||
min-width: 52px;
|
||||
height: 34px;
|
||||
flex: 0 0 auto;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 5px 9px rgb(182 98 63 / 16%));
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
background: var(--platform-button-secondary-fill);
|
||||
color: var(--platform-button-secondary-text);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.game-workbench-chat .pending-command-actions button:last-child {
|
||||
border-color: var(--platform-button-primary-border);
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
}
|
||||
|
||||
.agent-runtime-status .project-runtime-pending-command > span {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
color: var(--platform-text-strong);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.agent-runtime-status .project-runtime-pending-command > span small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
color: var(--platform-text-soft);
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.agent-runtime-status .project-runtime-pending-command .pending-command-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.agent-runtime-status
|
||||
.project-runtime-pending-command
|
||||
.pending-command-actions
|
||||
button:last-child {
|
||||
border-color: var(--platform-button-primary-border);
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.agent-runtime-status
|
||||
.project-runtime-pending-command {
|
||||
grid-template-columns: minmax(0, 1fr) 136px;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.agent-runtime-status
|
||||
.project-runtime-pending-command
|
||||
.pending-command-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 64px);
|
||||
gap: 8px;
|
||||
width: 136px;
|
||||
flex: 0 0 136px;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.agent-runtime-status
|
||||
.project-runtime-pending-command
|
||||
.pending-command-actions
|
||||
button {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
max-width: 64px;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Runtime 确认卡在部分项目状态下位于状态包装层外,工作台样式直接绑定卡片自身,避免回落旧的蓝色按钮样式。 */
|
||||
.game-workbench-chat .project-runtime-pending-command {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 136px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 10px;
|
||||
background: var(--platform-warm-bg);
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-surface > .project-runtime-pending-command,
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 136px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 10px;
|
||||
background: var(--platform-warm-bg);
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command > span {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
color: var(--platform-text-strong);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command > span small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
color: var(--platform-text-soft);
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command .pending-command-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 64px);
|
||||
gap: 8px;
|
||||
width: 136px;
|
||||
flex: 0 0 136px;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command .pending-command-actions button {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
max-width: 64px;
|
||||
height: 34px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 8px;
|
||||
background: var(--platform-button-secondary-fill);
|
||||
color: var(--platform-button-secondary-text);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-conversation .project-runtime-pending-command .pending-command-actions button:last-child {
|
||||
border-color: var(--platform-button-primary-border);
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
}
|
||||
|
||||
/* 该卡片的两个操作按钮禁止被全局 button 规则压缩,确保“拒绝 / 确认”完整可见。 */
|
||||
.project-runtime-pending-command .pending-command-actions button {
|
||||
display: inline-flex !important;
|
||||
width: 64px !important;
|
||||
min-width: 64px !important;
|
||||
max-width: 64px !important;
|
||||
flex: 0 0 64px !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 !important;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-runtime-pending-command > span {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
color: var(--platform-text-strong);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-runtime-pending-command > span small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
color: var(--platform-text-soft);
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-runtime-pending-command .pending-command-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 64px);
|
||||
gap: 8px;
|
||||
width: 136px;
|
||||
flex: 0 0 136px;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.project-runtime-pending-command
|
||||
.pending-command-actions
|
||||
button {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
max-width: 64px;
|
||||
height: 34px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 8px;
|
||||
background: var(--platform-button-secondary-fill);
|
||||
color: var(--platform-button-secondary-text);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.game-workbench-chat
|
||||
.project-runtime-pending-command
|
||||
.pending-command-actions
|
||||
button:last-child {
|
||||
border-color: var(--platform-button-primary-border);
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-surface {
|
||||
@@ -6971,6 +7216,100 @@ iframe.preview-frame {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 右侧对话采用简洁的 Codex 式消息流与编辑框,减少卡片嵌套和视觉噪音。 */
|
||||
.game-workbench-chat .project-supervisor-message-list {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 104px;
|
||||
left: 0;
|
||||
gap: 34px;
|
||||
height: auto;
|
||||
padding: 18px 20px 24px;
|
||||
scroll-padding-bottom: 24px;
|
||||
border: 1px solid var(--platform-subpanel-border);
|
||||
border-radius: 12px;
|
||||
background: var(--platform-input-fill);
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-message-list .message {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 4px 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: var(--platform-text-base);
|
||||
font-size: 14px;
|
||||
line-height: 1.85;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-message-list .message + .message {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-message-list .message--user {
|
||||
width: fit-content;
|
||||
max-width: min(82%, 640px);
|
||||
margin-left: auto;
|
||||
padding: 11px 16px;
|
||||
border: 1px solid var(--platform-button-primary-border);
|
||||
border-radius: 14px 14px 4px;
|
||||
background: var(--platform-warm-bg);
|
||||
color: var(--platform-text-strong);
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-composer {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-composer textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 88px;
|
||||
max-height: 180px;
|
||||
padding: 14px 48px 38px 15px;
|
||||
border: 1px solid var(--platform-surface-border);
|
||||
border-radius: 14px;
|
||||
background: var(--platform-input-fill);
|
||||
color: var(--platform-text-strong);
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
resize: vertical;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-composer button {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
display: grid;
|
||||
width: 30px;
|
||||
min-width: 30px;
|
||||
height: 30px;
|
||||
min-height: 30px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 9px;
|
||||
background: var(--platform-button-primary-fill);
|
||||
color: var(--platform-button-primary-text);
|
||||
place-items: center;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.game-workbench-chat .project-supervisor-composer button svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.game-agent-dock {
|
||||
position: relative;
|
||||
z-index: 30;
|
||||
@@ -7382,10 +7721,6 @@ iframe.preview-frame {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.game-workbench-view-actions .game-workbench-play-button {
|
||||
position: static;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
|
||||
@@ -45,7 +45,6 @@ import type {
|
||||
GameIterationVersion,
|
||||
ProjectResourceCanvasLayoutMode,
|
||||
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import PRODUCT_LOGO from '../../../../../packages/shared/src/icons/taonier-product-ip.png';
|
||||
import { canonicalAssetBaseName } from '../../features/asset-canvas/assetCanvasNaming';
|
||||
import {
|
||||
type AssetCanvasCommitNotification,
|
||||
@@ -833,6 +832,15 @@ export default function ProjectDevelopmentView({
|
||||
useState<ResourceCanvasViewportBySortMode>(defaultResourceCanvasViewports);
|
||||
const [activeResourceCategory, setActiveResourceCategory] =
|
||||
useState<ResourceCategory | null>(null);
|
||||
const [unreadResourceCategoryState, setUnreadResourceCategoryState] =
|
||||
useState<{
|
||||
scopeKey: string;
|
||||
categories: Set<ResourceCategory>;
|
||||
}>(() => ({ scopeKey: '', categories: new Set() }));
|
||||
const resourceCategorySnapshotRef = useRef<{
|
||||
scopeKey: string;
|
||||
resourceIdsByCategory: Map<ResourceCategory, Set<string>>;
|
||||
} | null>(null);
|
||||
const [selectedResourceId, setSelectedResourceId] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
@@ -872,8 +880,10 @@ export default function ProjectDevelopmentView({
|
||||
const [hiddenCommittedResourceId, setHiddenCommittedResourceId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [resourcePreviewVersionByResourceId, setResourcePreviewVersionByResourceId] =
|
||||
useState<Map<string, string>>(() => new Map());
|
||||
const [
|
||||
resourcePreviewVersionByResourceId,
|
||||
setResourcePreviewVersionByResourceId,
|
||||
] = useState<Map<string, string>>(() => new Map());
|
||||
const [approvalMode, setApprovalMode] = useState<ApprovalMode>('strict');
|
||||
const [approvalDialogOpen, setApprovalDialogOpen] = useState(false);
|
||||
const [approvalNotice, setApprovalNotice] = useState('');
|
||||
@@ -1375,6 +1385,24 @@ export default function ProjectDevelopmentView({
|
||||
),
|
||||
[resources],
|
||||
);
|
||||
const resourceIdsByCategory = useMemo(
|
||||
() =>
|
||||
new Map(
|
||||
categoryOrder.map((category) => [
|
||||
category,
|
||||
new Set(
|
||||
(projectResourcesByCategory.get(category) ?? []).map(
|
||||
(resource) => resource.id,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
[projectResourcesByCategory],
|
||||
);
|
||||
const resourceCategoryScopeKey = useMemo(
|
||||
() => JSON.stringify([projectPath, manifest.projectId]),
|
||||
[manifest.projectId, projectPath],
|
||||
);
|
||||
const resourcePageCategories = useMemo(
|
||||
() => (resources.length > 0 ? categoryOrder : []),
|
||||
[resources.length],
|
||||
@@ -1388,6 +1416,63 @@ export default function ProjectDevelopmentView({
|
||||
) ??
|
||||
resourcePageCategories[0] ??
|
||||
null;
|
||||
const viewedResourceCategory =
|
||||
mode === 'resources' ? activePageCategory : null;
|
||||
useEffect(() => {
|
||||
const previousSnapshot = resourceCategorySnapshotRef.current;
|
||||
if (
|
||||
!previousSnapshot ||
|
||||
previousSnapshot.scopeKey !== resourceCategoryScopeKey
|
||||
) {
|
||||
resourceCategorySnapshotRef.current = {
|
||||
scopeKey: resourceCategoryScopeKey,
|
||||
resourceIdsByCategory,
|
||||
};
|
||||
setUnreadResourceCategoryState({
|
||||
scopeKey: resourceCategoryScopeKey,
|
||||
categories: new Set(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const categoriesWithNewResources = categoryOrder.filter((category) => {
|
||||
if (category === viewedResourceCategory) {
|
||||
return false;
|
||||
}
|
||||
const previousIds =
|
||||
previousSnapshot.resourceIdsByCategory.get(category) ?? new Set();
|
||||
return Array.from(resourceIdsByCategory.get(category) ?? []).some(
|
||||
(resourceId) => !previousIds.has(resourceId),
|
||||
);
|
||||
});
|
||||
resourceCategorySnapshotRef.current = {
|
||||
scopeKey: resourceCategoryScopeKey,
|
||||
resourceIdsByCategory,
|
||||
};
|
||||
setUnreadResourceCategoryState((current) => {
|
||||
const categories =
|
||||
current.scopeKey === resourceCategoryScopeKey
|
||||
? new Set(current.categories)
|
||||
: new Set<ResourceCategory>();
|
||||
let changed = current.scopeKey !== resourceCategoryScopeKey;
|
||||
if (viewedResourceCategory && categories.delete(viewedResourceCategory)) {
|
||||
changed = true;
|
||||
}
|
||||
categoriesWithNewResources.forEach((category) => {
|
||||
if (!categories.has(category)) {
|
||||
categories.add(category);
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
return changed
|
||||
? { scopeKey: resourceCategoryScopeKey, categories }
|
||||
: current;
|
||||
});
|
||||
}, [resourceCategoryScopeKey, resourceIdsByCategory, viewedResourceCategory]);
|
||||
const unreadResourceCategories =
|
||||
unreadResourceCategoryState.scopeKey === resourceCategoryScopeKey
|
||||
? unreadResourceCategoryState.categories
|
||||
: new Set<ResourceCategory>();
|
||||
resourceCanvasPageWheelRef.current.activeCategory = activePageCategory;
|
||||
const nextPageCategory =
|
||||
activePageCategory && resourcePageCategories.length > 1
|
||||
@@ -1502,8 +1587,7 @@ export default function ProjectDevelopmentView({
|
||||
: { x: 48, y: 48, scale: 1 };
|
||||
const setResourceCanvasViewport = useCallback(
|
||||
(candidate: CanvasViewport) => {
|
||||
const activeCategory =
|
||||
resourceCanvasPageWheelRef.current.activeCategory;
|
||||
const activeCategory = resourceCanvasPageWheelRef.current.activeCategory;
|
||||
if (!activeCategory) {
|
||||
return;
|
||||
}
|
||||
@@ -1787,8 +1871,7 @@ export default function ProjectDevelopmentView({
|
||||
|
||||
const advanceResourceCanvasPage = useCallback(
|
||||
(stepOffset: number) => {
|
||||
const currentCategory =
|
||||
resourceCanvasPageWheelRef.current.activeCategory;
|
||||
const currentCategory = resourceCanvasPageWheelRef.current.activeCategory;
|
||||
const normalizedStepOffset = Math.trunc(stepOffset);
|
||||
if (
|
||||
!currentCategory ||
|
||||
@@ -1836,8 +1919,7 @@ export default function ProjectDevelopmentView({
|
||||
return;
|
||||
}
|
||||
const now = performance.now();
|
||||
const waitMs =
|
||||
pageWheelSwitchIntervalMs - (now - state.lastSwitchAt);
|
||||
const waitMs = pageWheelSwitchIntervalMs - (now - state.lastSwitchAt);
|
||||
if (waitMs > 0) {
|
||||
if (state.pendingTimerId === null) {
|
||||
state.pendingTimerId = window.setTimeout(() => {
|
||||
@@ -1912,8 +1994,7 @@ export default function ProjectDevelopmentView({
|
||||
}
|
||||
pageWheelState.accumulatedDeltaY += normalizedDeltaY;
|
||||
if (
|
||||
Math.abs(pageWheelState.accumulatedDeltaY) >=
|
||||
pageWheelDeltaThreshold
|
||||
Math.abs(pageWheelState.accumulatedDeltaY) >= pageWheelDeltaThreshold
|
||||
) {
|
||||
const stepCount = Math.max(
|
||||
1,
|
||||
@@ -1939,7 +2020,8 @@ export default function ProjectDevelopmentView({
|
||||
}
|
||||
const viewport = resolveViewport(event);
|
||||
const category = viewport?.dataset.resourceSectionScroll as
|
||||
ResourceCategory | undefined;
|
||||
| ResourceCategory
|
||||
| undefined;
|
||||
if (!viewport || !category) {
|
||||
return;
|
||||
}
|
||||
@@ -1958,7 +2040,8 @@ export default function ProjectDevelopmentView({
|
||||
const event = rawEvent as WebKitGestureEvent;
|
||||
const viewport = resolveViewport(event);
|
||||
const category = viewport?.dataset.resourceSectionScroll as
|
||||
ResourceCategory | undefined;
|
||||
| ResourceCategory
|
||||
| undefined;
|
||||
if (!viewport || !category) {
|
||||
return;
|
||||
}
|
||||
@@ -2048,11 +2131,7 @@ export default function ProjectDevelopmentView({
|
||||
]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (
|
||||
mode !== 'resources' ||
|
||||
!activePageCategory ||
|
||||
!activePageLayoutReady
|
||||
) {
|
||||
if (mode !== 'resources' || !activePageCategory || !activePageLayoutReady) {
|
||||
return undefined;
|
||||
}
|
||||
const canvas = resourceCanvasRef.current;
|
||||
@@ -2113,7 +2192,8 @@ export default function ProjectDevelopmentView({
|
||||
.querySelectorAll<HTMLElement>('[data-resource-section-scroll]')
|
||||
.forEach((viewport) => {
|
||||
const category = viewport.dataset.resourceSectionScroll as
|
||||
ResourceCategory | undefined;
|
||||
| ResourceCategory
|
||||
| undefined;
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
@@ -2133,7 +2213,8 @@ export default function ProjectDevelopmentView({
|
||||
?.querySelectorAll<HTMLElement>('[data-resource-section-scroll]')
|
||||
.forEach((viewport) => {
|
||||
const category = viewport.dataset.resourceSectionScroll as
|
||||
ResourceCategory | undefined;
|
||||
| ResourceCategory
|
||||
| undefined;
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
@@ -2735,9 +2816,7 @@ export default function ProjectDevelopmentView({
|
||||
}
|
||||
drag.changed = true;
|
||||
const coordinate = (start: number, delta: number) =>
|
||||
normalizeResourceCanvasDragCoordinate(
|
||||
start + delta / drag.startScale,
|
||||
);
|
||||
normalizeResourceCanvasDragCoordinate(start + delta / drag.startScale);
|
||||
const preview = {
|
||||
resourceId: drag.resourceId,
|
||||
x: coordinate(drag.startX, deltaX),
|
||||
@@ -3776,16 +3855,16 @@ export default function ProjectDevelopmentView({
|
||||
dependencyLayoutSettled: dependencyLayout.settled,
|
||||
dependencyPositioned: Boolean(
|
||||
intent.resourceId &&
|
||||
dependencyLayout.layout.positions.some(
|
||||
(position) => position.resourceId === intent.resourceId,
|
||||
),
|
||||
dependencyLayout.layout.positions.some(
|
||||
(position) => position.resourceId === intent.resourceId,
|
||||
),
|
||||
),
|
||||
typeLayoutSettled: typeLayout.settled,
|
||||
typePositioned: Boolean(
|
||||
intent.resourceId &&
|
||||
typeLayout.layout.positions.some(
|
||||
(position) => position.resourceId === intent.resourceId,
|
||||
),
|
||||
typeLayout.layout.positions.some(
|
||||
(position) => position.resourceId === intent.resourceId,
|
||||
),
|
||||
),
|
||||
visible: targetVisible,
|
||||
domRendered: Boolean(card),
|
||||
@@ -3925,27 +4004,37 @@ export default function ProjectDevelopmentView({
|
||||
data-unavailable={!runAvailable || uiEditorRoute || undefined}
|
||||
className={mode === 'run' ? 'is-active' : ''}
|
||||
disabled={uiEditorRoute !== null}
|
||||
onClick={showRunView}
|
||||
onClick={() => {
|
||||
if (!runAvailable) {
|
||||
return;
|
||||
}
|
||||
showRunView();
|
||||
onPlay?.();
|
||||
}}
|
||||
>
|
||||
运行
|
||||
</button>
|
||||
</div>
|
||||
<div className="game-workbench-view-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="game-workbench-play-button"
|
||||
disabled={!runAvailable || !onPlay || uiEditorRoute !== null}
|
||||
onClick={() => {
|
||||
showRunView();
|
||||
onPlay?.();
|
||||
}}
|
||||
title={
|
||||
runAvailable ? '运行当前游戏' : '首个可运行原型完成后才能播放'
|
||||
}
|
||||
>
|
||||
<Play size={15} aria-hidden="true" />
|
||||
播放
|
||||
</button>
|
||||
{mode === 'run' ? (
|
||||
<button
|
||||
type="button"
|
||||
className="game-workbench-play-button"
|
||||
disabled={!runAvailable || !onPlay || uiEditorRoute !== null}
|
||||
onClick={() => {
|
||||
showRunView();
|
||||
onPlay?.();
|
||||
}}
|
||||
title={
|
||||
runAvailable
|
||||
? '运行当前游戏'
|
||||
: '首个可运行原型完成后才能播放'
|
||||
}
|
||||
>
|
||||
<Play size={15} aria-hidden="true" />
|
||||
播放
|
||||
</button>
|
||||
) : null}
|
||||
{mode === 'resources' &&
|
||||
!assetCanvasRoute &&
|
||||
!resourceEditorRoute &&
|
||||
@@ -3965,15 +4054,6 @@ export default function ProjectDevelopmentView({
|
||||
: `管理未完成编辑 (${pendingResourceEdits.length})`}
|
||||
</button>
|
||||
) : null}
|
||||
<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"
|
||||
@@ -3981,15 +4061,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>
|
||||
@@ -4479,10 +4576,15 @@ export default function ProjectDevelopmentView({
|
||||
>
|
||||
{resourcePageCategories.map((category) => {
|
||||
const Icon = categoryIcons[category];
|
||||
const hasUnreadResources =
|
||||
unreadResourceCategories.has(category);
|
||||
return (
|
||||
<button
|
||||
key={category}
|
||||
type="button"
|
||||
aria-label={`${categoryLabels[category]}${
|
||||
hasUnreadResources ? ',有新资源' : ''
|
||||
}`}
|
||||
aria-current={
|
||||
category === activePageCategory
|
||||
? 'page'
|
||||
@@ -4498,7 +4600,15 @@ export default function ProjectDevelopmentView({
|
||||
}
|
||||
>
|
||||
<Icon size={14} aria-hidden="true" />
|
||||
<strong>{categoryLabels[category]}</strong>
|
||||
<strong className="game-resource-outline-label">
|
||||
{categoryLabels[category]}
|
||||
{hasUnreadResources ? (
|
||||
<span
|
||||
className="game-resource-outline-unread"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null}
|
||||
</strong>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -4760,29 +4870,13 @@ export default function ProjectDevelopmentView({
|
||||
<dd>{selectedResource.mediaType}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
) : (
|
||||
<p>暂停后选择资源可查看已登记信息</p>
|
||||
)}
|
||||
) : null}
|
||||
</section>
|
||||
<section aria-label="数值微调面板">
|
||||
<header>
|
||||
<SlidersHorizontal size={16} aria-hidden="true" />
|
||||
数值微调
|
||||
</header>
|
||||
<label>
|
||||
角色移动速度
|
||||
<input type="number" disabled placeholder="未载入" />
|
||||
</label>
|
||||
<label>
|
||||
跳跃高度
|
||||
<input type="number" disabled placeholder="未载入" />
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
disabled
|
||||
aria-label="新增微调数值项"
|
||||
placeholder="用自然语言新增微调项(尚未接入)"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
@@ -4792,11 +4886,6 @@ export default function ProjectDevelopmentView({
|
||||
{!uiEditorRoute ? (
|
||||
<aside className="game-workbench-chat" aria-label="陶泥儿 Agent 对话">
|
||||
<header>
|
||||
<img
|
||||
className="game-workbench-chat-avatar"
|
||||
src={PRODUCT_LOGO}
|
||||
alt="陶泥儿"
|
||||
/>
|
||||
<div className="game-workbench-chat-title">
|
||||
<strong>与陶泥儿的对话</strong>
|
||||
<small>
|
||||
|
||||
Reference in New Issue
Block a user