confirm dialog for map peak toggles, search below map, themed attribution

This commit is contained in:
Vincent van der Wal
2026-07-22 12:11:04 +02:00
parent b89de57967
commit ce073f3fee
2 changed files with 81 additions and 5 deletions
+7 -3
View File
@@ -288,12 +288,16 @@
:global(.maplibregl-ctrl button.maplibregl-ctrl-terrain-enabled .maplibregl-ctrl-icon) { :global(.maplibregl-ctrl button.maplibregl-ctrl-terrain-enabled .maplibregl-ctrl-icon) {
filter: none; filter: none;
} }
:global(.maplibregl-ctrl-attrib) { :global(.maplibregl-ctrl-attrib),
background: color-mix(in srgb, var(--surface-1) 80%, transparent); :global(.maplibregl-ctrl-attrib.maplibregl-compact) {
background: color-mix(in srgb, var(--surface-1) 85%, transparent) !important;
color: var(--text-muted); color: var(--text-muted);
} }
:global(.maplibregl-ctrl-attrib a) { :global(.maplibregl-ctrl-attrib a) {
color: var(--text-secondary); color: var(--text-secondary) !important;
}
:global(.maplibregl-ctrl-attrib-button) {
filter: var(--map-icon-filter);
} }
:global(.maplibregl-popup.peak-tip .maplibregl-popup-content) { :global(.maplibregl-popup.peak-tip .maplibregl-popup-content) {
background: var(--surface-1); background: var(--surface-1);
+74 -2
View File
@@ -56,6 +56,19 @@
// the "In view" list only offers peaks still to climb; climbed ones live in "My ascents" // the "In view" list only offers peaks still to climb; climbed ones live in "My ascents"
const toClimb = $derived(viewPeaks.filter((p) => !p.climbed_at)); const toClimb = $derived(viewPeaks.filter((p) => !p.climbed_at));
// map clicks confirm via a small dialog - easy to hit a peak while panning/zooming
let confirmPeak: ViewPeak | null = $state(null);
function onMapPeakClick(id: number) {
confirmPeak = viewPeaks.find((p) => p.id === id) ?? null;
}
async function confirmToggle() {
if (!confirmPeak) return;
await toggle(confirmPeak.id);
confirmPeak = null;
}
const highest = $derived(ascents[0] ?? null); const highest = $derived(ascents[0] ?? null);
const mapPeaks = $derived( const mapPeaks = $derived(
@@ -134,6 +147,8 @@
Zoom in to reveal less prominent summits; click a peak to cross it off. Zoom in to reveal less prominent summits; click a peak to cross it off.
</p> </p>
<Map bind:this={mapRef} peaks={mapPeaks} height="480px" onpeakclick={onMapPeakClick} {onviewport} />
<div class="search"> <div class="search">
<input <input
type="search" type="search"
@@ -159,7 +174,35 @@
{/if} {/if}
</div> </div>
<Map bind:this={mapRef} peaks={mapPeaks} height="480px" onpeakclick={toggle} {onviewport} /> {#if confirmPeak}
<div
class="dialog-backdrop"
role="presentation"
onclick={(e) => {
if (e.target === e.currentTarget) confirmPeak = null;
}}
>
<div class="dialog card" role="dialog" aria-modal="true" aria-label="Peak">
<p class="d-name">{confirmPeak.name}</p>
<p class="d-sub">
{confirmPeak.elevation_m
? `${Math.round(confirmPeak.elevation_m).toLocaleString('en-US')} m`
: 'elevation unknown'}
{#if confirmPeak.climbed_at}
· reached {fmtDate(confirmPeak.climbed_at)}
{/if}
</p>
<div class="d-actions">
{#if confirmPeak.climbed_at}
<button class="btn danger" onclick={confirmToggle}>Remove ascent</button>
{:else}
<button class="btn" onclick={confirmToggle}>Mark as reached</button>
{/if}
<button class="btn ghost" onclick={() => (confirmPeak = null)}>Cancel</button>
</div>
</div>
</div>
{/if}
<div class="tabs" role="group" aria-label="Peak lists"> <div class="tabs" role="group" aria-label="Peak lists">
<button class="filter-btn" class:on={tab === 'view'} onclick={() => (tab = 'view')}> <button class="filter-btn" class:on={tab === 'view'} onclick={() => (tab = 'view')}>
@@ -225,7 +268,7 @@
<style> <style>
.search { .search {
position: relative; position: relative;
margin-bottom: 0.75rem; margin-top: 0.75rem;
max-width: 420px; max-width: 420px;
} }
.search input { .search input {
@@ -288,6 +331,35 @@
font-size: 0.8rem; font-size: 0.8rem;
color: var(--text-muted); color: var(--text-muted);
} }
.dialog-backdrop {
position: fixed;
inset: 0;
z-index: 1200;
background: rgba(0, 0, 0, 0.35);
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
.dialog {
padding: 1.25rem 1.4rem;
min-width: 260px;
max-width: 360px;
}
.d-name {
margin: 0;
font-weight: 700;
font-size: 1.05rem;
}
.d-sub {
margin: 0.2rem 0 1rem;
color: var(--text-secondary);
font-size: 0.88rem;
}
.d-actions {
display: flex;
gap: 0.5rem;
}
.tabs { .tabs {
display: flex; display: flex;
gap: 0.4rem; gap: 0.4rem;