all repos — onyx @ 7ef255c556f3cf4d7889d58120319550a9bea53e

minimal map annotation and location data sharing tool

implement menu that keeps track of overlays, sets home
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmL7Lw4ACgkQO3+8IhRO
Y5iR7A//X1+klgDHZaBXVmzTOpd6eoRAvxFOT0Efixc3TNwMfUQo907ShKZosGCP
N+ufj5yT2jrZvmSpBOcGduNKRrSbDbh5J01eCKXV53USVJe8udjQ+ESIvzNoehgZ
4fNGYUH6kjAJoXCYi9otoUKVe+hWkJK7vUjow7p3StIqEigLuxp1hVaxueQfdpfL
7Zd01l1WjRtDmC+8GD77wcOJ5yWuGC+PQjxATKEXpqN1YUWDmss8I1YWfYUlk3cu
mo/e777WtrGbrXMmtRcwswam9MSS0R3FkDNrNro0VTaRMlEenTAO9MM+UIBwHCeo
Bjc5ysBkMpFwXRimG59L/DWnvK2JDMnAWbVXK5piRCEuhPZOyP9BwmnOPYfeW4bO
diOcHYO0IyIRpBC7DFKqgESxu6efPmKqtmUrhVzG4rJEqHIvlU+iCpoTyR0A84q9
nkYGhJuMcZFoBp1xVf9n0fE74qOneevJzxh2HTAIbaGEWBs++Iup7s5YITaIfrYF
qS1DYlxjcFFml0vowJHG9RuSpdcX72UkaA61DPOM3rX7x1HKPwj2Ek+qi6/aCByH
lMTVZWeAJwwNUR297PZpj6YrRkUculxI4AcD1cQldhxBWYgf2zlORwFmpeLrB27+
DrVtb6BlfgBPhX/5VVWw8iDhuS393J6lCEn2AQIU5EoAwtrO3NY=
=Z+8z
-----END PGP SIGNATURE-----
commit

7ef255c556f3cf4d7889d58120319550a9bea53e

parent

d42b5fcd3da322a63c8525b0b462426517bb5670

M src/10-overlay.tssrc/10-overlay.ts

@@ -46,44 +46,104 @@ this.points = points;

