|
| 1 | +import { LitElement, html } from "lit"; |
| 2 | +import { unsafeHTML } from "lit/directives/unsafe-html.js"; |
| 3 | +import { map } from "lit/directives/map.js"; |
| 4 | +import { when } from "lit/directives/when.js"; |
| 5 | +import { live } from "lit/directives/live.js"; |
| 6 | +import "./layerConfig"; |
| 7 | +import "./tabs"; |
| 8 | +import { button } from "../../../../utils/styles/button"; |
| 9 | +import { radio } from "../../../../utils/styles/radio"; |
| 10 | +import { checkbox } from "../../../../utils/styles/checkbox"; |
| 11 | +import { slider } from "../../../../utils/styles/slider"; |
| 12 | + |
| 13 | +/** |
| 14 | + * Layer tools |
| 15 | + * |
| 16 | + * @element eox-layercontrol-layer-tools |
| 17 | + */ |
| 18 | +export class EOxLayerControlLayerTools extends LitElement { |
| 19 | + static properties = { |
| 20 | + layer: { attribute: false }, |
| 21 | + tools: { attribute: false }, |
| 22 | + unstyled: { type: Boolean }, |
| 23 | + }; |
| 24 | + |
| 25 | + constructor() { |
| 26 | + super(); |
| 27 | + |
| 28 | + /** |
| 29 | + * The native OL layer |
| 30 | + * @type {import("ol/layer").Layer} |
| 31 | + * @see {@link https://openlayers.org/en/latest/apidoc/module-ol_layer_Layer-Layer.html} |
| 32 | + */ |
| 33 | + this.layer = null; |
| 34 | + |
| 35 | + /** |
| 36 | + * @type Array<string> |
| 37 | + */ |
| 38 | + this.tools = []; |
| 39 | + |
| 40 | + /** |
| 41 | + * Render the element without additional styles |
| 42 | + */ |
| 43 | + this.unstyled = false; |
| 44 | + } |
| 45 | + |
| 46 | + /** |
| 47 | + * |
| 48 | + * @param {Array<string>} tools |
| 49 | + */ |
| 50 | + _parseActions = (tools) => |
| 51 | + tools?.filter((t) => |
| 52 | + ["remove", "sort"] |
| 53 | + .filter((k) => |
| 54 | + this.layer?.get("layerControlDisable") ? k !== "sort" : true |
| 55 | + ) |
| 56 | + .includes(t) |
| 57 | + ); |
| 58 | + |
| 59 | + /** |
| 60 | + * |
| 61 | + * @param {Array<string>} tools |
| 62 | + */ |
| 63 | + _parseTools = (tools) => |
| 64 | + tools?.filter((t) => { |
| 65 | + let pass = true; |
| 66 | + if (["remove", "sort"].includes(t)) { |
| 67 | + pass = false; |
| 68 | + } |
| 69 | + if (t === "info") { |
| 70 | + pass = this.layer.get("description"); |
| 71 | + } |
| 72 | + if (t === "config") { |
| 73 | + // @ts-ignore |
| 74 | + pass = this.layer.style_?.color; |
| 75 | + } |
| 76 | + return pass; |
| 77 | + }); |
| 78 | + |
| 79 | + _removeButton = html` |
| 80 | + <button |
| 81 | + class="remove-icon icon" |
| 82 | + @click=${() => { |
| 83 | + this.layer?.set("layerControlOptional", true); |
| 84 | + this.layer?.setVisible(false); |
| 85 | + this.dispatchEvent( |
| 86 | + new CustomEvent("changed", { |
| 87 | + detail: this.layer, |
| 88 | + bubbles: true, |
| 89 | + }) |
| 90 | + ); |
| 91 | + }} |
| 92 | + > |
| 93 | + x |
| 94 | + </button> |
| 95 | + `; |
| 96 | + |
| 97 | + _sortButton = html` |
| 98 | + <button class="sort-icon icon drag-handle">sort</button> |
| 99 | + `; |
| 100 | + |
| 101 | + createRenderRoot() { |
| 102 | + return this; |
| 103 | + } |
| 104 | + |
| 105 | + render() { |
| 106 | + return html` |
| 107 | + <style> |
| 108 | + ${this.#styleBasic} |
| 109 | + ${!this.unstyled && this.#styleEOX} |
| 110 | + </style> |
| 111 | + ${when( |
| 112 | + this._parseActions(this.tools)?.length + |
| 113 | + this._parseTools(this.tools)?.length > |
| 114 | + 0, |
| 115 | + () => html` |
| 116 | + ${when( |
| 117 | + this._parseActions(this.tools)?.length === 1 && |
| 118 | + this._parseTools(this.tools)?.length === 0, |
| 119 | + () => html` |
| 120 | + <div class="single-action-container"> |
| 121 | + <div class="single-action"> |
| 122 | + ${ |
| 123 | + // @ts-ignore |
| 124 | + this[`_${this._parseActions(this.tools)[0]}Button`] |
| 125 | + } |
| 126 | + </div> |
| 127 | + </div> |
| 128 | + `, |
| 129 | + () => html` |
| 130 | + <details class="tools"> |
| 131 | + <summary> |
| 132 | + <button |
| 133 | + class="icon ${this.tools.length === 1 |
| 134 | + ? `${this.tools[0]}-icon` |
| 135 | + : ""}" |
| 136 | + > |
| 137 | + Tools |
| 138 | + </button> |
| 139 | + </summary> |
| 140 | + <eox-layercontrol-tabs |
| 141 | + .actions=${this._parseActions(this.tools)} |
| 142 | + .tabs=${this._parseTools(this.tools)} |
| 143 | + .unstyled=${this.unstyled} |
| 144 | + > |
| 145 | + ${map( |
| 146 | + this._parseTools(this.tools), |
| 147 | + (tool) => html` |
| 148 | + <button slot="${tool}-icon" class="icon">${tool}</button> |
| 149 | + ` |
| 150 | + )} |
| 151 | +
|
| 152 | + <div slot="info-content"> |
| 153 | + ${unsafeHTML(this.layer.get("description"))} |
| 154 | + </div> |
| 155 | + <div slot="opacity-content"> |
| 156 | + <input |
| 157 | + type="range" |
| 158 | + min="0" |
| 159 | + max="1" |
| 160 | + step="0.01" |
| 161 | + value=${live(this.layer?.getOpacity())} |
| 162 | + @input=${( |
| 163 | + /** @type {{ target: { value: string; }; }} */ evt |
| 164 | + ) => this.layer.setOpacity(parseFloat(evt.target.value))} |
| 165 | + /> |
| 166 | + </div> |
| 167 | + <div slot="config-content"></div> |
| 168 | + <!--<eox-layercontrol-layerconfig |
| 169 | + slot="config-content" |
| 170 | + .layer=${this.layer} |
| 171 | + .unstyled=${this.unstyled} |
| 172 | + @changed=${() => this.requestUpdate()} |
| 173 | + ></eox-layercontrol-layerconfig>--> |
| 174 | + <div slot="remove-icon">${this._removeButton}</div> |
| 175 | + <div slot="sort-icon">${this._sortButton}</div> |
| 176 | + </eox-layercontrol-tabs> |
| 177 | + </details> |
| 178 | + ` |
| 179 | + )} |
| 180 | + ` |
| 181 | + )} |
| 182 | + `; |
| 183 | + } |
| 184 | + |
| 185 | + #styleBasic = ``; |
| 186 | + |
| 187 | + #styleEOX = ` |
| 188 | + ${button} |
| 189 | + ${radio} |
| 190 | + ${checkbox} |
| 191 | + ${slider} |
| 192 | + button.icon.drag-handle { |
| 193 | + cursor: n-resize; |
| 194 | + } |
| 195 | + .single-action-container, |
| 196 | + details.tools { |
| 197 | + position: relative; |
| 198 | + } |
| 199 | + eox-layercontrol-layer details summary::before { |
| 200 | + content: ""; |
| 201 | + } |
| 202 | + details.tools[open] { |
| 203 | + /*border-top: 1px solid #0041703a;*/ |
| 204 | + } |
| 205 | + .single-action { |
| 206 | + position: relative; |
| 207 | + } |
| 208 | + details.tools summary .icon { |
| 209 | + pointer-events: none; |
| 210 | + } |
| 211 | + .single-action, |
| 212 | + details.tools summary { |
| 213 | + position: absolute; |
| 214 | + right: 0; |
| 215 | + top: -24px; |
| 216 | + display: flex; |
| 217 | + border-radius: 4px; |
| 218 | + cursor: pointer; |
| 219 | + } |
| 220 | + .single-action .icon::before, |
| 221 | + details.tools summary .icon::before { |
| 222 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004170' viewBox='0 0 24 24'%3E%3Ctitle%3Edots-vertical%3C/title%3E%3Cpath d='M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z' /%3E%3C/svg%3E"); |
| 223 | + } |
| 224 | + .single-action, |
| 225 | + details.tools summary, |
| 226 | + eox-layercontrol-tabs button.icon { |
| 227 | + transition: opacity .2s; |
| 228 | + } |
| 229 | + .single-action, |
| 230 | + details.tools summary { |
| 231 | + opacity: .5; |
| 232 | + } |
| 233 | + eox-layercontrol-tabs button.icon { |
| 234 | + opacity: .7; |
| 235 | + } |
| 236 | + .single-action:hover, |
| 237 | + details.tools summary:hover, |
| 238 | + eox-layercontrol-tabs button.icon:hover { |
| 239 | + opacity: 1; |
| 240 | + } |
| 241 | + .tools-placeholder, |
| 242 | + .single-action .icon, |
| 243 | + .single-action .icon::before, |
| 244 | + details.tools summary .icon, |
| 245 | + details.tools summary .icon::before { |
| 246 | + height: 16px; |
| 247 | + width: 16px; |
| 248 | + } |
| 249 | + eox-layercontrol-tabs button.icon { |
| 250 | + display: flex; |
| 251 | + justify-content: center; |
| 252 | + } |
| 253 | + eox-layercontrol-tabs .icon::before { |
| 254 | + width: 16px; |
| 255 | + height: 16px; |
| 256 | + } |
| 257 | + details.tools summary .info-icon, |
| 258 | + button.icon[slot=info-icon]::before { |
| 259 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004170' viewBox='0 0 24 24'%3E%3Ctitle%3Einformation-outline%3C/title%3E%3Cpath d='M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z' /%3E%3C/svg%3E"); |
| 260 | + } |
| 261 | + details.tools summary .opacity-icon, |
| 262 | + button.icon[slot=opacity-icon]::before { |
| 263 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004170' viewBox='0 0 24 24'%3E%3Ctitle%3Eopacity%3C/title%3E%3Cpath d='M17.66,8L12,2.35L6.34,8C4.78,9.56 4,11.64 4,13.64C4,15.64 4.78,17.75 6.34,19.31C7.9,20.87 9.95,21.66 12,21.66C14.05,21.66 16.1,20.87 17.66,19.31C19.22,17.75 20,15.64 20,13.64C20,11.64 19.22,9.56 17.66,8M6,14C6,12 6.62,10.73 7.76,9.6L12,5.27L16.24,9.65C17.38,10.77 18,12 18,14H6Z' /%3E%3C/svg%3E"); |
| 264 | + } |
| 265 | + details.tools summary .config-icon, |
| 266 | + button.icon[slot=config-icon]::before { |
| 267 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004170' viewBox='0 0 24 24'%3E%3Ctitle%3Etune%3C/title%3E%3Cpath d='M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z' /%3E%3C/svg%3E"); |
| 268 | + } |
| 269 | + .single-action .remove-icon::before, |
| 270 | + [slot=remove-icon] button.icon::before { |
| 271 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ff0000' viewBox='0 0 24 24'%3E%3Ctitle%3Edelete-outline%3C/title%3E%3Cpath d='M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19M8,9H16V19H8V9M15.5,4L14.5,3H9.5L8.5,4H5V6H19V4H15.5Z' /%3E%3C/svg%3E"); |
| 272 | + } |
| 273 | + .single-action .sort-icon::before, |
| 274 | + [slot=sort-icon] button.icon::before { |
| 275 | + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004170' viewBox='0 0 24 24'%3E%3Ctitle%3Edrag-horizontal-variant%3C/title%3E%3Cpath d='M21 11H3V9H21V11M21 13H3V15H21V13Z' /%3E%3C/svg%3E"); |
| 276 | + } |
| 277 | + [slot=info-content], |
| 278 | + [slot=opacity-content] { |
| 279 | + padding: 12px 6px; |
| 280 | + } |
| 281 | + `; |
| 282 | +} |
| 283 | + |
| 284 | +customElements.define( |
| 285 | + "eox-layercontrol-layer-tools", |
| 286 | + EOxLayerControlLayerTools |
| 287 | +); |
0 commit comments