fix: compact map geometry controls

This commit is contained in:
Nico 2026-06-04 00:34:18 -07:00
parent 2b534eed6a
commit 164a95e058
3 changed files with 127 additions and 54 deletions

View File

@ -300,55 +300,69 @@ export default function LocationMapBottomSheet({
Locked Locked
</label> </label>
</div> </div>
<div className="location-map-object-grid"> <div className="location-map-geometry-controls">
<label> <div className="location-map-geometry-group">
X <span className="location-map-geometry-title">Position</span>
<input <div className="location-map-geometry-row">
type="number" <label>
min="0" <span>X</span>
max={maxX} <input
step="1" type="number"
value={Math.round(selectedObject.x)} min="0"
disabled={saving || geometryLocked} max={maxX}
onChange={(event) => onObjectField("x", Number(event.target.value))} step="1"
/> value={Math.round(selectedObject.x)}
</label> aria-label="X position"
<label> disabled={saving || geometryLocked}
Y onChange={(event) => onObjectField("x", Number(event.target.value))}
<input />
type="number" </label>
min="0" <label>
max={maxY} <span>Y</span>
step="1" <input
value={Math.round(selectedObject.y)} type="number"
disabled={saving || geometryLocked} min="0"
onChange={(event) => onObjectField("y", Number(event.target.value))} max={maxY}
/> step="1"
</label> value={Math.round(selectedObject.y)}
<label> aria-label="Y position"
W disabled={saving || geometryLocked}
<input onChange={(event) => onObjectField("y", Number(event.target.value))}
type="number" />
min="40" </label>
max={maxWidth} </div>
step="1" </div>
value={Math.round(selectedObject.width)} <div className="location-map-geometry-group">
disabled={saving || geometryLocked} <span className="location-map-geometry-title">Size</span>
onChange={(event) => onObjectField("width", Number(event.target.value))} <div className="location-map-geometry-row">
/> <label>
</label> <span>W</span>
<label> <input
H type="number"
<input min="40"
type="number" max={maxWidth}
min="40" step="1"
max={maxHeight} value={Math.round(selectedObject.width)}
step="1" aria-label="Width"
value={Math.round(selectedObject.height)} disabled={saving || geometryLocked}
disabled={saving || geometryLocked} onChange={(event) => onObjectField("width", Number(event.target.value))}
onChange={(event) => onObjectField("height", Number(event.target.value))} />
/> </label>
</label> <label>
<span>H</span>
<input
type="number"
min="40"
max={maxHeight}
step="1"
value={Math.round(selectedObject.height)}
aria-label="Height"
disabled={saving || geometryLocked}
onChange={(event) => onObjectField("height", Number(event.target.value))}
/>
</label>
</div>
</div>
</div> </div>
{geometryLocked ? ( {geometryLocked ? (
<p className="location-map-muted location-map-lock-note"> <p className="location-map-muted location-map-lock-note">

View File

@ -610,10 +610,55 @@
padding: 0; padding: 0;
} }
.location-map-object-grid { .location-map-geometry-controls {
display: grid; display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.45rem; gap: 0.5rem;
}
.location-map-geometry-group {
display: grid;
gap: 0.35rem;
min-width: 0;
}
.location-map-geometry-title {
color: #cbd5e1;
font-size: 0.78rem;
font-weight: 900;
}
.location-map-geometry-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.35rem;
}
.location-map-geometry-row label {
min-width: 0;
display: flex;
align-items: center;
gap: 0.35rem;
padding: 0.3rem 0.45rem;
border: 1px solid var(--color-border-light);
border-radius: 8px;
background: rgba(15, 23, 34, 0.58);
color: #f8fafc;
}
.location-map-geometry-row label span {
flex: 0 0 auto;
min-width: 1.1rem;
color: #9fb3c8;
font-size: 0.76rem;
font-weight: 900;
}
.location-map-geometry-row input {
min-width: 0;
min-height: 34px;
padding: 0.35rem 0.4rem;
text-align: center;
} }
.location-map-lock-note { .location-map-lock-note {
@ -843,7 +888,7 @@
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
} }
.location-map-object-grid { .location-map-geometry-controls {
grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.45rem;
} }
} }

View File

@ -2028,6 +2028,14 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
const labelInput = page.getByRole("textbox", { name: "Label" }); const labelInput = page.getByRole("textbox", { name: "Label" });
await expect(labelInput).toBeVisible(); await expect(labelInput).toBeVisible();
await expect(page.locator(".location-map-sheet-header strong")).toHaveText("Bakery"); await expect(page.locator(".location-map-sheet-header strong")).toHaveText("Bakery");
const geometryControls = page.locator(".location-map-geometry-controls");
await expect(geometryControls).toBeVisible();
await expect(geometryControls.getByText("Position")).toBeVisible();
await expect(geometryControls.getByText("Size")).toBeVisible();
await expect(page.getByLabel("X position")).toHaveValue("40");
await expect(page.getByLabel("Y position")).toHaveValue("40");
await expect(page.getByLabel("Width")).toHaveValue("260");
await expect(page.getByLabel("Height")).toHaveValue("160");
const selectedPrimaryActions = page.locator(".location-map-selected-primary-actions"); const selectedPrimaryActions = page.locator(".location-map-selected-primary-actions");
const selectedSecondaryActions = page.locator(".location-map-selected-secondary-actions"); const selectedSecondaryActions = page.locator(".location-map-selected-secondary-actions");
await expect(selectedPrimaryActions.getByRole("button", { name: "Save Draft" })).toBeVisible(); await expect(selectedPrimaryActions.getByRole("button", { name: "Save Draft" })).toBeVisible();
@ -2042,6 +2050,12 @@ test("mobile editor uses bottom sheet controls instead of desktop object toolbar
throw new Error("Selected object draft actions were not measurable"); throw new Error("Selected object draft actions were not measurable");
} }
expect(selectedPrimaryBox.y).toBeLessThan(labelBox.y); expect(selectedPrimaryBox.y).toBeLessThan(labelBox.y);
const geometryBox = await geometryControls.boundingBox();
expect(geometryBox).not.toBeNull();
if (!geometryBox) {
throw new Error("Geometry controls were not measurable");
}
expect(geometryBox.height).toBeLessThanOrEqual(92);
await page.getByRole("button", { name: "Done" }).click(); await page.getByRole("button", { name: "Done" }).click();
await expect(page.getByRole("textbox", { name: "Label" })).toHaveCount(0); await expect(page.getByRole("textbox", { name: "Label" })).toHaveCount(0);
await expect(page.locator(".location-map-sheet-header strong")).toHaveText("Edit Objects"); await expect(page.locator(".location-map-sheet-header strong")).toHaveText("Edit Objects");