this.options = options; } - add(map: L.Map): void { - this.self.addTo(map); + abstract add(map: L.Map): void; + + abstract remove(map: L.Map): void; + + abstract menuItem: Node | null; + + static listAdd(self: OverlayBase, listName: string) { + const list = document.getElementById(listName); + if (list) { + const li = document.createElement("li"); + const a = document.createElement("a"); + if (li && a) { + a.innerText = self.name; + a.href = "#"; + a.onclick = (e: any) => { + //show EditOverlayModal with this overlay's data + }; + li.appendChild(a); + list.appendChild(li); + self.menuItem = li; + } + } } - remove(map: L.Map): void { - this.self.removeFrom(map); + static listRemove(self: OverlayBase, listName: string) { + const list = document.getElementById(listName); + if (list && self.menuItem) { + list.removeChild(self.menuItem); + } } } - class Marker extends OverlayBase { + menuItem: Node | null = null; + constructor(name: string, desc: string, point: Point, options: any) { super(name, desc, [ point ], options); this.self = L.marker(point); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + + add(map: L.Map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "markers-list"); + } + + remove(map: L.Map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "markers-list"); + } } class Circle extends OverlayBase { + menuItem: Node | null = null; + constructor(name: string, desc: string, point: Point, options: any) { super(name, desc, [ point ], options); this.self = L.circle(point, options); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + + add(map: L.Map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "circles-list"); + } + + remove(map: L.Map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "circles-list"); + } } class Polygon extends OverlayBase { + menuItem: Node | null = null; + constructor(name: string, desc: string, points: Point[], options: any) { super(name, desc, points, options); this.self = L.polygon(points, options); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + + add(map: L.Map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "polygons-list"); + } + + remove(map: L.Map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "polygons-list"); + } } class Polyline extends OverlayBase { + menuItem: Node | null = null; + constructor() { super("", "", [ ], {}); this.self = L.polyline([]);

@@ -101,6 +161,14 @@ }

numPoints(): number { return this.self.getLatLngs().length; + } + + add(map: L.Map) { + this.self.addTo(map); + } + + remove(map: L.Map) { + this.self.removeFrom(map); } }
A src/19-modal.ts

@@ -0,0 +1,5 @@

+interface Modal { + self(): HTMLElement | null; + visible(): boolean; + setVisible(v: boolean): void; +}
M src/20-createOverlayModal.tssrc/20-createOverlayModal.ts

@@ -1,10 +1,16 @@

-class CreateOverlayModal { +class CreateOverlayModal implements Modal { constructor() { const _this = this; const closeBtn = document.getElementById("createOverlay-closeBtn"); if (closeBtn) { closeBtn.onclick = ()=>{_this.setVisible(false)}; + } + const s = this.self(); + if (s) { + s.onsubmit = (e: any): void => { + e.preventDefault(); + } } }

@@ -89,7 +95,7 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const point = new Marker(name, desc, args.latlng, {title: name, alt: name});

@@ -108,7 +114,7 @@ submitBtn.onclick = () => {

const radius = _this.radiusField(); const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const circle = new Circle(name, desc, args.latlng, {radius: Number(radius) || 500});

@@ -126,7 +132,7 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const polygon = new Polygon(name, desc, args.points, {});
M src/21-cancelModal.tssrc/21-cancelModal.ts

@@ -1,4 +1,4 @@

-class CancelModal { +class CancelModal implements Modal { self(): HTMLElement | null { return document.getElementById("cancel-container"); }
M src/22-okCancelModal.tssrc/22-okCancelModal.ts

@@ -1,4 +1,4 @@

-class OKCancelModal { +class OKCancelModal implements Modal { self(): HTMLElement | null { return document.getElementById("confirm-container"); }
M src/23-infoModal.tssrc/23-infoModal.ts

@@ -1,4 +1,4 @@

-class InfoModal { +class InfoModal implements Modal { constructor() { const _this = this;
A src/25-overlayManagerModal.ts

@@ -0,0 +1,20 @@

+class OverlayManagementModal implements Modal { + self(): HTMLElement | null { + return document.getElementById("overlays-menu-container"); + } + + visible(): boolean { + return this.self()?.style.display !== "none"; + } + + setVisible(v: boolean): void { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "grid" : "none"; + } + } + + constructor() { + this.setVisible(false); + } +}
M src/29-modalCollection.tssrc/29-modalCollection.ts

@@ -3,22 +3,26 @@ createOverlay: CreateOverlayModal;

cancel: CancelModal; okCancel: OKCancelModal; info: InfoModal; + overlayMgr: OverlayManagementModal; constructor( createOverlay: CreateOverlayModal, cancel: CancelModal, okCancel: OKCancelModal, - info: InfoModal + info: InfoModal, + overlayMgr: OverlayManagementModal ) { this.createOverlay = createOverlay; this.cancel = cancel; this.okCancel = okCancel; this.info = info; + this.overlayMgr = overlayMgr; } closeAll(): void { this.createOverlay.setVisible(false); this.cancel.setVisible(false); this.okCancel.setVisible(false); + this.overlayMgr.setVisible(false); } }
M src/40-handlers.tssrc/40-handlers.ts

@@ -74,6 +74,7 @@ if (menuBtn) {

menuBtn.classList.remove("activeBtn"); } } catch {} + self.overlays.polyline.clearPoints(); } }

@@ -313,7 +314,26 @@

static setHome(e: any): void { const self = MapHandler.instance; if (self) { - localStorage.setItem("home", JSON.stringify(self.map.getCenter())); + self.modals.closeAll(); + const okCancel = self.modals.okCancel; + okCancel.setMsg("Set Home to current coordinates?"); + const okBtn = okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = (e: any) => { + okCancel.setVisible(false); + localStorage.setItem("home", JSON.stringify(self.map.getCenter() as Point)); + const info = self.modals.info; + info.setMsg("Home coordinates set"); + info.setVisible(true); + } + } + const cancelBtn = okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + okCancel.setVisible(false); + } + } + okCancel.setVisible(true); } }

@@ -326,6 +346,19 @@ const home = <Point>JSON.parse(homeData);

if (home) { self.map.setView(home, 13); } + } + } + } + + static toggleMenu(e: any): void { + const self = MapHandler.instance; + if (self) { + const visible = self.modals.overlayMgr.visible(); + self.modals.closeAll(); + MapHandler.resetMapClick(); + self.modals.overlayMgr.setVisible(!visible); + if (!visible) { + (e.target as HTMLElement).classList.add("activeBtn"); } } }
M src/99-onyx-scry.tssrc/99-onyx-scry.ts

@@ -33,7 +33,8 @@ const modals = new ModalCollection(

new CreateOverlayModal(), new CancelModal(), new OKCancelModal(), - new InfoModal()); + new InfoModal(), + new OverlayManagementModal()); MapHandler.init(map, overlays, TileLayerWrapper.layers, modals);

@@ -45,27 +46,13 @@

MapHandler.setButtonClick("save-btn", MapHandler.overlaySave); MapHandler.setButtonClick("clear-btn", MapHandler.overlayClear); MapHandler.setButtonClick("restore-btn", MapHandler.overlayReset); - MapHandler.setButtonClick("menu-btn", ()=>{}); + MapHandler.setButtonClick("menu-btn", MapHandler.toggleMenu); + + MapHandler.setButtonClick("set-home-btn", MapHandler.setHome); MapHandler.setButtonClick("tiles-btn", MapHandler.swapTiles); - map.on("locationfound", ()=> { - const okCancel = modals.okCancel; - okCancel.setMsg("Set Home to current location?"); - const okBtn = okCancel.okBtn(); - if (okBtn) { - okBtn.onclick = (e: any) => { - okCancel.setVisible(false); - MapHandler.setHome(null); - } - } - const cancelBtn = okCancel.cancelBtn(); - if (cancelBtn) { - cancelBtn.onclick = () => { - okCancel.setVisible(false); - } - } - }); + map.on("locationfound", MapHandler.setHome); map.on("locationerror", ()=> { const info = modals.info;

@@ -80,6 +67,8 @@ map.setView(home, 13);

} else { map.locate({setView: true, maxZoom: 13}); } + + modals.closeAll(); } init();
M static/index.htmlstatic/index.html

@@ -40,7 +40,7 @@ <form id="createOverlay-content">

<label for="createOverlay-name">Name</label><br/> <input type="text" id="createOverlay-name" required ><br/> <label for="createOverlay-desc">Description</label><br/> - <textarea id="createOverlay-desc" required></textarea><br/> + <textarea id="createOverlay-desc"></textarea><br/> <div id="radius-container"> <label for="createOverlay-radius">Radius (meters)</label><br/> <input type="number" step="1" id="createOverlay-radius" value="500" required><br/>

@@ -75,22 +75,24 @@ <div id="import-export-container">

<h2></h2> <textarea id="import-export-textarea"></textarea> <div class="multiBtn-container"> - <button id="import-export-ok-btn">OK</button> - <button id="import-export-cancel-btn">Cancel</button> + <button class="positive-btn" id="import-export-ok-btn">OK</button> + <button class="negative-btn" id="import-export-cancel-btn">Cancel</button> </div> </div> <div id="overlays-menu-container"> - <button class="closeBtn" id="overlys-closeBtn">x</button> - <details id="markers-wrapper"><summary>Markers</summary><ul id="markers-list"></ul></details> - <details id="circles-wrapper"><summary>Circles</summary><ul id="circles-list"></ul></details> - <details id="polygons-wrapper"><summary>Polygons</summary><ul id="polygons-list"></ul></details> + <div id="overlays-list"> + <details id="markers-wrapper"><summary>Markers</summary><ul id="markers-list"></ul></details> + <details id="circles-wrapper"><summary>Circles</summary><ul id="circles-list"></ul></details> + <details id="polygons-wrapper"><summary>Polygons</summary><ul id="polygons-list"></ul></details> + </div> <div class="multiBtn-container"> + <button id="set-home-btn">Set Home</button> <button id="import-btn">Import</button> <button id="export-all-btn">Export All</button> </div> </div> -<!--</div>--> + </body> <link rel='stylesheet' type="text/css" href="./leaflet.css"> <script src="./leaflet.js"></script>
M static/onyx-scry.jsstatic/onyx-scry.js

@@ -27,37 +27,82 @@ this.desc = desc;

this.points = points; this.options = options; } - add(map) { - this.self.addTo(map); + static listAdd(self, listName) { + const list = document.getElementById(listName); + if (list) { + const li = document.createElement("li"); + const a = document.createElement("a"); + if (li && a) { + a.innerText = self.name; + a.href = "#"; + a.onclick = (e) => { + //show EditOverlayModal with this overlay's data + }; + li.appendChild(a); + list.appendChild(li); + self.menuItem = li; + } + } } - remove(map) { - this.self.removeFrom(map); + static listRemove(self, listName) { + const list = document.getElementById(listName); + if (list && self.menuItem) { + list.removeChild(self.menuItem); + } } } class Marker extends OverlayBase { constructor(name, desc, point, options) { super(name, desc, [point], options); + this.menuItem = null; this.self = L.marker(point); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + add(map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "markers-list"); + } + remove(map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "markers-list"); + } } class Circle extends OverlayBase { constructor(name, desc, point, options) { super(name, desc, [point], options); + this.menuItem = null; this.self = L.circle(point, options); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + add(map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "circles-list"); + } + remove(map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "circles-list"); + } } class Polygon extends OverlayBase { constructor(name, desc, points, options) { super(name, desc, points, options); + this.menuItem = null; this.self = L.polygon(points, options); this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } + add(map) { + this.self.addTo(map); + OverlayBase.listAdd(this, "polygons-list"); + } + remove(map) { + this.self.removeFrom(map); + OverlayBase.listRemove(this, "polygons-list"); + } } class Polyline extends OverlayBase { constructor() { super("", "", [], {}); + this.menuItem = null; this.self = L.polyline([]); } insertPoint(pt) {

@@ -71,6 +116,12 @@ }

numPoints() { return this.self.getLatLngs().length; } + add(map) { + this.self.addTo(map); + } + remove(map) { + this.self.removeFrom(map); + } } class OverlayState { constructor() {

@@ -182,6 +233,12 @@ const closeBtn = document.getElementById("createOverlay-closeBtn");

if (closeBtn) { closeBtn.onclick = () => { _this.setVisible(false); }; } + const s = this.self(); + if (s) { + s.onsubmit = (e) => { + e.preventDefault(); + }; + } } self() { return document.getElementById("createOverlay-container");

@@ -252,7 +309,7 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const point = new Marker(name, desc, args.latlng, { title: name, alt: name });

@@ -271,7 +328,7 @@ submitBtn.onclick = () => {

const radius = _this.radiusField(); const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const circle = new Circle(name, desc, args.latlng, { radius: Number(radius) || 500 });

@@ -289,7 +346,7 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); - if (name.trim().length < 1 || desc.trim().length < 1) { + if (name.trim().length < 1) { return; } const polygon = new Polygon(name, desc, args.points, {});

@@ -390,17 +447,37 @@ modal.style.display = v ? "block" : "none";

} } } +class OverlayManagementModal { + self() { + return document.getElementById("overlays-menu-container"); + } + visible() { + var _a; + return ((_a = this.self()) === null || _a === void 0 ? void 0 : _a.style.display) !== "none"; + } + setVisible(v) { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "grid" : "none"; + } + } + constructor() { + this.setVisible(false); + } +} class ModalCollection { - constructor(createOverlay, cancel, okCancel, info) { + constructor(createOverlay, cancel, okCancel, info, overlayMgr) { this.createOverlay = createOverlay; this.cancel = cancel; this.okCancel = okCancel; this.info = info; + this.overlayMgr = overlayMgr; } closeAll() { this.createOverlay.setVisible(false); this.cancel.setVisible(false); this.okCancel.setVisible(false); + this.overlayMgr.setVisible(false); } } class MapHandler {

@@ -476,6 +553,7 @@ menuBtn.classList.remove("activeBtn");

} } catch (_g) { } + self.overlays.polyline.clearPoints(); } } static addMarker(e) {

@@ -695,7 +773,26 @@ }

