diff --git a/html/map.ejs b/html/map.ejs index 498c5394..f12e1e30 100644 --- a/html/map.ejs +++ b/html/map.ejs @@ -1,4 +1,3 @@ -
@@ -13,7 +12,10 @@ --vh:100vh;--pad:12px;--radius:14px;--fg:#fff;--bg:rgba(0,0,0,.6);--glass:blur(12px); --marker-size:20px;--marker-color:#e53935;--marker-ring:rgba(229,57,53,.35);--ring-width:3px; --panel:rgba(0,0,0,.85);--accent:#0ea5e9;--chip:#111;--chipb:#222;--tip:#888; - --surface:#0b0b0b;--border:#333 + --surface:#0b0b0b;--border:#333; + --sidew:320px; /* resizable desktop sidebar width */ + --sidew-min:260px; + --sidew-max:560px; } *{box-sizing:border-box} html,body{height:100%;margin:0} @@ -77,17 +79,27 @@ .settings textarea{width:100%;min-height:120px;border-radius:10px;border:1px solid var(--border);background:#0a0a0a;color:#eee;padding:8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace} .settings .about{font-size:13px;opacity:.92;line-height:1.5} - /* Desktop layout — simplified & clean */ + /* Desktop layout — resizable, scrollable sidebar */ .desktop .bar{grid-column:2} - .desktop .app{grid-template-columns:320px 1fr;grid-template-rows:auto 1fr} - .desktop .sidebar{position:fixed;left:0;top:0;bottom:0;width:320px;background:var(--panel);border-right:1px solid var(--border);display:flex;flex-direction:column;gap:12px;padding:12px;z-index:9} + .desktop .app{grid-template-columns:var(--sidew) 1fr;grid-template-rows:auto 1fr} + .desktop .sidebar{position:fixed;left:0;top:0;bottom:0;width:var(--sidew);background:var(--panel);border-right:1px solid var(--border);display:flex;flex-direction:column;gap:12px;padding:12px;z-index:9;overflow:auto} .desktop .sidecard{border:1px solid #222;border-radius:12px;overflow:hidden} .desktop .sidecard header{padding:10px 12px;border-bottom:1px solid #222;font-weight:600;display:flex;justify-content:space-between;align-items:center} .desktop .sidecard .row{display:flex;gap:8px;align-items:center;padding:8px 12px;border-top:1px solid #111} .desktop .sidecard .row:first-of-type{border-top:0} .desktop .sidecard .hint{font-size:12px;opacity:.75;padding:8px 12px} .desktop .mapwrap{grid-column:2} - /* Suppress popovers on desktop (sidebar replaces them) */ + + /* Sidebar resizer */ + .desktop .resizer{position:fixed;left:calc(var(--sidew));top:0;bottom:0;width:6px;cursor:col-resize;z-index:10;background:transparent} + .desktop .resizer::after{content:"";position:absolute;right:0;top:40px;bottom:40px;width:2px;background:rgba(255,255,255,.08)} + + /* Hide floating buttons on desktop (they exist in the sidebar) */ + .desktop .dock, + .desktop #menuBtn, + .desktop #locate{ display:none !important } + + /* Suppress mobile popovers on desktop (sidebar replaces them) */ .desktop .menu,.desktop .pins,.desktop .settings{display:none !important} /* Pro detail rows subtly toned down */ @@ -292,8 +304,7 @@ const accentColorEl=S("#accentColor"), accentResetEl=S("#accentReset"); const customCSSEl=S("#customCSS"), applyCSSEl=S("#applyCSS"), clearCSSEl=S("#clearCSS"); - /* Pro mode */ - const PREFS_KEY="pokemaps_prefs_v6"; + const PREFS_KEY="pokemaps_prefs_v7"; const LS_PINS="pokemaps_pins_v1"; const LS_SEARCH="pokemaps_search_hist_v1"; @@ -302,7 +313,7 @@ const prefs=loadPrefs(); applyPrefs(); const isDesktop=()=> matchMedia("(min-width: 1024px)").matches && matchMedia("(pointer: fine)").matches; - const applyDesktopClass=()=>{ document.body.classList.toggle("desktop", isDesktop()) }; + const applyDesktopClass=()=>{ document.body.classList.toggle("desktop", isDesktop()); if(isDesktop()) ensureDesktopSidebar(); else removeDesktopSidebar() }; applyDesktopClass(); addEventListener("resize",applyDesktopClass,{passive:true}); const setVH=()=>{const vh=window.innerHeight*0.01;document.documentElement.style.setProperty("--vh",`${vh*100}px`)}; @@ -419,7 +430,7 @@ const highlight=(text,term)=>{ term=term.trim(); if(!term) return text; - const esc=term.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"); + const esc=term.replace(/[.*+?^${}()|[\\]\\\\]/g,"\\\\$&"); return text.replace(new RegExp(esc,"ig"),m=>`${m}`); }; @@ -429,7 +440,6 @@ const renderSuggest=(items, term="")=>{ if(!sug) return; - // keep the sticky head; rebuild the rest const head = sug.querySelector(".head"); sug.innerHTML=""; if(head) sug.appendChild(head); @@ -557,15 +567,15 @@ }; function button(t,fn){ const b=document.createElement("button"); b.textContent=t; b.className="iconbtn"; b.onclick=fn; return b } const nameFromState=()=> q.value?.trim() || new Date().toLocaleString(); - savepin.onclick=()=>{ const pins=loadPins(); pins.unshift({name:nameFromState(), lat:state.lat, lon:state.lon, delta:state.delta, layer:state.layer}); savePins(pins); renderPins(); pinsPane.style.display="block" }; - showpins.onclick=()=>{ renderPins(); pinsPane.style.display="block" }; - closepins.onclick=()=>{ pinsPane.style.display="none" }; + savepin && (savepin.onclick=()=>{ const pins=loadPins(); pins.unshift({name:nameFromState(), lat:state.lat, lon:state.lon, delta:state.delta, layer:state.layer}); savePins(pins); renderPins(); pinsPane.style.display="block" }); + showpins && (showpins.onclick=()=>{ renderPins(); pinsPane.style.display="block" }); + closepins && (closepins.onclick=()=>{ pinsPane.style.display="none" }); // Panels (mobile/tablet only; desktop has sidebar) menuBtn.onclick=()=>{ if(isDesktop()) return; menu.style.display="block" }; closeMenu && (closeMenu.onclick=()=>{ menu.style.display="none" }); - opensettings.onclick=()=>{ if(isDesktop()) return; settings.style.display="block" }; - closesettings.onclick=()=>{ settings.style.display="none" }; + opensettings && (opensettings.onclick=()=>{ if(isDesktop()) return; settings.style.display="block" }); + closesettings && (closesettings.onclick=()=>{ settings.style.display="none" }); // Prefs -> UI toggleCoords.checked = !!prefs.showCoords; @@ -624,7 +634,7 @@ addEventListener("keydown",(e)=>{ if(e.target.matches("input, textarea")) return; if(e.key.toLowerCase()==="l"){ e.preventDefault(); locate() } - if(e.key.toLowerCase()==="s"){ e.preventDefault(); savepin.click() } + if(e.key.toLowerCase()==="s"){ e.preventDefault(); savepin?.click() } if(e.key.toLowerCase()==="h"){ e.preventDefault(); toggleFollow() } if(e.key.toLowerCase()==="r"){ e.preventDefault(); reset() } if(e.key.toLowerCase()==="1"){ e.preventDefault(); setLayer("mapnik") } @@ -653,7 +663,7 @@ applyMarkerStyle(prefs.markerStyle||"dot"); setAccent(prefs.accent||"#0ea5e9"); applyTheme(prefs.theme||"auto"); - // apply pro mode class on body + if(prefs.sideW) document.documentElement.style.setProperty("--sidew", clamp(prefs.sideW, getMinSide(), getMaxSide()) + "px"); document.body.classList.toggle("pro-enabled", !!prefs.proMode); } function applyMarkerStyle(style){ markerEl.classList.toggle("crosshair", style==="crosshair") } @@ -696,11 +706,22 @@ if(!urlHasLat){ locate() } if(prefs.autoFollow) startFollow(); - // Desktop sidebar builder (clean, with Pro toggle) - if(isDesktop()) buildDesktopSidebar(); + /* ===== Desktop sidebar: build once, resizable + scrollable ===== */ + let sideBuilt=false, sideEl=null, resizerEl=null; + function ensureDesktopSidebar(){ + if(sideBuilt) return; + buildDesktopSidebar(); + sideBuilt=true; + } + function removeDesktopSidebar(){ + if(!sideBuilt) return; + sideEl?.remove(); resizerEl?.remove(); + sideEl=null; resizerEl=null; sideBuilt=false; + } + function buildDesktopSidebar(){ - const side=document.createElement("div"); side.className="sidebar"; - side.innerHTML=` + sideEl=document.createElement("div"); sideEl.className="sidebar"; + sideEl.innerHTML=`