diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index a5b44b28..eb41f0e5 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -240,6 +240,14 @@ - 验证:浏览器触发 `/creation/puzzle` 与 `/creation/match3d` 的泥点确认弹窗,检查 overlay 最近主题 class 存在、`--platform-modal-fill` 有值且面板为实底;聚焦测试覆盖默认 overlay / panel class。 - 关联:`src/components/common/PlatformMudPointConfirmDialog.tsx`、`src/components/common/PlatformStatusDialog.tsx`、`src/components/unified-creation/workspaces/PuzzleCreationWorkspace.tsx`、`src/components/unified-creation/workspaces/Match3DCreationWorkspace.tsx`。 +## 拼图结果页关卡图不要裁切,嵌套图片预览要高于详情弹窗 + +- 现象:拼图结果页“拼图关卡”列表里的关卡图底部被裁掉;进入关卡详情后点击画面图,看起来没有打开全屏预览。 +- 原因:关卡列表复用 `PlatformMediaFrame aspect="standard"` 默认 `object-cover`,方图或竖向生成图会在 4:3 框内被裁切;关卡详情弹窗自身层级高于 `CreativeImageInputPanel` 默认图片预览层级,预览实际打开但被压在详情弹窗后面。 +- 处理:结果页关卡缩略图显式传 `imageClassName="h-full w-full object-contain"` 保留完整画面;`CreativeImageInputPanel` 提供 `mainImagePreviewZIndexClassName`,嵌套在高层级弹窗内时由调用方传更高层级。 +- 验证:聚焦测试断言关卡缩略图使用 `object-contain` 且没有 `object-cover`,并断言关卡详情内主图预览 overlay 层级高于详情弹窗;浏览器里检查列表完整显示图片,详情内点击画面图能打开可见预览。 +- 关联:`src/components/puzzle-result/PuzzleResultView.tsx`、`src/components/common/CreativeImageInputPanel.tsx`、`src/components/puzzle-result/PuzzleResultView.test.tsx`。 + ## 玩法入口分类字段缺失要前端兜底 - 现象:平台创作入口初始化时,`platformEntryCreationTypes.ts` 直接对 `creationTypes[].categoryId` / `categoryLabel` 调 `trim()`,一旦后端旧数据、局部 mock 或异常返回里缺字段,整个创作页会在 `derivePlatformCreationTypes(...)` 里直接炸掉。 diff --git a/src/components/common/CreativeImageInputPanel.tsx b/src/components/common/CreativeImageInputPanel.tsx index 524bf118..feff331a 100644 --- a/src/components/common/CreativeImageInputPanel.tsx +++ b/src/components/common/CreativeImageInputPanel.tsx @@ -52,6 +52,7 @@ export type CreativeImageInputPanelProps = { uploadedImageSrc: string; uploadedImageAlt: string; uploadedImageRefreshKey?: string | number | null; + mainImagePreviewZIndexClassName?: string; mainImageMeta?: ReactNode; mainImageInputId: string; mainImageAccept?: string; @@ -100,6 +101,7 @@ export function CreativeImageInputPanel({ uploadedImageSrc, uploadedImageAlt, uploadedImageRefreshKey = null, + mainImagePreviewZIndexClassName = 'z-[82]', mainImageMeta = null, mainImageInputId, mainImageAccept = DEFAULT_IMAGE_ACCEPT, @@ -524,7 +526,7 @@ export function CreativeImageInputPanel({ } closeVariant="profileCompact" size="xl" - zIndexClassName="z-[82]" + zIndexClassName={mainImagePreviewZIndexClassName} overlayClassName="px-4 py-6" panelClassName="platform-remap-surface rounded-[1.35rem] p-3 shadow-[0_24px_70px_rgba(15,23,42,0.22)]" headerClassName="mb-3 items-center border-b-0 px-1 py-0" diff --git a/src/components/puzzle-result/PuzzleResultView.test.tsx b/src/components/puzzle-result/PuzzleResultView.test.tsx index ac938959..ad6d3514 100644 --- a/src/components/puzzle-result/PuzzleResultView.test.tsx +++ b/src/components/puzzle-result/PuzzleResultView.test.tsx @@ -274,6 +274,8 @@ describe('PuzzleResultView', () => { const levelImage = screen.getByRole('img', { name: '雨夜猫街' }); const mediaFrame = levelImage.closest('div.relative'); expect(mediaFrame?.className).toContain('aspect-[4/3]'); + expect(levelImage.className).toContain('object-contain'); + expect(levelImage.className).not.toContain('object-cover'); expect(mediaFrame?.className).not.toContain( 'bg-[var(--platform-subpanel-fill)]', ); @@ -552,6 +554,7 @@ describe('PuzzleResultView', () => { const imagePreviewDialog = screen.getByRole('dialog', { name: '查看关卡图片', }); + expect(imagePreviewDialog.parentElement?.className).toContain('z-[150]'); expect(within(imagePreviewDialog).getByAltText('暖灯猫街')).toBeTruthy(); fireEvent.click( within(imagePreviewDialog).getByRole('button', { diff --git a/src/components/puzzle-result/PuzzleResultView.tsx b/src/components/puzzle-result/PuzzleResultView.tsx index 9f4a52e8..ea2ee1e9 100644 --- a/src/components/puzzle-result/PuzzleResultView.tsx +++ b/src/components/puzzle-result/PuzzleResultView.tsx @@ -724,6 +724,7 @@ function PuzzleLevelDetailDialog({ promptReferenceImages={promptReferenceImages} promptReferenceLimit={PUZZLE_LEVEL_PROMPT_REFERENCE_LIMIT} imageLimitHint="图片≤6MB" + mainImagePreviewZIndexClassName="z-[150]" imageModelPicker={