From 48c6494e7368700324883581d974992e89c46471 Mon Sep 17 00:00:00 2001 From: leefer Date: Sun, 2 Aug 2026 14:08:48 +0800 Subject: [PATCH] fix: use page scrolling for dragon tiger --- config/architecture-inventory.json | 4 +- frontend/styles/design-system.css | 10 --- frontend/styles/redesign-v2.css | 41 +++-------- tests/e2e/app-shell.spec.js | 12 ++- tests/preservation_helpers.py | 113 ++++++++++++++++++++++++++++- 5 files changed, 132 insertions(+), 48 deletions(-) diff --git a/config/architecture-inventory.json b/config/architecture-inventory.json index bf5f700..19c9aff 100644 --- a/config/architecture-inventory.json +++ b/config/architecture-inventory.json @@ -314,8 +314,8 @@ }, { "path": "frontend/styles/redesign-v2.css", - "bytes": 262826, - "lines": 8554 + "bytes": 262113, + "lines": 8533 }, { "path": "frontend/index.html", diff --git a/frontend/styles/design-system.css b/frontend/styles/design-system.css index dcc452c..875ccc7 100644 --- a/frontend/styles/design-system.css +++ b/frontend/styles/design-system.css @@ -771,7 +771,6 @@ tbody tr.clickable{cursor:pointer} [data-active-view="auctionView"], [data-active-view="themeLibraryView"], [data-active-view="popularityView"], - [data-active-view="dragonView"], [data-active-view="mentorView"], [data-active-view="rotationView"] ) .app-main{ @@ -786,7 +785,6 @@ tbody tr.clickable{cursor:pointer} [data-active-view="auctionView"], [data-active-view="themeLibraryView"], [data-active-view="popularityView"], - [data-active-view="dragonView"], [data-active-view="mentorView"], [data-active-view="rotationView"] ) .overview-strip{flex:0 0 auto} @@ -795,7 +793,6 @@ tbody tr.clickable{cursor:pointer} [data-active-view="auctionView"], [data-active-view="themeLibraryView"], [data-active-view="popularityView"], - [data-active-view="dragonView"], [data-active-view="mentorView"], [data-active-view="rotationView"] ) .workspace-view.active-view{ @@ -807,7 +804,6 @@ tbody tr.clickable{cursor:pointer} #auctionView.active-view, #themeLibraryView.active-view, #popularityView.active-view, - #dragonView.active-view, #mentorView.active-view{display:flex;flex-direction:column} #rotationView.active-view{ @@ -827,7 +823,6 @@ tbody tr.clickable{cursor:pointer} #themeLibraryView .theme-summary-v2, #popularityView .popularity-page-head-v2, #popularityView .popularity-glance-v2, - #dragonView .dragon-page-head-v2, #mentorView .mentor-page-header, #mentorView .member-gate, #mentorView #mentorNotice{flex:0 0 auto} @@ -835,7 +830,6 @@ tbody tr.clickable{cursor:pointer} #auctionView .auction-workspace-v2, #themeLibraryView .theme-library-workspace-v2, #popularityView .popularity-table-card-v2, - #dragonView .dragon-daily-content-v2, #mentorView .mentor-layout{min-height:0;flex:1 1 auto} #auctionView .auction-workspace-v2{height:100%;grid-template-columns:minmax(0,1fr) var(--right-rail-wide);grid-template-rows:minmax(0,1fr);align-items:stretch;overflow:hidden} @@ -853,10 +847,6 @@ tbody tr.clickable{cursor:pointer} #popularityView .popularity-table-card-v2{display:flex;flex-direction:column;overflow:hidden} #popularityView .popularity-table-frame-v2{min-height:0;flex:1 1 auto;overflow:auto} - #dragonView .dragon-daily-content-v2{overflow:hidden} - #dragonView .dragon-trader-detail-v2{min-height:0} - #dragonView .dragon-trader-detail .trader-operations{min-height:0;overflow:auto} - #mentorView .mentor-layout{height:auto;overflow:hidden} #mentorView .mentor-sidebar, #mentorView .mentor-chat-panel, diff --git a/frontend/styles/redesign-v2.css b/frontend/styles/redesign-v2.css index 56f8eef..5948eb6 100644 --- a/frontend/styles/redesign-v2.css +++ b/frontend/styles/redesign-v2.css @@ -4350,17 +4350,11 @@ body.sidebar-collapsed .status-bar { left: 64px; } .dragon-empty-actions-v2 .lucide { width: 15px; height: 15px; } @media (min-width: 721px) { - body[data-active-view="dragonView"] .app-main { display: flex; flex-direction: column; overflow: hidden; } - body[data-active-view="dragonView"] .overview-strip { flex: 0 0 auto; } + body[data-active-view="dragonView"] .app-main { height: var(--workspace-height); min-height: 0; display: block; overflow: auto; } body[data-active-view="dragonView"] #dragonView.active-view { - min-height: 0; - flex: 1 1 auto; - display: flex; - flex-direction: column; + display: block; + overflow: visible; } - body[data-active-view="dragonView"] .dragon-page-head-v2 { flex: 0 0 auto; } - body[data-active-view="dragonView"] .dragon-daily-content-v2, - body[data-active-view="dragonView"] .dragon-empty-state-v2 { flex: 1 1 auto; } } @media (min-width: 721px) and (max-height: 900px) { @@ -8372,40 +8366,25 @@ body.sidebar-collapsed .status-bar { left: 64px; } white-space: nowrap; } -/* The Dragon-Tiger page stays still; only the selected trader's operations scroll. */ +/* The Dragon-Tiger page owns vertical scrolling; wide operation tables scroll horizontally. */ @media (min-width: 721px) { body[data-active-view="dragonView"] .dragon-daily-content-v2 { - min-height: 0; - display: grid; - grid-template-rows: auto auto auto minmax(150px, 1fr) auto; - overflow: hidden; - } - - body[data-active-view="dragonView"] #dragonView .dragon-card-stage-v2 { - flex: 0 0 auto; + display: block; + overflow: visible; } body[data-active-view="dragonView"] #dragonView .dragon-trader-detail-v2 { - min-height: 0; - display: flex; - flex-direction: column; - } - - body[data-active-view="dragonView"] #dragonView .dragon-detail-header { - flex: 0 0 auto; + display: block; } body[data-active-view="dragonView"] #dragonView .dragon-trader-detail .trader-operations { - min-height: 0; - flex: 1 1 auto; + max-height: none; overflow: auto; - overscroll-behavior: contain; - scrollbar-gutter: stable; } body[data-active-view="dragonView"] #dragonView .dragon-unclassified-v2 { - max-height: 180px; - overflow: auto; + max-height: none; + overflow: visible; } :is( diff --git a/tests/e2e/app-shell.spec.js b/tests/e2e/app-shell.spec.js index e377bb4..39a3489 100644 --- a/tests/e2e/app-shell.spec.js +++ b/tests/e2e/app-shell.spec.js @@ -1400,25 +1400,31 @@ test("dragon-tiger redesign keeps the merged empty state and independent card hi await expect(page.locator("#stockDialog")).toBeVisible(); await page.locator("#closeStockDialog").click(); + await page.setViewportSize({ width: 1366, height: 768 }); const scrollOwnership = await page.evaluate(() => { const body = document.querySelector("#dragonTraderDetail tbody"); const seed = body.querySelector("tr"); for (let index = 0; index < 20; index += 1) body.appendChild(seed.cloneNode(true)); + const main = document.querySelector(".app-main"); const daily = document.querySelector("#dragonDailyContent"); const operations = document.querySelector("#dragonTraderDetail .trader-operations"); return { + mainOverflow: getComputedStyle(main).overflowY, + pageScrolls: main.scrollHeight > main.clientHeight, dailyOverflow: getComputedStyle(daily).overflowY, dailyFits: daily.scrollHeight <= daily.clientHeight + 1, operationOverflow: getComputedStyle(operations).overflowY, - operationsScroll: operations.scrollHeight > operations.clientHeight, + operationsFit: operations.scrollHeight <= operations.clientHeight + 1, descriptionSize: parseFloat(getComputedStyle(document.querySelector("#dragonTraderDetail .dragon-detail-header p")).fontSize), }; }); expect(scrollOwnership).toEqual({ - dailyOverflow: "hidden", + mainOverflow: "auto", + pageScrolls: true, + dailyOverflow: "visible", dailyFits: true, operationOverflow: "auto", - operationsScroll: true, + operationsFit: true, descriptionSize: 13, }); diff --git a/tests/preservation_helpers.py b/tests/preservation_helpers.py index edb431c..1c20683 100644 --- a/tests/preservation_helpers.py +++ b/tests/preservation_helpers.py @@ -151,6 +151,106 @@ AUDITED_CSS_RETIREMENTS = { ), } +# User-approved product behavior changes remain separate from code-retirement +# records. Each entry is an exact source/replacement pair. Optional trailing +# values declare the expected source count and how many leading occurrences to +# transform when one identical occurrence must remain. +AUDITED_CSS_REPLACEMENTS = { + "redesign-v2.css": ( + ( + ( + '@media (min-width: 721px) {\n' + ' body[data-active-view="dragonView"] .app-main { display: flex; flex-direction: column; overflow: hidden; }\n' + ' body[data-active-view="dragonView"] .overview-strip { flex: 0 0 auto; }\n' + ' body[data-active-view="dragonView"] #dragonView.active-view {\n' + ' min-height: 0;\n' + ' flex: 1 1 auto;\n' + ' display: flex;\n' + ' flex-direction: column;\n' + ' }\n' + ' body[data-active-view="dragonView"] .dragon-page-head-v2 { flex: 0 0 auto; }\n' + ' body[data-active-view="dragonView"] .dragon-daily-content-v2,\n' + ' body[data-active-view="dragonView"] .dragon-empty-state-v2 { flex: 1 1 auto; }\n' + '}\n' + ), + ( + '@media (min-width: 721px) {\n' + ' body[data-active-view="dragonView"] .app-main { height: var(--workspace-height); min-height: 0; display: block; overflow: auto; }\n' + ' body[data-active-view="dragonView"] #dragonView.active-view {\n' + ' display: block;\n' + ' overflow: visible;\n' + ' }\n' + '}\n' + ), + ), + ( + ( + "/* The Dragon-Tiger page stays still; only the selected trader's operations scroll. */\n" + '@media (min-width: 721px) {\n' + ' body[data-active-view="dragonView"] .dragon-daily-content-v2 {\n' + ' min-height: 0;\n' + ' display: grid;\n' + ' grid-template-rows: auto auto auto minmax(150px, 1fr) auto;\n' + ' overflow: hidden;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-card-stage-v2 {\n' + ' flex: 0 0 auto;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-trader-detail-v2 {\n' + ' min-height: 0;\n' + ' display: flex;\n' + ' flex-direction: column;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-detail-header {\n' + ' flex: 0 0 auto;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-trader-detail .trader-operations {\n' + ' min-height: 0;\n' + ' flex: 1 1 auto;\n' + ' overflow: auto;\n' + ' overscroll-behavior: contain;\n' + ' scrollbar-gutter: stable;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-unclassified-v2 {\n' + ' max-height: 180px;\n' + ' overflow: auto;\n' + ' }\n' + ), + ( + '/* The Dragon-Tiger page owns vertical scrolling; wide operation tables scroll horizontally. */\n' + '@media (min-width: 721px) {\n' + ' body[data-active-view="dragonView"] .dragon-daily-content-v2 {\n' + ' display: block;\n' + ' overflow: visible;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-trader-detail-v2 {\n' + ' display: block;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-trader-detail .trader-operations {\n' + ' max-height: none;\n' + ' overflow: auto;\n' + ' }\n\n' + ' body[data-active-view="dragonView"] #dragonView .dragon-unclassified-v2 {\n' + ' max-height: none;\n' + ' overflow: visible;\n' + ' }\n' + ), + ), + ), + "design-system.css": ( + (' [data-active-view="dragonView"],\n', "", 4, 3), + (' #dragonView.active-view,\n', ""), + (' #dragonView .dragon-page-head-v2,\n', ""), + (' #dragonView .dragon-daily-content-v2,\n', ""), + ( + ' #dragonView .dragon-daily-content-v2{overflow:hidden}\n' + ' #dragonView .dragon-trader-detail-v2{min-height:0}\n' + ' #dragonView .dragon-trader-detail .trader-operations{min-height:0;overflow:auto}\n\n', + "", + ), + ), +} + def sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() @@ -245,12 +345,21 @@ def assert_moved_asset_matches( frontend_relative: str | None = None, ) -> None: target_relative = frontend_relative or original_relative - if original_relative in AUDITED_CSS_RETIREMENTS: + if ( + original_relative in AUDITED_CSS_RETIREMENTS + or original_relative in AUDITED_CSS_REPLACEMENTS + ): original = (ORIGINAL_STATIC / original_relative).read_text(encoding="utf-8") - for retired in AUDITED_CSS_RETIREMENTS[original_relative]: + for retired in AUDITED_CSS_RETIREMENTS.get(original_relative, ()): source, replacement = retired if isinstance(retired, tuple) else (retired, "") testcase.assertEqual(original.count(source), 1, source) original = original.replace(source, replacement, 1) + for replacement in AUDITED_CSS_REPLACEMENTS.get(original_relative, ()): + source, target, *count_override = replacement + expected_count = count_override[0] if count_override else 1 + replacement_count = count_override[1] if len(count_override) > 1 else expected_count + testcase.assertEqual(original.count(source), expected_count, source) + original = original.replace(source, target, replacement_count) testcase.assertEqual( (FRONTEND_ROOT / target_relative).read_text(encoding="utf-8"), original,