static setHome(e) { const self = MapHandler.instance; if (self) { - localStorage.setItem("home", JSON.stringify(self.map.getCenter())); + self.modals.closeAll(); + const okCancel = self.modals.okCancel; + okCancel.setMsg("Set Home to current coordinates?"); + const okBtn = okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = (e) => { + okCancel.setVisible(false); + localStorage.setItem("home", JSON.stringify(self.map.getCenter())); + const info = self.modals.info; + info.setMsg("Home coordinates set"); + info.setVisible(true); + }; + } + const cancelBtn = okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + okCancel.setVisible(false); + }; + } + okCancel.setVisible(true); } } static goHome(e) {

@@ -710,6 +807,18 @@ }

} } } + static toggleMenu(e) { + const self = MapHandler.instance; + if (self) { + const visible = self.modals.overlayMgr.visible(); + self.modals.closeAll(); + MapHandler.resetMapClick(); + self.modals.overlayMgr.setVisible(!visible); + if (!visible) { + e.target.classList.add("activeBtn"); + } + } + } } MapHandler.instance = null; function init() {

@@ -730,7 +839,7 @@ overlays.markers.forEach(m => m.add(map));

overlays.circles.forEach(m => m.add(map)); overlays.polygons.forEach(m => m.add(map)); overlays.polyline.add(map); - const modals = new ModalCollection(new CreateOverlayModal(), new CancelModal(), new OKCancelModal(), new InfoModal()); + const modals = new ModalCollection(new CreateOverlayModal(), new CancelModal(), new OKCancelModal(), new InfoModal(), new OverlayManagementModal()); MapHandler.init(map, overlays, TileLayerWrapper.layers, modals); MapHandler.setButtonClick("home-btn", MapHandler.goHome); MapHandler.setButtonClick("addPoint-btn", MapHandler.markerCollect);

@@ -739,25 +848,10 @@ MapHandler.setButtonClick("addPolygon-btn", MapHandler.polygonCollect);

MapHandler.setButtonClick("save-btn", MapHandler.overlaySave); MapHandler.setButtonClick("clear-btn", MapHandler.overlayClear); MapHandler.setButtonClick("restore-btn", MapHandler.overlayReset); - MapHandler.setButtonClick("menu-btn", () => { }); + MapHandler.setButtonClick("menu-btn", MapHandler.toggleMenu); + MapHandler.setButtonClick("set-home-btn", MapHandler.setHome); MapHandler.setButtonClick("tiles-btn", MapHandler.swapTiles); - map.on("locationfound", () => { - const okCancel = modals.okCancel; - okCancel.setMsg("Set Home to current location?"); - const okBtn = okCancel.okBtn(); - if (okBtn) { - okBtn.onclick = (e) => { - okCancel.setVisible(false); - MapHandler.setHome(null); - }; - } - const cancelBtn = okCancel.cancelBtn(); - if (cancelBtn) { - cancelBtn.onclick = () => { - okCancel.setVisible(false); - }; - } - }); + map.on("locationfound", MapHandler.setHome); map.on("locationerror", () => { const info = modals.info; info.setMsg("Could not get location data");

@@ -771,5 +865,6 @@ }

else { map.locate({ setView: true, maxZoom: 13 }); } + modals.closeAll(); } init();
M static/style.cssstatic/style.css

@@ -57,11 +57,18 @@ background: black;

font-size: 5vh; padding-left: 0.5ch; padding-right: 0.5ch; + border: solid 1px black; border-bottom: solid 0.1em black; } -#mapControls button.activeBtn, #mapControls button:hover { +#mapControls .activeBtn, +#mapControls button:hover { color: white; + border-bottom: solid 0.1em #1f9b92; +} + +#mapControls button:focus { + border: dotted 1px #1f9b92; border-bottom: solid 0.1em #1f9b92; }

