Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edbefcc738 |
@@ -0,0 +1,152 @@
|
|||||||
|
:root {
|
||||||
|
--dada-interaction-duration: 120ms;
|
||||||
|
--dada-interaction-easing: cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(button:not(:disabled), a[href], label:has(input:not(:disabled))) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(button:not(:disabled), a[href]) {
|
||||||
|
transition:
|
||||||
|
transform var(--dada-interaction-duration) var(--dada-interaction-easing),
|
||||||
|
box-shadow var(--dada-interaction-duration) var(--dada-interaction-easing),
|
||||||
|
border-color var(--dada-interaction-duration) ease,
|
||||||
|
background-color var(--dada-interaction-duration) ease,
|
||||||
|
color var(--dada-interaction-duration) ease,
|
||||||
|
opacity var(--dada-interaction-duration) ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(input:not(:disabled), select:not(:disabled), textarea:not(:disabled)) {
|
||||||
|
transition:
|
||||||
|
border-color var(--dada-interaction-duration) ease,
|
||||||
|
box-shadow var(--dada-interaction-duration) ease,
|
||||||
|
background-color var(--dada-interaction-duration) ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.product-page, .product-loading) :focus-visible {
|
||||||
|
outline: 2px solid #005fcc;
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(input:not(:disabled), select:not(:disabled), textarea:not(:disabled)):focus-visible {
|
||||||
|
border-color: #005fcc;
|
||||||
|
box-shadow: 0 0 0 3px rgb(0 95 204 / 16%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card,
|
||||||
|
.project-preview img,
|
||||||
|
.ratio-control span,
|
||||||
|
.reference-input,
|
||||||
|
.editor-sticker-preview,
|
||||||
|
.editor-template-mark,
|
||||||
|
.editor-color-card-preview,
|
||||||
|
.editor-dynamic-preview,
|
||||||
|
.editor-source-preview-canvas,
|
||||||
|
.editor-thumb {
|
||||||
|
transition:
|
||||||
|
transform var(--dada-interaction-duration) var(--dada-interaction-easing),
|
||||||
|
box-shadow var(--dada-interaction-duration) var(--dada-interaction-easing),
|
||||||
|
border-color var(--dada-interaction-duration) ease,
|
||||||
|
background-color var(--dada-interaction-duration) ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: hover) and (pointer: fine) {
|
||||||
|
:where(button:not(:disabled)):hover {
|
||||||
|
border-color: #111111;
|
||||||
|
box-shadow: 0 2px 0 rgb(17 17 17 / 35%);
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(a[href]):hover {
|
||||||
|
color: #005fcc;
|
||||||
|
opacity: 0.78;
|
||||||
|
text-decoration-thickness: 2px;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-header nav a:hover {
|
||||||
|
color: #111111;
|
||||||
|
background: #e9e9e5;
|
||||||
|
box-shadow: inset 0 -3px #111111;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-header nav a[aria-current="page"]:hover {
|
||||||
|
background: #f2f500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ratio-control label:hover span,
|
||||||
|
.reference-input:hover {
|
||||||
|
border-color: #111111;
|
||||||
|
background: #ffffd6;
|
||||||
|
box-shadow: inset 0 -3px #111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card:hover {
|
||||||
|
border-color: #111111;
|
||||||
|
box-shadow: 0 3px 0 rgb(17 17 17 / 22%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-asset-tabs button:not(:disabled):hover,
|
||||||
|
.editor-source:hover,
|
||||||
|
.editor-sticker-grid button:not(:disabled):hover,
|
||||||
|
.editor-template-categories button:not(:disabled):hover,
|
||||||
|
.editor-template-grid button:not(:disabled):hover,
|
||||||
|
.editor-provider-grid button:not(:disabled):hover,
|
||||||
|
.editor-candidates button:not(:disabled):hover {
|
||||||
|
border-color: #111111;
|
||||||
|
background: #ffffd6;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(input:not(:disabled), select:not(:disabled), textarea:not(:disabled)):hover {
|
||||||
|
border-color: #111111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
|
||||||
|
:where(button:not(:disabled), a[href]):hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card:hover .project-preview img,
|
||||||
|
.editor-sticker-grid button:not(:disabled):hover .editor-sticker-preview {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-template-grid button:not(:disabled):hover .editor-template-mark,
|
||||||
|
.editor-provider-grid button:not(:disabled):hover > :first-child {
|
||||||
|
transform: scale(1.03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
:where(button:not(:disabled), a[href]):active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
transition-duration: 45ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(button:not(:disabled)):active {
|
||||||
|
box-shadow: inset 0 2px 0 rgb(17 17 17 / 24%);
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(a[href]):active {
|
||||||
|
opacity: 0.58;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
:where(button, a[href], input, select, textarea),
|
||||||
|
.project-card,
|
||||||
|
.project-preview img,
|
||||||
|
.ratio-control span,
|
||||||
|
.reference-input,
|
||||||
|
.editor-sticker-preview,
|
||||||
|
.editor-template-mark,
|
||||||
|
.editor-color-card-preview,
|
||||||
|
.editor-dynamic-preview,
|
||||||
|
.editor-source-preview-canvas,
|
||||||
|
.editor-thumb {
|
||||||
|
animation-duration: 0s !important;
|
||||||
|
transition-duration: 0s !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@ import { ProjectDetailPage, ProjectsPage, WorkspacePage } from "./project-pages.
|
|||||||
import { EditorPage } from "./editor-page.js";
|
import { EditorPage } from "./editor-page.js";
|
||||||
import { AdminOverviewPage, AdminPlaceholderPage, AdminProtectedRoute } from "./admin-shell.js";
|
import { AdminOverviewPage, AdminPlaceholderPage, AdminProtectedRoute } from "./admin-shell.js";
|
||||||
|
|
||||||
|
import "./interaction-feedback.css";
|
||||||
|
|
||||||
const root = document.getElementById("root");
|
const root = document.getElementById("root");
|
||||||
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
|
|||||||
@@ -105,9 +105,21 @@ test("TDD-WP2-PROJ-005 limits failed-empty selection on the project list", async
|
|||||||
await expect(page.getByLabel("选择失败草稿:失败草稿")).toBeVisible();
|
await expect(page.getByLabel("选择失败草稿:失败草稿")).toBeVisible();
|
||||||
await expect(page.getByLabel("选择失败草稿:城市工作室")).toHaveCount(0);
|
await expect(page.getByLabel("选择失败草稿:城市工作室")).toHaveCount(0);
|
||||||
await page.getByLabel("选择失败草稿:失败草稿").check();
|
await page.getByLabel("选择失败草稿:失败草稿").check();
|
||||||
await page.getByRole("button", { name: "批量移入回收站" }).click();
|
const batchTrashButton = page.getByRole("button", { name: "批量移入回收站" });
|
||||||
|
await batchTrashButton.hover();
|
||||||
|
await expect(batchTrashButton).toHaveCSS("transform", "matrix(1, 0, 0, 1, 0, -1)");
|
||||||
|
const buttonBounds = await batchTrashButton.boundingBox();
|
||||||
|
if (!buttonBounds) throw new Error("Batch trash button geometry is unavailable.");
|
||||||
|
await page.mouse.move(buttonBounds.x + buttonBounds.width / 2, buttonBounds.y + buttonBounds.height / 2);
|
||||||
|
await page.mouse.down();
|
||||||
|
await expect(batchTrashButton).toHaveCSS("transform", "matrix(1, 0, 0, 1, 0, 1)");
|
||||||
|
await page.mouse.move(0, 0);
|
||||||
|
await page.mouse.up();
|
||||||
|
await batchTrashButton.click();
|
||||||
expect(batchPayload).toEqual({ project_ids: [failedId] });
|
expect(batchPayload).toEqual({ project_ids: [failedId] });
|
||||||
await expect(page.getByText("失败草稿已移入回收站")).toBeVisible();
|
await expect(page.getByText("失败草稿已移入回收站")).toBeVisible();
|
||||||
|
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||||
|
await expect(page.getByRole("link", { name: "打开项目:城市工作室" })).toHaveCSS("transition-duration", "0s");
|
||||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(375);
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(375);
|
||||||
await captureEvidence(page, "TDD-WP2-PROJ-005-failed-draft-retry", "projects-mobile.png");
|
await captureEvidence(page, "TDD-WP2-PROJ-005-failed-draft-retry", "projects-mobile.png");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -98,7 +98,11 @@ test("TDD-WP4-TXT-003 exposes the frozen catalog, display-name search and accoun
|
|||||||
await expect(page.locator(".editor-template-grid button")).toHaveCount(0);
|
await expect(page.locator(".editor-template-grid button")).toHaveCount(0);
|
||||||
await search.fill("");
|
await search.fill("");
|
||||||
expect(page.getByText("添加普通文字", { exact: true })).toHaveCount(0);
|
expect(page.getByText("添加普通文字", { exact: true })).toHaveCount(0);
|
||||||
await page.getByRole("button", { name: /FLOWER001 春日计划/ }).click();
|
const flowerTemplate = page.getByRole("button", { name: /FLOWER001 春日计划/ });
|
||||||
|
await flowerTemplate.hover();
|
||||||
|
await expect(flowerTemplate).toHaveCSS("background-color", "rgb(255, 255, 214)");
|
||||||
|
await expect(flowerTemplate.locator(".editor-template-mark")).toHaveCSS("transform", "matrix(1.03, 0, 0, 1.03, 0, 0)");
|
||||||
|
await flowerTemplate.click();
|
||||||
await expect(page.getByText("对象 1 / 50")).toBeVisible();
|
await expect(page.getByText("对象 1 / 50")).toBeVisible();
|
||||||
await expect.poll(() => backend.recent).toEqual([{ asset_id: "FLOWER001", asset_kind: "text_template", resource_version: "p0a-complex-v1" }]);
|
await expect.poll(() => backend.recent).toEqual([{ asset_id: "FLOWER001", asset_kind: "text_template", resource_version: "p0a-complex-v1" }]);
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
|||||||
Reference in New Issue
Block a user