diff --git a/html/map.ejs b/html/map.ejs
index 248cf974..c5b66fc2 100644
--- a/html/map.ejs
+++ b/html/map.ejs
@@ -1,182 +1,102 @@
+can u like remove the desktop ui? make a new unified ui for mobile + desktop. i want u to split it between two messages so first just send the html for it then the js. please? (NOTE:MAKE SURE EVERYTHING WORKS IN MOBILE AND DESKTOP AT THE SAME TIME)
+
PokeMaps Public Beta
-
+
-
+
@@ -184,180 +104,765 @@
-
+
+
+ Suggestions
+ β
+
+
-
π
-
+
π
+
-
-
+
+
PokeMaps Public Beta
- β Save Pin
- π Pins
- β Settings
+ β Save Pin
+ π Pins
+ β Settings
-
-
+ S("#form").addEventListener("submit",async e=>{ e.preventDefault(); await searchNow(q.value); hideSuggest(true) });
+
+ // Quick actions (Menu)
+ quickNear && (quickNear.onclick=locate);
+ quickClear && (quickClear.onclick=()=>{ q.value=""; searchPlaces(""); q.focus() });
+
+ locateBtn.onclick=locate;
+ layerSel && (layerSel.onchange=()=>setLayer(layerSel.value));
+ followBtn && (followBtn.onclick=toggleFollow);
+ resetBtn && (resetBtn.onclick=reset);
+ shareBtn && (shareBtn.onclick=shareLink);
+ copyBtn && (copyBtn.onclick=copyLink);
+ copyCoordsBtn && (copyCoordsBtn.onclick=copyCoords);
+ openBtn && (openBtn.onclick=()=>window.open(osmViewURL(state), "_blank"));
+ openGmapsBtn && (openGmapsBtn.onclick=()=>window.open(gmapsURL(state), "_blank"));
+
+ // Pins
+ const loadPins=()=>{ try{ return JSON.parse(localStorage.getItem(LS_PINS)||"[]") }catch{ return [] } };
+ const savePins=(pins)=>{ localStorage.setItem(LS_PINS, JSON.stringify(pins.slice(0,100))) };
+ const renderPins=()=>{
+ const pins=loadPins();
+ pinlist.innerHTML="";
+ if(!pins.length){ const li=document.createElement("li"); li.textContent="No pins yet."; pinlist.appendChild(li); return }
+ pins.forEach((p,idx)=>{
+ const li=document.createElement("li");
+ const head=document.createElement("div");
+ head.innerHTML=`${p.name} ${p.lat.toFixed(5)}, ${p.lon.toFixed(5)} Β· ${p.layer}
`;
+ const actions=document.createElement("div"); actions.className="row";
+ const go=button("Go",()=>{ pinsPane.style.display="none"; state.lat=p.lat; state.lon=p.lon; state.delta=p.delta; state.layer=p.layer; layerSel && (layerSel.value=p.layer); apply(true) });
+ const share=button("Share",async()=>{ const url=appURL(p); if(navigator.share){ try{ await navigator.share({title:"PokeMaps Public Beta",url}) }catch{} } else { try{ await navigator.clipboard.writeText(url); alert("Link copied!") }catch{} } });
+ const copyc=button("Copy Coords",()=>navigator.clipboard.writeText(`${p.lat.toFixed(6)},${p.lon.toFixed(6)}`).then(()=>alert("Copied!")));
+ const ren=button("Rename",()=>{ const nv=prompt("New name:", p.name||""); if(nv!==null){ const arr=loadPins(); arr[idx].name=(nv||"").trim()||new Date().toLocaleString(); savePins(arr); renderPins() } });
+ const del=button("Del",()=>{ if(confirmDeleteEl.checked){ if(!confirm("Delete pin?")) return } const arr=loadPins(); arr.splice(idx,1); savePins(arr); renderPins() });
+ actions.append(go,share,copyc,ren,del);
+ li.append(head,actions); pinlist.appendChild(li);
+ });
+ };
+ 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" };
+
+ // 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" };
+
+ // Prefs -> UI
+ toggleCoords.checked = !!prefs.showCoords;
+ coordsEl.style.display = prefs.showCoords ? "block" : "none";
+ coordFmtEl.value = prefs.coordFmt || "dec";
+ coordPrecEl.value = prefs.prec ?? 6;
+ coordPrecVal.textContent = String(prefs.prec ?? 6);
+ themeModeEl.value = prefs.theme || "auto";
+
+ autoFollowEl.checked = !!prefs.autoFollow;
+ shareDeltaEl.checked = prefs.includeDelta!==false;
+ confirmDeleteEl.checked = prefs.confirmDelete!==false;
+
+ markerVisibleEl.checked = !prefs.markerHidden;
+ markerSizeEl.value = prefs.markerSize || 20;
+ markerSizeVal.textContent = markerSizeEl.value + "px";
+ markerColorEl.value = prefs.markerColor || "#e53935";
+ markerRingEl.checked = prefs.markerRing !== false;
+ ringWidthEl.value = prefs.ringWidth != null ? prefs.ringWidth : 3;
+ ringWidthVal.textContent = ringWidthEl.value + "px";
+ markerStyleEl.value = prefs.markerStyle || "dot";
+ applyMarkerStyle(markerStyleEl.value);
+
+ accentColorEl.value = prefs.accent || "#0ea5e9";
+ setAccent(prefs.accent || "#0ea5e9");
+
+ customCSSEl.value = prefs.userCSS || "";
+ applyUserCSS(prefs.userCSS||"");
+
+ document.querySelectorAll(".settings .ghead button").forEach(b=>{
+ b.onclick=()=>{ const t=b.getAttribute("data-t"); const sec=document.querySelector(`.settings .section[data-sec="${t}"]`); sec.style.display=sec.style.display==="block"?"none":"block" }
+ });
+
+ // Pref listeners
+ markerVisibleEl.onchange=()=>{ markerEl.classList.toggle("hidden", !markerVisibleEl.checked); prefs.markerHidden = !markerVisibleEl.checked; savePrefs() };
+ markerSizeEl.oninput=()=>{ document.documentElement.style.setProperty("--marker-size", markerSizeEl.value+"px"); markerSizeVal.textContent=markerSizeEl.value+"px"; prefs.markerSize=+markerSizeEl.value; savePrefs() };
+ markerColorEl.oninput=()=>{ document.documentElement.style.setProperty("--marker-color", markerColorEl.value); prefs.markerColor=markerColorEl.value; savePrefs() };
+ markerRingEl.onchange=()=>{ document.documentElement.style.setProperty("--marker-ring", markerRingEl.checked ? "rgba(229,57,53,.35)" : "transparent"); prefs.markerRing = markerRingEl.checked; savePrefs() };
+ ringWidthEl.oninput=()=>{ document.documentElement.style.setProperty("--ring-width", ringWidthEl.value+"px"); ringWidthVal.textContent=ringWidthEl.value+"px"; prefs.ringWidth=+ringWidthEl.value; savePrefs() };
+ markerStyleEl.onchange=()=>{ applyMarkerStyle(markerStyleEl.value); prefs.markerStyle=markerStyleEl.value; savePrefs() };
+
+ toggleCoords.onchange=()=>{ prefs.showCoords = toggleCoords.checked; coordsEl.style.display = prefs.showCoords ? "block" : "none"; savePrefs() };
+ coordFmtEl.onchange=()=>{ prefs.coordFmt = coordFmtEl.value; savePrefs() };
+ coordPrecEl.oninput=()=>{ prefs.prec = +coordPrecEl.value; coordPrecVal.textContent=String(prefs.prec); savePrefs() };
+ autoFollowEl.onchange=()=>{ prefs.autoFollow = autoFollowEl.checked; savePrefs() };
+ shareDeltaEl.onchange=()=>{ prefs.includeDelta = shareDeltaEl.checked; savePrefs() };
+ confirmDeleteEl.onchange=()=>{ prefs.confirmDelete = confirmDeleteEl.checked; savePrefs() };
+ themeModeEl.onchange=()=>{ prefs.theme = themeModeEl.value; applyTheme(prefs.theme); savePrefs() };
+
+ accentColorEl.oninput=()=>{ setAccent(accentColorEl.value); prefs.accent=accentColorEl.value; savePrefs() };
+ accentResetEl.onclick=()=>{ const def="#0ea5e9"; accentColorEl.value=def; setAccent(def); prefs.accent=def; savePrefs() };
+
+ applyCSSEl.onclick=()=>{ const css=customCSSEl.value||""; prefs.userCSS=css; applyUserCSS(css); savePrefs() };
+ clearCSSEl.onclick=()=>{ customCSSEl.value=""; prefs.userCSS=""; applyUserCSS(""); savePrefs() };
+
+ 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()==="h"){ e.preventDefault(); toggleFollow() }
+ if(e.key.toLowerCase()==="r"){ e.preventDefault(); reset() }
+ if(e.key.toLowerCase()==="1"){ e.preventDefault(); setLayer("mapnik") }
+ if(e.key.toLowerCase()==="2"){ e.preventDefault(); setLayer("cyclemap") }
+ if(e.key.toLowerCase()==="3"){ e.preventDefault(); setLayer("transportmap") }
+ if(e.key.toLowerCase()==="4"){ e.preventDefault(); setLayer("hot") }
+ if(e.key==="/"){ e.preventDefault(); q.focus() }
+ if(e.key==="Escape"){ menu.style.display="none"; settings.style.display="none"; pinsPane.style.display="none"; hideSuggest(true) }
+ });
+
+ addEventListener("popstate",e=>{
+ stopFollow();
+ if(e.state && typeof e.state.lat==="number"){ state=e.state; layerSel && (layerSel.value=state.layer); apply(false) }
+ else { parseURL(); layerSel && (layerSel.value=state.layer); apply(false) }
+ });
+
+ function loadPrefs(){ try{ return JSON.parse(localStorage.getItem(PREFS_KEY)||"{}") }catch{ return {} } }
+ function savePrefs(){ localStorage.setItem(PREFS_KEY, JSON.stringify(prefs)) }
+
+ function applyPrefs(){
+ if(prefs.markerSize) document.documentElement.style.setProperty("--marker-size", prefs.markerSize+"px");
+ if(prefs.markerColor) document.documentElement.style.setProperty("--marker-color", prefs.markerColor);
+ document.documentElement.style.setProperty("--marker-ring", (prefs.markerRing===false) ? "transparent" : "rgba(229,57,53,.35)");
+ document.documentElement.style.setProperty("--ring-width", (prefs.ringWidth!=null?prefs.ringWidth:3)+"px");
+ if(prefs.markerHidden) markerEl.classList.add("hidden");
+ applyMarkerStyle(prefs.markerStyle||"dot");
+ setAccent(prefs.accent||"#0ea5e9");
+ applyTheme(prefs.theme||"auto");
+ // apply pro mode class on body
+ document.body.classList.toggle("pro-enabled", !!prefs.proMode);
+ }
+ function applyMarkerStyle(style){ markerEl.classList.toggle("crosshair", style==="crosshair") }
+ function setAccent(hex){ document.documentElement.style.setProperty("--accent",hex); themeColorMeta?.setAttribute("content",hex) }
+
+ function applyTheme(mode){
+ if(mode==="dark"){ document.documentElement.style.colorScheme="dark" }
+ else if(mode==="light"){ document.documentElement.style.colorScheme="light" }
+ else { document.documentElement.style.colorScheme="" }
+ }
+
+ // PWA manifest (runtime-injected, no service worker)
+ (function injectManifest(){
+ const manifest={
+ name:"PokeMaps Public Beta",
+ short_name:"PokeMaps",
+ start_url: location.pathname,
+ display:"standalone",
+ background_color:"#000000",
+ theme_color:getComputedStyle(document.documentElement).getPropertyValue("--accent").trim() || "#0ea5e9",
+ icons:[ { src:"/css/yt-ukraine.svg", sizes:"any", type:"image/svg+xml", purpose:"any" } ]
+ };
+ const blob=new Blob([JSON.stringify(manifest)],{type:"application/manifest+json"});
+ const url=URL.createObjectURL(blob);
+ const link=document.createElement("link");
+ link.rel="manifest"; link.href=url;
+ document.head.appendChild(link);
+ })();
+
+ // Custom CSS injector
+ function applyUserCSS(css){
+ let tag=document.getElementById("user-css");
+ if(!tag){ tag=document.createElement("style"); tag.id="user-css"; document.head.appendChild(tag) }
+ tag.textContent=css||"";
+ }
+
+ // Init navigation
+ parseURL(); apply(false);
+ const urlHasLat = new URLSearchParams(location.search).has("lat");
+ if(!urlHasLat){ locate() }
+ if(prefs.autoFollow) startFollow();
+
+ // Desktop sidebar builder (clean, with Pro toggle)
+ if(isDesktop()) buildDesktopSidebar();
+ function buildDesktopSidebar(){
+ const side=document.createElement("div"); side.className="sidebar";
+ side.innerHTML=`
+
+
+
+
+ Standard
+ Cycle
+ Transport
+ Humanitarian
+
+
Locate Follow Reset
+
Copy Link Copy Coords
+
Open in OSM Google Maps
+
Tip: / to focus search β’ 1β4 change layers β’ S save pin β’ R reset
+
+
+
+
+
+
+
Save current Manage
+
+
+
+
+
+
Always show coords
+
DD (Decimal) DMS
+
Precision
+
Accent Reset
+
Share Copy Link
+
+
+
+
+
+
+
Powered by openstreetmap.org β’ Data Β© OSM contributors β’ Public Beta
+
+ `;
+ document.body.appendChild(side);
+
+ // Mirror search
+ const d_searchmirror=side.querySelector("#d_searchmirror");
+ d_searchmirror.value=q.value||"";
+ d_searchmirror.addEventListener("input",()=>{ q.value=d_searchmirror.value; q.dispatchEvent(new Event("input",{bubbles:true})) });
+
+ // Pro toggle
+ const proToggle=side.querySelector("#pro_toggle");
+ const updatePro=()=>{ prefs.proMode = proToggle.checked; savePrefs(); document.body.classList.toggle("pro-enabled", !!prefs.proMode) };
+ proToggle.addEventListener("change",updatePro);
+ document.body.classList.toggle("pro-enabled", !!prefs.proMode);
+
+ const d_layer=side.querySelector("#d_layer");
+ side.querySelector("#d_osm").onclick=()=>window.open(osmViewURL(state),"_blank");
+ side.querySelector("#d_copy").onclick=copyLink;
+ side.querySelector("#d_copy2").onclick=copyLink;
+ side.querySelector("#d_share").onclick=shareLink;
+ side.querySelector("#d_locate").onclick=locate;
+ side.querySelector("#d_follow").onclick=toggleFollow;
+ side.querySelector("#d_reset").onclick=reset;
+ side.querySelector("#d_gmaps").onclick=()=>window.open(gmapsURL(state), "_blank");
+ d_layer.value=state.layer;
+ d_layer.onchange=()=>setLayer(d_layer.value);
+
+ // Marker group
+ const d_markerv=side.querySelector("#d_markerv");
+ const d_style=side.querySelector("#d_style");
+ const d_ms=side.querySelector("#d_ms"), d_msv=side.querySelector("#d_msv");
+ const d_mc=side.querySelector("#d_mc");
+ const d_mr=side.querySelector("#d_mr");
+ const d_rw=side.querySelector("#d_rw"), d_rwv=side.querySelector("#d_rwv");
+
+ d_markerv.checked=!prefs.markerHidden;
+ d_style.value=prefs.markerStyle||"dot";
+ d_ms.value=markerSizeEl.value; d_msv.textContent=d_ms.value+"px";
+ d_mc.value=markerColorEl.value;
+ d_mr && (d_mr.checked=markerRingEl.checked);
+ d_rw && (d_rw.value=ringWidthEl.value, d_rwv.textContent=d_rw.value+"px");
+
+ d_markerv.onchange=()=>{ markerVisibleEl.checked=d_markerv.checked; markerVisibleEl.onchange() };
+ d_style.onchange=()=>{ markerStyleEl.value=d_style.value; markerStyleEl.onchange() };
+ d_ms.oninput=()=>{ markerSizeEl.value=d_ms.value; markerSizeEl.oninput(); d_msv.textContent=d_ms.value+"px" };
+ d_mc.oninput=()=>{ markerColorEl.value=d_mc.value; markerColorEl.oninput() };
+ d_mr && (d_mr.onchange=()=>{ markerRingEl.checked=d_mr.checked; markerRingEl.onchange() });
+ d_rw && (d_rw.oninput=()=>{ ringWidthEl.value=d_rw.value; ringWidthEl.oninput(); d_rwv.textContent=d_rw.value+"px" });
+
+ // Pins mini
+ const d_save=side.querySelector("#d_save");
+ const d_showpins=side.querySelector("#d_showpins");
+ const d_pinlistmini=side.querySelector("#d_pinlistmini");
+ d_save.onclick=()=>savepin.click();
+ d_showpins.onclick=()=>{ renderPins(); pinsPane.style.display="block" };
+
+ const renderPinsMini=()=>{
+ d_pinlistmini.innerHTML="";
+ const pins=loadPins().slice(0,6);
+ if(!pins.length){ d_pinlistmini.innerHTML='No pins yet. '; return }
+ pins.forEach((p,idx)=>{
+ const row=document.createElement("div");
+ row.style.display="flex"; row.style.gap="6px"; row.style.alignItems="center"; row.style.justifyContent="space-between";
+ const txt=document.createElement("div");
+ txt.innerHTML=`${p.name} ${p.lat.toFixed(5)}, ${p.lon.toFixed(5)} `;
+ const go=document.createElement("button"); go.className="iconbtn"; go.textContent="Go"; go.onclick=()=>{ state.lat=p.lat; state.lon=p.lon; state.delta=p.delta; state.layer=p.layer; layerSel && (layerSel.value=p.layer); apply(true) };
+ row.append(txt,go); d_pinlistmini.appendChild(row);
+ });
+ };
+ renderPinsMini();
+
+ // Display group
+ const d_showc=side.querySelector("#d_showc");
+ const d_fmt=side.querySelector("#d_fmt");
+ const d_prec=side.querySelector("#d_prec"), d_precv=side.querySelector("#d_precv");
+ const d_accent=side.querySelector("#d_accent"), d_accent_reset=side.querySelector("#d_accent_reset");
+ d_showc.checked=!!prefs.showCoords;
+ d_fmt.value=prefs.coordFmt||"dec";
+ d_prec && (d_prec.value=prefs.prec??6, d_precv.textContent=String(prefs.prec??6));
+ d_accent.value=prefs.accent||"#0ea5e9";
+ d_showc.onchange=()=>{ toggleCoords.checked=d_showc.checked; toggleCoords.onchange() };
+ d_fmt.onchange=()=>{ coordFmtEl.value=d_fmt.value; coordFmtEl.onchange() };
+ d_prec && (d_prec.oninput=()=>{ coordPrecEl.value=d_prec.value; coordPrecEl.oninput(); d_precv.textContent=d_prec.value });
+ d_accent.oninput=()=>{ accentColorEl.value=d_accent.value; accentColorEl.oninput() };
+ d_accent_reset.onclick=()=>{ accentResetEl.click(); d_accent.value=accentColorEl.value };
+
+ // Custom CSS
+ const d_usercss=side.querySelector("#d_usercss");
+ const d_applycss=side.querySelector("#d_applycss");
+ const d_clearcss=side.querySelector("#d_clearcss");
+ if(d_usercss){ d_usercss.value=prefs.userCSS||""; d_applycss.onclick=()=>applyCSSEl.onclick(); d_clearcss.onclick=()=>clearCSSEl.onclick() }
+ }
+
+ function tickCoords(){ updateCoordsFast(); setTimeout(tickCoords,120) }
+ tickCoords();
+ })();
+
+
+