修复拼图结果页图片预览层级
关卡缩略图改为完整显示,避免生成图被裁切 关卡详情内主图预览支持提高层级,避免被详情弹窗遮挡 补充拼图结果页聚焦测试与 Hermes 踩坑记录
This commit is contained in:
@@ -240,6 +240,14 @@
|
|||||||
- 验证:浏览器触发 `/creation/puzzle` 与 `/creation/match3d` 的泥点确认弹窗,检查 overlay 最近主题 class 存在、`--platform-modal-fill` 有值且面板为实底;聚焦测试覆盖默认 overlay / panel class。
|
- 验证:浏览器触发 `/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`。
|
- 关联:`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(...)` 里直接炸掉。
|
- 现象:平台创作入口初始化时,`platformEntryCreationTypes.ts` 直接对 `creationTypes[].categoryId` / `categoryLabel` 调 `trim()`,一旦后端旧数据、局部 mock 或异常返回里缺字段,整个创作页会在 `derivePlatformCreationTypes(...)` 里直接炸掉。
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export type CreativeImageInputPanelProps = {
|
|||||||
uploadedImageSrc: string;
|
uploadedImageSrc: string;
|
||||||
uploadedImageAlt: string;
|
uploadedImageAlt: string;
|
||||||
uploadedImageRefreshKey?: string | number | null;
|
uploadedImageRefreshKey?: string | number | null;
|
||||||
|
mainImagePreviewZIndexClassName?: string;
|
||||||
mainImageMeta?: ReactNode;
|
mainImageMeta?: ReactNode;
|
||||||
mainImageInputId: string;
|
mainImageInputId: string;
|
||||||
mainImageAccept?: string;
|
mainImageAccept?: string;
|
||||||
@@ -100,6 +101,7 @@ export function CreativeImageInputPanel({
|
|||||||
uploadedImageSrc,
|
uploadedImageSrc,
|
||||||
uploadedImageAlt,
|
uploadedImageAlt,
|
||||||
uploadedImageRefreshKey = null,
|
uploadedImageRefreshKey = null,
|
||||||
|
mainImagePreviewZIndexClassName = 'z-[82]',
|
||||||
mainImageMeta = null,
|
mainImageMeta = null,
|
||||||
mainImageInputId,
|
mainImageInputId,
|
||||||
mainImageAccept = DEFAULT_IMAGE_ACCEPT,
|
mainImageAccept = DEFAULT_IMAGE_ACCEPT,
|
||||||
@@ -524,7 +526,7 @@ export function CreativeImageInputPanel({
|
|||||||
}
|
}
|
||||||
closeVariant="profileCompact"
|
closeVariant="profileCompact"
|
||||||
size="xl"
|
size="xl"
|
||||||
zIndexClassName="z-[82]"
|
zIndexClassName={mainImagePreviewZIndexClassName}
|
||||||
overlayClassName="px-4 py-6"
|
overlayClassName="px-4 py-6"
|
||||||
panelClassName="platform-remap-surface rounded-[1.35rem] p-3 shadow-[0_24px_70px_rgba(15,23,42,0.22)]"
|
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"
|
headerClassName="mb-3 items-center border-b-0 px-1 py-0"
|
||||||
|
|||||||
@@ -274,6 +274,8 @@ describe('PuzzleResultView', () => {
|
|||||||
const levelImage = screen.getByRole('img', { name: '雨夜猫街' });
|
const levelImage = screen.getByRole('img', { name: '雨夜猫街' });
|
||||||
const mediaFrame = levelImage.closest('div.relative');
|
const mediaFrame = levelImage.closest('div.relative');
|
||||||
expect(mediaFrame?.className).toContain('aspect-[4/3]');
|
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(
|
expect(mediaFrame?.className).not.toContain(
|
||||||
'bg-[var(--platform-subpanel-fill)]',
|
'bg-[var(--platform-subpanel-fill)]',
|
||||||
);
|
);
|
||||||
@@ -552,6 +554,7 @@ describe('PuzzleResultView', () => {
|
|||||||
const imagePreviewDialog = screen.getByRole('dialog', {
|
const imagePreviewDialog = screen.getByRole('dialog', {
|
||||||
name: '查看关卡图片',
|
name: '查看关卡图片',
|
||||||
});
|
});
|
||||||
|
expect(imagePreviewDialog.parentElement?.className).toContain('z-[150]');
|
||||||
expect(within(imagePreviewDialog).getByAltText('暖灯猫街')).toBeTruthy();
|
expect(within(imagePreviewDialog).getByAltText('暖灯猫街')).toBeTruthy();
|
||||||
fireEvent.click(
|
fireEvent.click(
|
||||||
within(imagePreviewDialog).getByRole('button', {
|
within(imagePreviewDialog).getByRole('button', {
|
||||||
|
|||||||
@@ -724,6 +724,7 @@ function PuzzleLevelDetailDialog({
|
|||||||
promptReferenceImages={promptReferenceImages}
|
promptReferenceImages={promptReferenceImages}
|
||||||
promptReferenceLimit={PUZZLE_LEVEL_PROMPT_REFERENCE_LIMIT}
|
promptReferenceLimit={PUZZLE_LEVEL_PROMPT_REFERENCE_LIMIT}
|
||||||
imageLimitHint="图片≤6MB"
|
imageLimitHint="图片≤6MB"
|
||||||
|
mainImagePreviewZIndexClassName="z-[150]"
|
||||||
imageModelPicker={
|
imageModelPicker={
|
||||||
<PuzzleImageModelPicker
|
<PuzzleImageModelPicker
|
||||||
value={imageModel}
|
value={imageModel}
|
||||||
@@ -1069,6 +1070,7 @@ function PuzzleLevelListTab({
|
|||||||
fallbackLabel="暂无正式图"
|
fallbackLabel="暂无正式图"
|
||||||
aspect="standard"
|
aspect="standard"
|
||||||
surface="none"
|
surface="none"
|
||||||
|
imageClassName="h-full w-full object-contain"
|
||||||
className="rounded-none"
|
className="rounded-none"
|
||||||
fallbackClassName="tracking-normal text-[var(--platform-text-soft)]"
|
fallbackClassName="tracking-normal text-[var(--platform-text-soft)]"
|
||||||
previewOverlay={
|
previewOverlay={
|
||||||
|
|||||||
Reference in New Issue
Block a user