@@ -154,7 +161,7 @@ width: 12ch;

text-align: right; } -button.closeBtn { +.closeBtn { float: right; background: transparent; font-size: 200%;

@@ -165,11 +172,17 @@ padding-left: 1em;

padding-right: 1em; } -button.closeBtn:hover { +.closeBtn:hover, +.closeBtn:focus { color: crimson; } -button#createOverlay-submitBtn, button.positive-btn, button.negative-btn { +#createOverlay-submitBtn, +.positive-btn, +.negative-btn, +#set-home-btn, +#import-btn, +#export-all-btn { font-size: 150%; background: transparent; color: white;

@@ -180,32 +193,41 @@ padding: 0.25em;

text-transform: uppercase; } -button#createOverlay-submitBtn:hover { +#createOverlay-submitBtn:hover, +#createOverlay-submitBtn:focus, +#set-home-btn:hover, +#set-home-btn:focus, +#import-btn:hover, +#import-btn:focus, +#export-all-btn:hover, +#export-all-btn:focus { background: white; color: black; border: solid 2px white; } -button.positive-btn, button.negative-btn { +.positive-btn, .negative-btn { font-size: 66.66%; margin-top: 1em; } -button.positive-btn { +.positive-btn { border: solid 2px #1f9b92; float: left; } -button.positive-btn:hover { +.positive-btn:hover, +.positive-btn:focus { color: black; background: #1f9b92; } -button.negative-btn { +.negative-btn { float: right; } -button.negative-btn:hover { +.negative-btn:hover, +.negative-btn:focus { color: black; background: crimson; border: solid 2px crimson;

@@ -231,7 +253,7 @@ float: left;

line-height: 200%; } -#info-container button.closeBtn { +#info-container .closeBtn { font-size: 150%; padding: 0; margin-left: 1ch;

