Add store location map manager #20
@ -1,5 +1,51 @@
|
||||
import { MAX_MAP_ZOOM, MIN_MAP_ZOOM, clampMapZoom } from "../../lib/locationMapUtils";
|
||||
|
||||
function ToolbarIcon({ name }) {
|
||||
if (name === "undo") {
|
||||
return (
|
||||
<svg className="location-map-toolbar-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M9 7H4v5" />
|
||||
<path d="M5 11a7 7 0 1 0 2-5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === "redo") {
|
||||
return (
|
||||
<svg className="location-map-toolbar-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M15 7h5v5" />
|
||||
<path d="M19 11a7 7 0 1 1-2-5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === "zoom-in") {
|
||||
return (
|
||||
<svg className="location-map-toolbar-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M11 5v12" />
|
||||
<path d="M5 11h12" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === "fit") {
|
||||
return (
|
||||
<svg className="location-map-toolbar-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M8 4H4v4" />
|
||||
<path d="M16 4h4v4" />
|
||||
<path d="M20 16v4h-4" />
|
||||
<path d="M8 20H4v-4" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<svg className="location-map-toolbar-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M5 11h12" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function LocationMapToolbar({
|
||||
mode,
|
||||
editorTool,
|
||||
@ -61,19 +107,23 @@ export default function LocationMapToolbar({
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="location-map-icon-button"
|
||||
onClick={onUndo}
|
||||
disabled={!canUseHistoryControls || saving || history.length === 0}
|
||||
aria-label="Undo"
|
||||
title="Undo"
|
||||
>
|
||||
<span aria-hidden="true">↶</span>
|
||||
<ToolbarIcon name="undo" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="location-map-icon-button"
|
||||
onClick={onRedo}
|
||||
disabled={!canUseHistoryControls || saving || future.length === 0}
|
||||
aria-label="Redo"
|
||||
title="Redo"
|
||||
>
|
||||
<span aria-hidden="true">↷</span>
|
||||
<ToolbarIcon name="redo" />
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
@ -103,23 +153,34 @@ export default function LocationMapToolbar({
|
||||
<div className="location-map-zoom-controls" aria-label="Zoom controls">
|
||||
<button
|
||||
type="button"
|
||||
className="location-map-icon-button"
|
||||
onClick={() => setZoom((value) => Number(clampMapZoom(value - 0.15).toFixed(2)))}
|
||||
disabled={!hasAnyMap || isAtMinZoom}
|
||||
aria-label="Zoom out"
|
||||
title="Zoom out"
|
||||
>
|
||||
-
|
||||
<ToolbarIcon name="zoom-out" />
|
||||
</button>
|
||||
<span>{Math.round(zoom * 100)}%</span>
|
||||
<button
|
||||
type="button"
|
||||
className="location-map-icon-button"
|
||||
onClick={() => setZoom((value) => Number(clampMapZoom(value + 0.15).toFixed(2)))}
|
||||
disabled={!hasAnyMap || isAtMaxZoom}
|
||||
aria-label="Zoom in"
|
||||
title="Zoom in"
|
||||
>
|
||||
+
|
||||
<ToolbarIcon name="zoom-in" />
|
||||
</button>
|
||||
<button type="button" onClick={onFit} disabled={!hasAnyMap}>
|
||||
Fit
|
||||
<button
|
||||
type="button"
|
||||
className="location-map-icon-button"
|
||||
onClick={onFit}
|
||||
disabled={!hasAnyMap}
|
||||
aria-label="Fit"
|
||||
title="Fit"
|
||||
>
|
||||
<ToolbarIcon name="fit" />
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 }) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user