fix(hive): „Zurück“ im Fokus-Modus nicht mehr von der Liste verdeckt
Backend Image / build-and-push (push) Successful in 6m35s
Frontend Image / build-and-push (push) Successful in 19m22s

Auf dem Handy lag die offene Aufbau-Liste (288 px, rechts, z-10) über dem
rechten Teil der „Zurück“-Pille, der Tipp landete in der Liste und der
Fokus blieb. Die Spalte für Liste und Knopfleiste beginnt jetzt unter der
gemessenen Titel- bzw. Fokusleiste (insets.top + 8 px), wie sie schon über
den Knöpfen endet.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick.RosenloecherandClaude Opus 5.5 committed 2026-10-19 18:11:01 +02:00
1 parent c2189df47a
commit c8b9bd5cd2
2 files changed
+31 -2

No files matched your search

@@ -231,6 +231,29 @@ describe("HiveCard", () => {
expect(buttons?.parentElement).toBe(column.parentElement);
});
it("starts the outline panel below the title or focus bar, so it never covers „Zurück“", async () => {
// jsdom has no layout: every overlay reports 60 px, the observer measures once.
vi.stubGlobal(
"ResizeObserver",
class {
observe() {}
disconnect() {}
},
);
const height = vi.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(60);
try {
renderCard();
await userEvent.click(await screen.findByRole("button", { name: "Aufbau als Liste" }));
const column = screen.getByTestId("hive-outline-scroll").parentElement!.parentElement!.parentElement!;
// 60 px overlay + 12 px from the stage top + 8 px gap.
expect(column).toHaveStyle({ paddingTop: "80px" });
} finally {
height.mockRestore();
vi.unstubAllGlobals();
}
});
it("shows title and facts as a frosted overlay and the actions as glass buttons on the stage", async () => {
renderCard();
await screen.findByRole("img", { name: /Beute mit/ });
@@ -157,6 +157,8 @@ function HiveCardContent({ colonyId, colony, mode = "view", onOpsChange, initial
/** Top: title panel or focus bar (placed 12 px from the top). Bottom: the button column (8 px padding). */
const TOP_OVERLAY_OFFSET_PX = 12;
const BOTTOM_OVERLAY_OFFSET_PX = 8;
/** Gap between the top overlay and the outline panel (the column's p-2). */
const OUTLINE_GAP_PX = 8;
/** Heights of the overlays over the stage, so the 3D camera keeps the model clear of them. */
function useOverlayInsets(top: RefObject<HTMLElement | null>, bottom: RefObject<HTMLElement | null>) {
@@ -349,8 +351,12 @@ function HiveCardBody({ colonyId, setup, catalog, canEdit, mode, onOpsChange, in
)}
</div>
{/* One column for the outline panel and the button bar: the panel always ends above the
buttons, however they wrap. DOM order keeps the buttons before the tree (tab order). */}
<div className="pointer-events-none absolute inset-0 flex flex-col gap-2 p-2">
buttons, however they wrap, and starts below the title or focus bar (on a phone it
would cover „Zurück“). DOM order keeps the buttons before the tree (tab order). */}
<div
className="pointer-events-none absolute inset-0 flex flex-col gap-2 p-2"
style={{ paddingTop: insets.top + OUTLINE_GAP_PX }}
>
<div ref={bottomOverlayRef} className="order-2 flex flex-col items-center gap-2 p-1">
{past ? (
<div className="pointer-events-auto">