Фиксы финального ревью: страница не шире окна (C-1), событие пакета на телефоне (I-1) (#69)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1f74a27cb3
commit
d3db88708b
@ -83,3 +83,9 @@
|
||||
| 4 | 22.10.2026 | Свёртка панели в полосу 64 px с запоминанием (решение 3) | доске нужна ширина; раз в спринт граф — тогда удобно свернуть | низкая |
|
||||
| 5 | 22.10.2026 | На узком экране — строка с «Меню» и выезжающая панель (решение 4) | закреплённая панель 4–5 строк (M-12 #65) съела бы экран | низкая: узкий экран — только «без поломок» |
|
||||
| 6 | 22.10.2026 | Развёрнута по умолчанию, ширина 240 px | на 1920 место есть; название проекта видно целиком | низкая |
|
||||
| 7 | 22.10.2026 | R-1: панель без `overflow-y:auto` (вопреки решению 1) | прокрутка панели обрезала бы меню «Ещё» свёрнутой панели, выходящее за 64 px | низкая: на окне ниже ~470 px низ панели обрезан (M-5) |
|
||||
| 8 | 22.10.2026 | R-2: в выезжающей панели «Закрыть меню» вместо «Свернуть панель» | свёртка внутри выезжающей панели бессмысленна (решение 4) | нет |
|
||||
| 9 | 22.10.2026 | R-3: e2e M-3 переходит по разделам обычным щелчком, не `dispatchEvent` | панель закреплена, щелчок больше не прокручивает доску; тест заодно проверяет закрепление | нет |
|
||||
| 10 | 22.10.2026 | R-4 (C-1): `.shell>.page{width:100%}` и `.page` — контейнер (`container: page/inline-size`); пороги раскладки страниц (фильтры списка, прокрутка таблицы, колонка ящика «Проблемы») — запросами к контейнеру с порогами «прежний порог окна минус поля страницы 48 px» | рядом панель 240/64 px: ширина страницы больше не равна ширине окна, и пороги по окну давали таблицу шире страницы | низкая: пороги — числа в CSS |
|
||||
| 11 | 22.10.2026 | R-5 (I-1): на узком экране событие пакета — строкой под закреплённой строкой (`aria-hidden`, озвучивает `role=status` кнопки) | на телефоне подсказок нет, результат «Обновить из Jira» был не виден | низкая: строка занимает 1–2 строки по высоте, пока есть событие |
|
||||
|
||||
|
||||
@ -42,3 +42,19 @@ test("390 px: «Меню» открывает панель, «Задачи» з
|
||||
await expect(page.getByTestId("page-issues")).toBeVisible();
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
});
|
||||
|
||||
test("C-1: на средних ширинах страница не шире окна — «Задачи» на 1280, доска на 1000 прокручивается сама", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await login(page, "/app/issues");
|
||||
await expect(page.locator("table.issue-table tbody tr").first()).toBeVisible();
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(1280);
|
||||
await page.setViewportSize({ width: 1000, height: 800 });
|
||||
await page.getByRole("link", { name: "Доска связей" }).click();
|
||||
await expect(page.locator(".board .card[data-key]").first()).toBeVisible();
|
||||
await page.getByRole("button", { name: "По датам" }).click();
|
||||
await expect(page.locator(".dcol").first()).toBeVisible();
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(1000);
|
||||
await expect(page.getByRole("button", { name: /Проблемы/ })).toBeInViewport();
|
||||
const wrap = page.locator(".wrap");
|
||||
expect(await wrap.evaluate((el) => el.scrollWidth > el.clientWidth)).toBe(true); // доска шире своей рамки — прокрутка внутри
|
||||
});
|
||||
|
||||
@ -167,7 +167,7 @@ td.k{font-family:var(--font-mono);font-size:12px;white-space:nowrap;color:var(--
|
||||
/* 9. Движение и узкие экраны */
|
||||
@media (prefers-reduced-motion:no-preference){.card{transition:border-color .15s}}
|
||||
@media (prefers-reduced-motion:reduce){.card .grip,.fold svg{transition:none}}
|
||||
@media (max-width:900px){.stage{flex-direction:column}.drawer{flex:none;max-width:100%;max-height:none;position:static}}
|
||||
@container page (max-width:852px){.stage{flex-direction:column}.drawer{flex:none;max-width:100%;max-height:none;position:static}}
|
||||
@media (max-width:640px){.sticky{position:static}.dates-bar{position:static}}
|
||||
@media (max-width:640px){.board-controls__sep,.legend .sep{display:none}}
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
.issue-filters__row .ui-btn[aria-pressed="true"],.issue-filters__row .ui-btn[aria-expanded="true"]{border-color:var(--color-border-selected);color:var(--color-action-primary)}
|
||||
.issue-filters__chips{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2)}
|
||||
.issue-filters__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-3) var(--space-4)}
|
||||
@media (max-width:899.98px){.issue-filters__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
@media (max-width:639.98px){.issue-filters__grid{grid-template-columns:minmax(0,1fr)}.issue-filters__search{max-width:none}}
|
||||
/* прокрутка внутри панели — только на узких экранах: overflow на предке отключает липкую шапку страницы */
|
||||
@media (max-width:1099.98px){.issue-table-wrap{overflow-x:auto}}
|
||||
@container page (max-width:851.98px){.issue-filters__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
@container page (max-width:607.98px){.issue-filters__grid{grid-template-columns:minmax(0,1fr)}.issue-filters__search{max-width:none}}
|
||||
/* прокрутка внутри панели — только при узкой странице: overflow на предке отключает липкую шапку страницы; пороги контейнера = прежние пороги окна минус поля страницы */
|
||||
@container page (max-width:1051.98px){.issue-table-wrap{overflow-x:auto}}
|
||||
.issue-table th:first-child{border-top-left-radius:calc(var(--radius-xl) - 1px)}
|
||||
.issue-table th:last-child{border-top-right-radius:calc(var(--radius-xl) - 1px)}
|
||||
.issue-table tbody tr:last-child td:first-child{border-bottom-left-radius:calc(var(--radius-xl) - 1px)}
|
||||
|
||||
@ -228,4 +228,15 @@ describe("боковая панель на узком экране", () => {
|
||||
await userEvent.click(within(bar()).getByRole("button", { name: "Закрыть меню" }));
|
||||
expect(screen.queryByRole("complementary", { name: "Панель приложения" })).toBeNull();
|
||||
});
|
||||
|
||||
it("I-1: событие пакета видно под строкой, не только в подсказке", async () => {
|
||||
hub();
|
||||
open("/app/board?project=AWPCA");
|
||||
const top = await screen.findByRole("banner", { name: "Строка приложения" });
|
||||
await userEvent.click(within(top).getByRole("button", { name: "Обновить из Jira" }));
|
||||
const strip = await screen.findByTestId("topbar-event");
|
||||
await waitFor(() => expect(strip).toHaveTextContent(/пакет #7 выполняется/));
|
||||
expect(strip).not.toHaveClass("visually-hidden");
|
||||
expect(strip).toHaveAttribute("aria-hidden", "true"); // озвучивает role=status кнопки, второй раз не нужно
|
||||
});
|
||||
});
|
||||
|
||||
@ -6,6 +6,8 @@ import { withProject } from "../projects/current.ts";
|
||||
import { ProjectPicker } from "../projects/ProjectPicker.tsx";
|
||||
import { IconBoard, IconButton, IconClose, IconList, IconMenu, IconSidebar, Menu, MenuItem, ThemeSwitch } from "../ui/index.ts";
|
||||
import { DataStatus } from "./DataStatus.tsx";
|
||||
import { useJiraRefresh } from "./refresh.ts";
|
||||
import { refreshText } from "./refreshStatus.ts";
|
||||
import { readSidebar, saveSidebar } from "./sidebarPref.ts";
|
||||
|
||||
export type Section = "/board" | "/issues";
|
||||
@ -37,6 +39,8 @@ function NarrowShell(p: Props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const menuBtn = useRef<HTMLButtonElement>(null);
|
||||
// объект стабилен, пока панель открыта: эффект фокуса и Escape в Panel не перезапускается на каждой отрисовке
|
||||
const refresh = useJiraRefresh();
|
||||
const rt = refresh.event ? refreshText(refresh.event) : null; // I-1: на телефоне подсказок нет — событие пакета строкой под панелью
|
||||
const drawer = useMemo(() => ({ close: () => { setOpen(false); menuBtn.current?.focus(); }, navigated: () => setOpen(false) }), []);
|
||||
return (
|
||||
<>
|
||||
@ -47,6 +51,7 @@ function NarrowShell(p: Props) {
|
||||
<span className="sidebar__spacer" />
|
||||
<DataStatus project={p.project} compact />
|
||||
</header>
|
||||
{rt && <div className={`topbar-event data-status__event--${rt.tone}`} data-testid="topbar-event" aria-hidden="true">{rt.text}</div>}
|
||||
{open && <>
|
||||
<div className="sidebar-backdrop" data-testid="sidebar-backdrop" onClick={drawer.close} />
|
||||
<Panel {...p} drawer={drawer} />
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
/* оболочка: боковая панель и страница (#69, design 1–3); прокрутка — у окна, панель липнет к его верху */
|
||||
.shell{display:grid;grid-template-columns:auto minmax(0,1fr);min-height:100vh}
|
||||
/* C-1: у элемента сетки с margin-inline:auto ширина — по содержимому; явная 100% держит страницу в своей дорожке */
|
||||
.shell>.page{width:100%;box-sizing:border-box}
|
||||
.sidebar{
|
||||
position:sticky;top:0;height:100vh;height:100dvh;width:240px;box-sizing:border-box;z-index:20;
|
||||
display:flex;flex-direction:column;gap:var(--space-4);padding:var(--space-4);
|
||||
@ -58,3 +60,7 @@
|
||||
.shell{display:block}
|
||||
:root{--topbar-h:56px}
|
||||
}
|
||||
.topbar-event{
|
||||
position:sticky;top:56px;z-index:19;padding:var(--space-2) var(--space-4);border-bottom:1px solid var(--color-border-default);
|
||||
background:var(--color-bg-subtle);font-size:var(--fs-caption);line-height:var(--lh-caption);font-weight:600;overflow-wrap:anywhere;
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@ html,body{min-height:100%}
|
||||
body{font:var(--fs-body)/var(--lh-body) var(--font-ui);background:var(--color-bg-canvas);color:var(--color-text-primary);margin:0}
|
||||
h1{font-size:var(--fs-section);line-height:var(--lh-section);font-weight:700;margin:0}
|
||||
[hidden]{display:none!important}
|
||||
.page{padding-inline:24px;padding-block:0 32px;max-width:1440px;margin-inline:auto}
|
||||
/* страница — контейнер: раскладка страниц зависит от её ширины, а не окна (рядом боковая панель, #69) */
|
||||
.page{padding-inline:24px;padding-block:0 32px;max-width:1440px;margin-inline:auto;container:page/inline-size}
|
||||
.page--board{max-width:none}
|
||||
@media (max-width:639px){.page{padding-inline:16px}}
|
||||
:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user