fix(post): close location-map race, block submit on bad coords
Code review (4 independent reviewers) converged on the same bug: the maplibre-gl singleton cached its handle only after import() resolved, so a fast close/reopen of the "More location details" panel could race two Map instances onto one container. Cache the in-flight promise synchronously instead, and propagate/handle import rejection so a failed map load surfaces a hint instead of hanging silently. Also closes a submit-time hole the adversarial pass found: the mismatch flag on lat/lng was purely cosmetic and never blocked form submission, so out-of-range coordinates could be saved. The flag now gates submit like the other required fields, and clears itself when both fields are blanked back out instead of sticking. The geocode fetch gets a 10s timeout via AbortController so a hung response can't leave the lookup button disabled forever. Also moves the location-details CSS out of the site-wide style.css into post-form's own code-split stylesheet, since none of it is used outside the post form. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -833,110 +833,6 @@ body::after {
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
/* "More location details" disclosure — search + map preview for setting an
|
||||
entry's coordinates without live GPS. Mirrors .more-options's disclosure
|
||||
look (post-form.css); the lat/lng fields (relocated here by JS) and the
|
||||
lookup button reuse this file's existing .btn-action/.form-status/
|
||||
.field-invalid conventions unmodified. */
|
||||
.location-details {
|
||||
margin-bottom: var(--space-5);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-canvas);
|
||||
}
|
||||
.location-details__summary {
|
||||
cursor: pointer;
|
||||
padding: 0.875rem 1rem;
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
color: var(--color-ink);
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
}
|
||||
.location-details__summary::-webkit-details-marker { display: none; }
|
||||
.location-details__summary::before {
|
||||
content: '▸';
|
||||
margin-right: var(--space-2);
|
||||
color: var(--color-ink-muted);
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.location-details[open] .location-details__summary::before { transform: rotate(90deg); }
|
||||
.location-details[open] .location-details__summary { border-bottom: 1px solid var(--color-border); }
|
||||
.location-details > .form-field { padding: 0 1rem; }
|
||||
.location-details > .form-field:first-of-type { padding-top: var(--space-4); }
|
||||
.location-details > .form-field:last-of-type { padding-bottom: var(--space-2); }
|
||||
.location-details__body { padding: 1rem; }
|
||||
|
||||
.location-search-row { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
|
||||
|
||||
.location-search-hint {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink-muted);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
.location-search-hint:empty { display: none; }
|
||||
|
||||
.location-search-results {
|
||||
list-style: none;
|
||||
margin: var(--space-3) 0 0;
|
||||
padding: 0;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
.location-search-results:empty { display: none; margin: 0; border: none; }
|
||||
.location-search-results li + li { border-top: 1px solid var(--color-border); }
|
||||
.location-search-results button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0.75rem 1rem;
|
||||
min-height: 44px;
|
||||
background: var(--color-canvas);
|
||||
border: none;
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-ink);
|
||||
cursor: pointer;
|
||||
}
|
||||
.location-search-results button:hover,
|
||||
.location-search-results button:focus-visible { background: var(--color-paper); }
|
||||
|
||||
.location-map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 240px;
|
||||
margin-top: var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
background: var(--color-paper);
|
||||
}
|
||||
.location-map .maplibregl-canvas { border-radius: var(--radius-md); }
|
||||
|
||||
.location-pin {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent);
|
||||
border: 3px solid #fff;
|
||||
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
|
||||
cursor: grab;
|
||||
}
|
||||
.location-pin:active { cursor: grabbing; }
|
||||
|
||||
/* Mismatch flag: a typed lat/lng that doesn't (yet) parse to a valid pin. */
|
||||
.location-field--mismatch { border-color: var(--color-error) !important; outline-color: var(--color-error) !important; }
|
||||
.location-field-note {
|
||||
display: block;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-error);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
|
||||
/* Grav form field inputs */
|
||||
.post-form-wrap .form-field { margin-bottom: var(--space-5); }
|
||||
.post-form-wrap .form-label label {
|
||||
|
||||
Reference in New Issue
Block a user