@@ -252,9 +274,71 @@ }

#overlays-menu-container { position: fixed; - height: calc(100vh - 2.5em); + height: 100vh; right: 0; + top: 0; width: 100%; max-width: 800px; background: black; + color: white; + z-index:2; + display: none; + padding: 1em; + font-size: 150%; + box-sizing: border-box; + grid-template-rows: 1fr auto; +} + +#overlays-menu-container .multiBtn-container { + text-align: center; + grid-row: 2; + margin-bottom: 3em; +} + +#overlays-list { + font-size: 200%; + grid-row: 1; + max-height: 100%; + overflow: auto; + +} + +#overlays-list details summary { + outline-style: none; + border-bottom: solid 1px black; +} + +#overlays-list details summary:hover { + color: #1f9b92; +} + +#overlays-list details summary:focus { + border-bottom: dotted 1px #1f9b92; +} + +#overlays-list ul { + list-style: none; + margin: 0.5em; +} + +#overlays-list a { + color: white; + text-decoration: none; + outline-style: none; + border-bottom: solid 1px black; +} + +#overlays-list a:hover { + color: #1f9b92; +} + +#overlays-list a:focus { + border-bottom: dotted 1px #1f9b92; +} +#overlays-list details { + margin: 1em; +} + +#import-export-container { + display: none; }