diff --git a/frontend/src/components/maps/LocationMapToolbar.jsx b/frontend/src/components/maps/LocationMapToolbar.jsx index b0390dd..89e48b2 100644 --- a/frontend/src/components/maps/LocationMapToolbar.jsx +++ b/frontend/src/components/maps/LocationMapToolbar.jsx @@ -1,5 +1,51 @@ import { MAX_MAP_ZOOM, MIN_MAP_ZOOM, clampMapZoom } from "../../lib/locationMapUtils"; +function ToolbarIcon({ name }) { + if (name === "undo") { + return ( + + ); + } + + if (name === "redo") { + return ( + + ); + } + + if (name === "zoom-in") { + return ( + + ); + } + + if (name === "fit") { + return ( + + ); + } + + return ( + + ); +} + export default function LocationMapToolbar({ mode, editorTool, @@ -61,19 +107,23 @@ export default function LocationMapToolbar({ > ) : null} @@ -103,23 +153,34 @@ export default function LocationMapToolbar({
{Math.round(zoom * 100)}% -
diff --git a/frontend/src/styles/pages/LocationMapManager.css b/frontend/src/styles/pages/LocationMapManager.css index bb0add0..8e76f7e 100644 --- a/frontend/src/styles/pages/LocationMapManager.css +++ b/frontend/src/styles/pages/LocationMapManager.css @@ -191,6 +191,28 @@ line-height: 1; } +.location-map-history-buttons button.location-map-icon-button, +.location-map-zoom-controls button.location-map-icon-button { + width: 40px; + min-width: 40px; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.location-map-toolbar-icon { + width: 18px; + height: 18px; + display: block; + fill: none; + stroke: currentColor; + stroke-width: 2.2; + stroke-linecap: round; + stroke-linejoin: round; + pointer-events: none; +} + .location-map-tool-buttons button.is-pan.active { border-color: rgba(245, 158, 11, 0.78); background: rgba(245, 158, 11, 0.22); diff --git a/frontend/tests/location-map-manager.spec.ts b/frontend/tests/location-map-manager.spec.ts index b2faa57..c46f712 100644 --- a/frontend/tests/location-map-manager.spec.ts +++ b/frontend/tests/location-map-manager.spec.ts @@ -1488,6 +1488,11 @@ test("narrow mobile toolbar keeps map controls tappable without overflow", async const toolbarButtons = toolbar.getByRole("button"); const buttonCount = await toolbarButtons.count(); expect(buttonCount).toBe(7); + await expect(toolbar.getByRole("button", { name: "Undo" })).toBeVisible(); + await expect(toolbar.getByRole("button", { name: "Redo" })).toBeVisible(); + await expect(toolbar.getByRole("button", { name: "Zoom out" })).toBeVisible(); + await expect(toolbar.getByRole("button", { name: "Zoom in" })).toBeVisible(); + await expect(toolbar.getByRole("button", { name: "Fit" })).toBeVisible(); for (let index = 0; index < buttonCount; index += 1) { const buttonBox = await toolbarButtons.nth(index).boundingBox(); expect(buttonBox).not.toBeNull(); @@ -1495,6 +1500,17 @@ test("narrow mobile toolbar keeps map controls tappable without overflow", async expect(buttonBox.width).toBeGreaterThanOrEqual(40); expect(buttonBox.height).toBeGreaterThanOrEqual(40); } + + const iconButtons = toolbar.locator(".location-map-icon-button"); + await expect(iconButtons).toHaveCount(5); + for (let index = 0; index < await iconButtons.count(); index += 1) { + const iconButtonBox = await iconButtons.nth(index).boundingBox(); + expect(iconButtonBox).not.toBeNull(); + if (!iconButtonBox) throw new Error("Toolbar icon button was not measurable"); + expect(iconButtonBox.width).toBeLessThanOrEqual(44); + expect(iconButtonBox.height).toBeLessThanOrEqual(44); + await expect(iconButtons.nth(index).locator(".location-map-toolbar-icon")).toHaveCount(1); + } }); test("admin selecting an object does not mark a draft dirty until it changes", async ({ page }) => {