B-214: keep desktop header commands visible instead of behind ellipsis
Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
f311580d02
commit
6ae0f5f862
@@ -372,9 +372,9 @@
|
|||||||
"css_layers": [
|
"css_layers": [
|
||||||
"/shared/tokens.css?v=20260820-2",
|
"/shared/tokens.css?v=20260820-2",
|
||||||
"/shared/base.css?v=20260806-1",
|
"/shared/base.css?v=20260806-1",
|
||||||
"/shared/shell.css?v=20260820-2",
|
"/shared/shell.css?v=20260820-5",
|
||||||
"/shared/auth.css?v=20260820-3",
|
"/shared/auth.css?v=20260820-4",
|
||||||
"/shared/components/controls.css?v=20260820-1",
|
"/shared/components/controls.css?v=20260820-2",
|
||||||
"/shared/components/navigation.css?v=20260820-1",
|
"/shared/components/navigation.css?v=20260820-1",
|
||||||
"/shared/components/cards.css?v=20260820-1",
|
"/shared/components/cards.css?v=20260820-1",
|
||||||
"/shared/components/tables.css?v=20260820-1",
|
"/shared/components/tables.css?v=20260820-1",
|
||||||
@@ -451,8 +451,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "frontend/shared/shell.css",
|
"path": "frontend/shared/shell.css",
|
||||||
"bytes": 62384,
|
"bytes": 63204,
|
||||||
"lines": 3718
|
"lines": 3761
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "backend/features/heaven/engine.py",
|
"path": "backend/features/heaven/engine.py",
|
||||||
@@ -461,7 +461,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "frontend/index.html",
|
"path": "frontend/index.html",
|
||||||
"bytes": 47056,
|
"bytes": 47131,
|
||||||
"lines": 646
|
"lines": 646
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-7
@@ -19,9 +19,9 @@
|
|||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="/shared/tokens.css?v=20260820-2">
|
<link rel="stylesheet" href="/shared/tokens.css?v=20260820-2">
|
||||||
<link rel="stylesheet" href="/shared/base.css?v=20260806-1">
|
<link rel="stylesheet" href="/shared/base.css?v=20260806-1">
|
||||||
<link rel="stylesheet" href="/shared/shell.css?v=20260820-2">
|
<link rel="stylesheet" href="/shared/shell.css?v=20260820-5">
|
||||||
<link rel="stylesheet" href="/shared/auth.css?v=20260820-3">
|
<link rel="stylesheet" href="/shared/auth.css?v=20260820-4">
|
||||||
<link rel="stylesheet" href="/shared/components/controls.css?v=20260820-1">
|
<link rel="stylesheet" href="/shared/components/controls.css?v=20260820-2">
|
||||||
<link rel="stylesheet" href="/shared/components/navigation.css?v=20260820-1">
|
<link rel="stylesheet" href="/shared/components/navigation.css?v=20260820-1">
|
||||||
<link rel="stylesheet" href="/shared/components/cards.css?v=20260820-1">
|
<link rel="stylesheet" href="/shared/components/cards.css?v=20260820-1">
|
||||||
<link rel="stylesheet" href="/shared/components/tables.css?v=20260820-1">
|
<link rel="stylesheet" href="/shared/components/tables.css?v=20260820-1">
|
||||||
@@ -137,12 +137,12 @@
|
|||||||
<button class="button mobile-command-shortcut" type="button" data-mobile-command-target="alertButton"><i data-lucide="bell"></i><span>提醒</span></button>
|
<button class="button mobile-command-shortcut" type="button" data-mobile-command-target="alertButton"><i data-lucide="bell"></i><span>提醒</span></button>
|
||||||
<button class="button mobile-command-shortcut" type="button" data-mobile-command-target="assistantButton"><i data-lucide="message-circle-more"></i><span>助手</span></button>
|
<button class="button mobile-command-shortcut" type="button" data-mobile-command-target="assistantButton"><i data-lucide="message-circle-more"></i><span>助手</span></button>
|
||||||
</div>
|
</div>
|
||||||
<button id="refreshButton" class="button command-button" type="button"><i data-lucide="refresh-cw"></i><span>刷新</span></button>
|
<button id="refreshButton" class="button command-button" type="button" title="刷新"><i data-lucide="refresh-cw"></i><span>刷新</span></button>
|
||||||
<button id="syncButton" class="button primary command-button" type="button" hidden><i data-lucide="cloud-download"></i><span>后台刷新</span></button>
|
<button id="syncButton" class="button primary command-button" type="button" title="后台刷新" hidden><i data-lucide="cloud-download"></i><span>后台刷新</span></button>
|
||||||
<button id="settingsButton" class="button command-button" type="button" hidden><i data-lucide="settings-2"></i><span>系统管理</span></button>
|
<button id="settingsButton" class="button command-button" type="button" title="系统管理" hidden><i data-lucide="settings-2"></i><span>系统管理</span></button>
|
||||||
<div class="account-menu-shell">
|
<div class="account-menu-shell">
|
||||||
<div id="accountRoleBadges" class="account-role-badges" aria-label="账号身份">
|
<div id="accountRoleBadges" class="account-role-badges" aria-label="账号身份">
|
||||||
<span id="accountAdminBadge" class="account-role-badge admin-role-badge" hidden><i data-lucide="shield-check"></i><span>管理员</span></span>
|
<span id="accountAdminBadge" class="account-role-badge admin-role-badge" title="管理员" hidden><i data-lucide="shield-check"></i><span>管理员</span></span>
|
||||||
<button id="accountVipBadge" class="account-role-badge vip-role-badge" type="button" title="查看会员状态" hidden><b aria-hidden="true">V</b><span id="accountVipLabel">非会员</span></button>
|
<button id="accountVipBadge" class="account-role-badge vip-role-badge" type="button" title="查看会员状态" hidden><b aria-hidden="true">V</b><span id="accountVipLabel">非会员</span></button>
|
||||||
</div>
|
</div>
|
||||||
<button id="accountButton" class="button account-button command-button" type="button" title="账号菜单" aria-haspopup="menu" aria-expanded="false" aria-controls="accountDropdown"><i data-lucide="circle-user-round"></i><span id="accountName">--</span><i class="account-menu-chevron" data-lucide="chevron-down"></i></button>
|
<button id="accountButton" class="button account-button command-button" type="button" title="账号菜单" aria-haspopup="menu" aria-expanded="false" aria-controls="accountDropdown"><i data-lucide="circle-user-round"></i><span id="accountName">--</span><i class="account-menu-chevron" data-lucide="chevron-down"></i></button>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
"/pages/review/page.js?v=20260729-1",
|
"/pages/review/page.js?v=20260729-1",
|
||||||
"/shared/state.js?v=20260729-1",
|
"/shared/state.js?v=20260729-1",
|
||||||
"/shared/api.js?v=20260729-1",
|
"/shared/api.js?v=20260729-1",
|
||||||
"/shared/shell.js?v=20260820-1",
|
"/shared/shell.js?v=20260820-2",
|
||||||
"/shared/export.js?v=20260731-1",
|
"/shared/export.js?v=20260731-1",
|
||||||
"/pages/heaven/loading-v2.js?v=20260728-2",
|
"/pages/heaven/loading-v2.js?v=20260728-2",
|
||||||
"/shared/context.js?v=20260804-1",
|
"/shared/context.js?v=20260804-1",
|
||||||
|
|||||||
@@ -1179,27 +1179,27 @@ button.account-role-badge:focus-visible {
|
|||||||
gap: 3px;
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1280px) and (max-width: 1510px) {
|
@media (min-width: 1280px) {
|
||||||
.app-header .header-command-group .account-role-badge span {
|
.app-header .header-command-group .account-role-badge span {
|
||||||
display: inline;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group .account-role-badge {
|
.app-header .header-command-group .account-role-badge {
|
||||||
min-width: 0;
|
min-width: 28px;
|
||||||
|
|
||||||
justify-content: flex-start;
|
justify-content: center;
|
||||||
|
|
||||||
|
padding-inline: 6px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1380px) and (max-width: 1510px) {
|
|
||||||
#settingsButton,
|
|
||||||
.header-command-group .account-button {
|
.header-command-group .account-button {
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
||||||
padding: 0px 9px;
|
max-width: 108px;
|
||||||
|
|
||||||
|
padding: 0px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#settingsButton > span,
|
|
||||||
.header-command-group .account-button > span {
|
.header-command-group .account-button > span {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -635,14 +635,16 @@ body.sidebar-collapsed .sidebar-collapse-button .lucide {
|
|||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1280px) and (max-width: 1510px) {
|
@media (min-width: 1280px) {
|
||||||
.header-command-group .command-button {
|
.header-command-group .command-button:not(.account-button) {
|
||||||
width: 31px;
|
width: 32px;
|
||||||
|
|
||||||
|
min-width: 32px;
|
||||||
|
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-command-group .command-button > span {
|
.header-command-group .command-button:not(.account-button) > span {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1012,7 @@ textarea {
|
|||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.header-menu-button {
|
.header-menu-button {
|
||||||
display: inline-flex;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+79
-36
@@ -3013,6 +3013,11 @@ body.sidebar-collapsed .status-bar {
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.mobile-shell .header-command-group .account-button > span,
|
||||||
|
body.mobile-shell .header-command-group .account-role-badge span {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
body.mobile-shell .header-command-group .account-dropdown {
|
body.mobile-shell .header-command-group .account-dropdown {
|
||||||
position: static;
|
position: static;
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
@@ -3329,8 +3334,24 @@ body.sidebar-collapsed .status-bar {
|
|||||||
color: var(--warn);
|
color: var(--warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tape-sentiment .sentiment-gauge {
|
@media (min-width: 1440px) and (max-width: 1599px) {
|
||||||
|
.app-header .overview-strip .tape-sentiment.sentiment-block {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header .overview-strip .tape-sentiment .metric-label,
|
||||||
|
.app-header .overview-strip .tape-sentiment .sentiment-text {
|
||||||
|
font-size: var(--fs-caption);
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header .overview-strip .tape-sentiment > .sentiment-gauge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
display: none;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -3573,12 +3594,43 @@ body.sidebar-collapsed .status-bar {
|
|||||||
--focus-ring: rgba(108, 168, 232, .22);
|
--focus-ring: rgba(108, 168, 232, .22);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) and (max-width: 1439px) {
|
@media (min-width: 1024px) and (max-width: 1599px) {
|
||||||
.tape-optional {
|
.tape-optional {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1280px) {
|
||||||
|
.tape-metric {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header {
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1280px) and (max-width: 1599px) {
|
||||||
|
.app-page-context {
|
||||||
|
min-width: 96px;
|
||||||
|
max-width: 128px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header .header-actions {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header .header-command-group {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1440px) {
|
||||||
|
.app-page-context {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1023px) {
|
@media (max-width: 1023px) {
|
||||||
.app-header {
|
.app-header {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -3587,10 +3639,6 @@ body.sidebar-collapsed .status-bar {
|
|||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-page-context {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header .overview-strip,
|
.app-header .overview-strip,
|
||||||
.app-header .overview-strip[data-overview-expanded="true"] {
|
.app-header .overview-strip[data-overview-expanded="true"] {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
@@ -3653,53 +3701,48 @@ body.sidebar-collapsed .status-bar {
|
|||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.app-header .header-menu-button {
|
.app-header .header-menu-button {
|
||||||
display: inline-flex;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group {
|
.app-header .header-command-group {
|
||||||
position: absolute;
|
position: static;
|
||||||
top: calc(100% + 8px);
|
|
||||||
right: 0;
|
|
||||||
z-index: 60;
|
|
||||||
display: none;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: 6px;
|
|
||||||
width: 240px;
|
|
||||||
padding: 8px;
|
|
||||||
overflow: visible;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
background: var(--surface);
|
|
||||||
box-shadow: var(--shadow-float);
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header .header-command-group.is-open {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
padding: 0;
|
||||||
|
overflow: visible;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group .command-button,
|
.app-header .header-command-group .command-button,
|
||||||
.app-header .header-command-group .account-button {
|
.app-header .header-command-group .account-button {
|
||||||
width: 100%;
|
width: auto;
|
||||||
justify-content: flex-start;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group .account-menu-shell {
|
.app-header .header-command-group .account-menu-shell {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
align-items: center;
|
||||||
width: 100%;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group .account-role-badges {
|
.app-header .header-command-group .account-role-badges {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: nowrap;
|
||||||
min-height: 0;
|
min-height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header .header-command-group .account-dropdown {
|
.app-header .header-command-group .account-dropdown {
|
||||||
left: 0;
|
left: auto;
|
||||||
right: auto;
|
right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,19 @@
|
|||||||
const button = document.querySelector("#headerMenuButton");
|
const button = document.querySelector("#headerMenuButton");
|
||||||
const backdrop = document.querySelector("#mobileCommandBackdrop");
|
const backdrop = document.querySelector("#mobileCommandBackdrop");
|
||||||
if (!menu || !button) return;
|
if (!menu || !button) return;
|
||||||
|
if (!isMobileViewport()) {
|
||||||
|
menu.classList.remove("is-open");
|
||||||
|
button.setAttribute("aria-expanded", "false");
|
||||||
|
document.body.classList.remove("mobile-command-open");
|
||||||
|
if (backdrop) backdrop.hidden = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
const open = typeof force === "boolean" ? force : !menu.classList.contains("is-open");
|
const open = typeof force === "boolean" ? force : !menu.classList.contains("is-open");
|
||||||
menu.classList.toggle("is-open", open);
|
menu.classList.toggle("is-open", open);
|
||||||
button.setAttribute("aria-expanded", String(open));
|
button.setAttribute("aria-expanded", String(open));
|
||||||
document.body.classList.toggle("mobile-command-open", open && isMobileViewport());
|
document.body.classList.toggle("mobile-command-open", open);
|
||||||
if (backdrop) backdrop.hidden = !(open && isMobileViewport());
|
if (backdrop) backdrop.hidden = !open;
|
||||||
if (open && isMobileViewport()) {
|
if (open) {
|
||||||
global.requestAnimationFrame(() => menu.querySelector("button:not([hidden])")?.focus({ preventScroll: true }));
|
global.requestAnimationFrame(() => menu.querySelector("button:not([hidden])")?.focus({ preventScroll: true }));
|
||||||
} else if (force === false && document.activeElement && menu.contains(document.activeElement)) {
|
} else if (force === false && document.activeElement && menu.contains(document.activeElement)) {
|
||||||
button.focus({ preventScroll: true });
|
button.focus({ preventScroll: true });
|
||||||
|
|||||||
+119
-3
@@ -3198,10 +3198,10 @@ test("merged header keeps date, detail fields and 13 pool columns after dual-rev
|
|||||||
dashboard.limits = previousLimits;
|
dashboard.limits = previousLimits;
|
||||||
await page.waitForTimeout(400);
|
await page.waitForTimeout(400);
|
||||||
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
|
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
|
||||||
await expect(page.locator("#headerMenuButton")).toBeVisible();
|
await expect(page.locator("#headerMenuButton")).toBeHidden();
|
||||||
await expect(page.locator("#headerCommandGroup")).toBeHidden();
|
await expect(page.locator("#headerCommandGroup")).toBeVisible();
|
||||||
await expect(page.locator("#themeToggle")).toBeVisible();
|
await expect(page.locator("#themeToggle")).toBeVisible();
|
||||||
await expect(page.locator("#refreshButton")).toBeHidden();
|
await expect(page.locator("#refreshButton")).toBeVisible();
|
||||||
|
|
||||||
await page.locator('[data-view="limitPool"]').first().click();
|
await page.locator('[data-view="limitPool"]').first().click();
|
||||||
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
|
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
|
||||||
@@ -3377,3 +3377,119 @@ test("B-199 screener review and account surfaces fit day night viewports", async
|
|||||||
|
|
||||||
expect(pageErrors).toEqual([]);
|
expect(pageErrors).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("desktop header keeps refresh, admin commands and account identity visible", async ({ page }) => {
|
||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const shotDir = path.join(__dirname, "../../runtime/b214-shots");
|
||||||
|
fs.mkdirSync(shotDir, { recursive: true });
|
||||||
|
const pageErrors = [];
|
||||||
|
page.on("pageerror", (error) => pageErrors.push(String(error)));
|
||||||
|
await mockApplication(page, session("admin", true));
|
||||||
|
await page.goto("/index.html");
|
||||||
|
const shot = (name) => page.locator(".app-header").screenshot({ path: path.join(shotDir, `${name}.png`) });
|
||||||
|
const shotPage = (name) => page.screenshot({ path: path.join(shotDir, `${name}.png`) });
|
||||||
|
|
||||||
|
const measureHeader = () => page.evaluate(() => {
|
||||||
|
const header = document.querySelector(".app-header");
|
||||||
|
const tape = document.querySelector(".market-tape");
|
||||||
|
const actions = document.querySelector(".header-actions");
|
||||||
|
const refresh = document.querySelector("#refreshButton");
|
||||||
|
const account = document.querySelector("#accountButton");
|
||||||
|
const name = document.querySelector("#accountName");
|
||||||
|
const box = (node) => node ? node.getBoundingClientRect() : null;
|
||||||
|
const visible = (node) => {
|
||||||
|
if (!node || node.hidden) return false;
|
||||||
|
const style = getComputedStyle(node);
|
||||||
|
if (style.display === "none" || style.visibility === "hidden") return false;
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
return rect.width > 0 && rect.height > 0;
|
||||||
|
};
|
||||||
|
const tapeBox = box(tape);
|
||||||
|
const actionsBox = box(actions);
|
||||||
|
return {
|
||||||
|
headerOverflow: header ? header.scrollWidth - header.clientWidth : 0,
|
||||||
|
documentOverflow: document.documentElement.scrollWidth - window.innerWidth,
|
||||||
|
tapeHeight: tapeBox ? tapeBox.height : 0,
|
||||||
|
overlap: tapeBox && actionsBox
|
||||||
|
? Math.max(0, Math.min(tapeBox.right, actionsBox.right) - Math.max(tapeBox.left, actionsBox.left))
|
||||||
|
* Math.max(0, Math.min(tapeBox.bottom, actionsBox.bottom) - Math.max(tapeBox.top, actionsBox.top))
|
||||||
|
: 0,
|
||||||
|
refreshVisible: visible(refresh),
|
||||||
|
accountVisible: visible(account),
|
||||||
|
nameVisible: visible(name),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const viewport of [
|
||||||
|
{ width: 1600, height: 1000 },
|
||||||
|
{ width: 1440, height: 900 },
|
||||||
|
{ width: 1280, height: 800 },
|
||||||
|
]) {
|
||||||
|
await page.setViewportSize(viewport);
|
||||||
|
await expect(page.locator("#headerMenuButton")).toBeHidden();
|
||||||
|
await expect(page.locator("#headerCommandGroup")).toBeVisible();
|
||||||
|
await expect(page.locator("#refreshButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#syncButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#settingsButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountAdminBadge")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountVipBadge")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountName")).toBeVisible();
|
||||||
|
const geometry = await measureHeader();
|
||||||
|
expect(geometry.headerOverflow, `${viewport.width} header overflow`).toBeLessThanOrEqual(1);
|
||||||
|
expect(geometry.documentOverflow, `${viewport.width} document overflow`).toBeLessThanOrEqual(1);
|
||||||
|
expect(geometry.overlap, `${viewport.width} tape overlap`).toBe(0);
|
||||||
|
expect(geometry.tapeHeight, `${viewport.width} tape height`).toBeGreaterThan(20);
|
||||||
|
await page.locator("#refreshButton").click();
|
||||||
|
await expect(page.locator("#loadingOverlay")).toBeHidden();
|
||||||
|
await page.locator("#settingsButton").click();
|
||||||
|
await expect(page.locator("#adminDialog")).toBeVisible();
|
||||||
|
await page.locator("#closeAdminDialog").click();
|
||||||
|
await page.locator("#accountButton").click();
|
||||||
|
await expect(page.locator("#accountDropdown")).toBeVisible();
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
await shot(`${viewport.width}-day`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.locator("#themeToggle").click();
|
||||||
|
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||||
|
await page.setViewportSize({ width: 1600, height: 1000 });
|
||||||
|
await shot("1600-night");
|
||||||
|
await page.locator("#themeToggle").click();
|
||||||
|
|
||||||
|
await page.locator('[data-view="heavenView"]').first().click();
|
||||||
|
await expect(page.locator("#heavenView")).toHaveClass(/active-view/);
|
||||||
|
await expect(page.locator("#refreshButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#headerMenuButton")).toBeHidden();
|
||||||
|
await shot("heaven-1600-day");
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 390, height: 844 });
|
||||||
|
await expect(page.locator("#headerMenuButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#refreshButton")).toBeHidden();
|
||||||
|
await page.locator("#headerMenuButton").click();
|
||||||
|
await expect(page.locator("#headerCommandGroup")).toBeVisible();
|
||||||
|
await expect(page.locator("#refreshButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#syncButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#settingsButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountAdminBadge")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountVipBadge")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountButton")).toBeVisible();
|
||||||
|
await expect(page.locator('[data-mobile-command-target="themeToggle"]')).toBeVisible();
|
||||||
|
await shotPage("390-menu-open");
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
await expect(page.locator("#headerCommandGroup")).toBeHidden();
|
||||||
|
|
||||||
|
await mockApplication(page, session("user", false));
|
||||||
|
await page.setViewportSize({ width: 1600, height: 1000 });
|
||||||
|
await page.goto("/index.html");
|
||||||
|
await expect(page.locator("#refreshButton")).toBeVisible();
|
||||||
|
await expect(page.locator("#syncButton")).toBeHidden();
|
||||||
|
await expect(page.locator("#settingsButton")).toBeHidden();
|
||||||
|
await expect(page.locator("#accountAdminBadge")).toBeHidden();
|
||||||
|
await expect(page.locator("#accountVipBadge")).toBeVisible();
|
||||||
|
await expect(page.locator("#accountName")).toHaveText("normal_user");
|
||||||
|
await shot("1600-user-day");
|
||||||
|
expect(pageErrors).toEqual([]);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user