@dkvz/img-lightbox 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,16 @@
1
1
  # img-lightbox
2
2
  Web Component / Custom Element with no dependencies to make a lightbox effect around images.
3
3
 
4
+ Check out the [demo](https://dkvz.eu/stuff/img-lightbox-demo/)
5
+
4
6
  The idea is that it should still display the image and link to the full sized one if JS is disabled, hasn't loaded for some reason, or if web components are not supported.
5
7
 
6
8
  I quickly made this in regard to a blog article I was writing, it could be improved **a lot**.
7
9
 
10
+ Uncompressed minified size: 8.5Kb including the loading spinner image.
11
+
12
+ **Note**: we no longer minify the build - It seems to be standard practice for libraries nowadays.
13
+
8
14
  ## Using the component from npm
9
15
  To use it in a project with a module bundler, install the dependency first:
10
16
  ```
@@ -20,7 +26,7 @@ customElements.define('img-lightbox', ImgLightbox);
20
26
 
21
27
  To use the component in a web page, you're expected to put at least an img tag inside of it.
22
28
 
23
- It's however best to enclose the img in a link as in the example you'll find in `src/shared/testpage.html`:
29
+ It's however best to enclose the img in a link, like so:
24
30
 
25
31
  ```html
26
32
  <img-lightbox>
@@ -33,6 +39,29 @@ It's however best to enclose the img in a link as in the example you'll find in
33
39
 
34
40
  You'll probably want to add some styling to the element in your global styles as it doesn't have any by default.
35
41
 
42
+ The component sets up a default outline on focus, but you might want to add your own globally (which will trump the default one) like so:
43
+ ```css
44
+ img-lightbox:active, img-lightbox:focus {
45
+ outline: 2px solid rgba(20, 20, 200, 0.65);
46
+ }
47
+ ```
48
+
49
+ You also may have strange spacing issues if the a and img elements have their default "inline" display mode. Which could be changed like so:
50
+ ```css
51
+ img-lightbox a, img-lightbox img {
52
+ display: block;
53
+ }
54
+ ```
55
+
56
+ This is also where you should set any max-width or max-height. Or you could set it on img-lightbox itself but then you need to set width and height to 100% as in:
57
+ ```css
58
+ img-lightbox a, img-lightbox img {
59
+ display: block;
60
+ width: 100%;
61
+ height: 100%;
62
+ }
63
+ ```
64
+
36
65
  ## Building the component
37
66
 
38
67
  ### Build requirements
@@ -51,11 +80,6 @@ Build using either:
51
80
  ```
52
81
  npm run build
53
82
  ```
54
- For the shadow DOM (default) version and:
55
- ```
56
- npm run build-no-shadow
57
- ```
58
- For the version that does not use the shadow DOM API at all.
59
83
 
60
84
  You'll find the build script in the `dist` folder.
61
85
 
@@ -66,8 +90,20 @@ To manually use it in some page, you could do something like this:
66
90
  customElements.define('img-lightbox', ImgLightbox.default);
67
91
  </script>
68
92
  ```
93
+ **Update 2025**: There is a .mjs file built as well and it might be a good idea to use that one (with `type="module" in the script tag`).
94
+
69
95
  The loading icon SVG file is normally not necessary but since I change my mind all the time about it you might want to copy it along anyway.
70
96
 
97
+ ## Build without shadow DOM
98
+ In the past I had a way to build the component without using the shadow DOM at all, which has a few consequences but I think the main idea was to support some old browsers.
99
+
100
+ Anyway, after upgrading Parcel to v2 I didn't take time to fix the build command for the no-shadow DOM version.
101
+
102
+ It used to be:
103
+ ```
104
+ npm run build-no-shadow
105
+ ```
106
+
71
107
  The no-shadow DOM version also requires extra styles to work. See `src/no-shadow/index.pug`.
72
108
 
73
109
  ## Remarks
@@ -111,17 +147,33 @@ if (event.altKey)
111
147
  ## Resources and copyright notices
112
148
  - The hourglass icon has been modified from the GPL-licensed file here: https://fr.wikipedia.org/wiki/Fichier:Circle-icons-hourglass.svg
113
149
 
150
+ ## Upgrade to parcel 2
151
+ The doc: https://parceljs.org/migration/parcel-1/
152
+
153
+ I removed all of these deps:
154
+ ```
155
+ "parcel-bundler": "^1.12.4",
156
+ "parcel-plugin-clean-dist": "0.0.6",
157
+ "parcel-plugin-url-loader": "^1.3.1",
158
+ ```
159
+
160
+ Then added the latest parcel through npm install.
161
+
162
+ I need to add a manual wipe of the dist folder before the build commands, doing a quick rimraf for now.
163
+
164
+ I also had to change how the loading SVG gets inlined. It's now imported as a string.
165
+
114
166
  ## TODO
115
167
  - [ ] Test on all browsers
116
168
  - [ ] Write tests - Probably going to need jsdom
117
169
  - [x] Don't forget to register the keyboard events
118
170
  - [x] Use template tags, they say it's better (here)[https://github.com/GoogleChromeLabs/howto-components/blob/master/elements/howto-checkbox/howto-checkbox.js]
119
- - [ ] Document how to check for web component browser support
120
171
  - [x] Disable overflow on the fullscreen overlay
121
172
  - [x] Make a shadow DOM version
122
- - [ ] To maximize accessibility we need some kind of focus outline
173
+ - [x] To maximize accessibility we need some kind of focus outline
123
174
  - [ ] Add support for lightbox over an svg tag instead of img
124
175
  - [ ] Support for iframes would be really cool
125
176
  - [x] Link the repo in package.json
126
177
  - [ ] Add a gif to show what this does - A codepen link would also work
178
+ - [x] Add the minified uncompressed bundle size to the README introduction
127
179
 
@@ -1,6 +1,198 @@
1
- parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c<t.length;c++)try{f(t[c])}catch(e){i||(i=e)}if(t.length){var l=f(t[t.length-1]);"object"==typeof exports&&"undefined"!=typeof module?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):n&&(this[n]=l)}if(parcelRequire=f,i)throw i;return f}({"q71P":[function(require,module,exports) {
2
- module.exports="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2NCA2NCIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNjQgNjQiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPjxtZXRhZGF0YT48cmRmOlJERj48Y2M6V29yayByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIvPjxkYzp0aXRsZS8+PC9jYzpXb3JrPjwvcmRmOlJERj48L21ldGFkYXRhPgo8Zz4KCQk8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIzMiIgY3k9IjMyIiByPSIzMiIvPgoJPC9nPjxnIGNsYXNzPSJzdDEiIG9wYWNpdHk9Ii4yIj4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJtNDYgNTBoLTJ2LTRjMC00LjUtMy03LjQtMy03LjRzLTMtMi44LTMuOS0zLjcgMC0xLjggMC0xLjggMS4zLTEuMyA0LjItNGMyLjgtMi43IDIuNy02LjcgMi43LTYuN3YtNS4xbC0xMi0xLTEyIDF2NS4xcy0wLjEgMy45IDIuNyA2LjdjMi44IDIuNyA0LjIgNCA0LjIgNHMwLjkgMC45IDAgMS44LTMuOSAzLjctMy45IDMuNy0zIDIuOC0zIDcuNHY0aC0yYy0xLjEgMC0yIDAuOS0yIDJzMC45IDIgMiAyaDI4YzEuMSAwIDItMC45IDItMnMtMC45LTItMi0yeiIgZmlsbD0iIzIzMWYyMCIvPgoJPC9nPgoJCTxwYXRoIGNsYXNzPSJzdDMiIGQ9Im00MSAzNi42cy0zLTIuOC0zLjktMy43IDAtMS44IDAtMS44IDEuMy0xLjMgNC4yLTRjMi44LTIuNyAyLjctNi43IDIuNy02Ljd2LTUuMWwtMTItMS0xMiAxdjUuMXMtMC4xIDMuOSAyLjcgNi43YzIuOCAyLjcgNC4yIDQgNC4yIDRzMC45IDAuOSAwIDEuOC0zLjkgMy43LTMuOSAzLjctMyAyLjgtMyA3LjR2NS4xaDI0di01LjFjMC00LjUtMy03LjQtMy03LjR6IiBmaWxsPSIjZmZmIi8+CgkKCQk8cGF0aCBjbGFzcz0ic3Q0IiBkPSJtMzEgNDN2LTExYzAtMi4xLTEtMy40LTEuMy0zLjdsLTQuMi00Yy0xLjUtMS40LTEuNS0zLjctMS41LTMuN2gxNnMwIDIuMy0xLjUgMy43bC00LjIgNGMtMC40IDAuMy0xLjMgMS42LTEuMyAzLjd2MTF6Ii8+Cgk8ZyBjbGFzcz0ic3Q1IiBvcGFjaXR5PSIuMyI+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0ibTQ4IDE2YzAgMS4xLTAuOSAyLTIgMmgtMjhjLTEuMSAwLTItMC45LTItMnMwLjktMiAyLTJoMjhjMS4xIDAgMiAwLjkgMiAyeiIgZmlsbD0iIzIzMWYyMCIvPgoJPC9nPjxnIGZpbGw9IiNmZmYiPgoJCTxwYXRoIGNsYXNzPSJzdDYiIGQ9Im00OCAxNGMwIDEuMS0wLjkgMi0yIDJoLTI4Yy0xLjEgMC0yLTAuOS0yLTJzMC45LTIgMi0yaDI4YzEuMSAwIDIgMC45IDIgMnoiIGZpbGw9IiNmZmYiLz4KCTwvZz48ZyBmaWxsPSIjZmZmIj4KCQk8cGF0aCBjbGFzcz0ic3Q2IiBkPSJtNDggNTBjMCAxLjEtMC45IDItMiAyaC0yOGMtMS4xIDAtMi0wLjktMi0yczAuOS0yIDItMmgyOGMxLjEgMCAyIDAuOSAyIDJ6IiBmaWxsPSIjZmZmIi8+Cgk8L2c+PGc+CgkJPHBvbHlnb24gY2xhc3M9InN0NCIgcG9pbnRzPSIyMyA0OCAyMyA0OCAzMiA0MCA0MSA0OCIvPgoJPC9nPgoKPC9zdmc+Cg==";
3
- },{}],"wPYj":[function(require,module,exports) {
4
- "use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function o(t,e,o){return e&&n(t.prototype,e),o&&n(t,o),t}function r(e,n){return!n||"object"!==t(n)&&"function"!=typeof n?i(e):n}function i(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&f(t,e)}function l(t){var e="function"==typeof Map?new Map:void 0;return(l=function(t){if(null===t||!c(t))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,n)}function n(){return u(t,arguments,h(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,t)})(t)}function s(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}function u(t,e,n){return(u=s()?Reflect.construct:function(t,e,n){var o=[null];o.push.apply(o,e);var r=new(Function.bind.apply(t,o));return n&&f(r,n.prototype),r}).apply(null,arguments)}function c(t){return-1!==Function.toString.call(t).indexOf("[native code]")}function f(t,e){return(f=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(t){return(h=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var d=require("../../assets/hourglass.svg"),y=function(t){function n(){var t;return e(this,n),(t=r(this,h(n).call(this))).loading=!1,t.attachShadow({mode:"open"}),t}return a(n,l(HTMLElement)),o(n,[{key:"connectedCallback",value:function(){this.shadowRoot.appendChild(this.template.content.cloneNode(!0)),this.overlay=this.shadowRoot.querySelector("#overlay"),this.loadingOverlay=this.shadowRoot.querySelector("#loader");var t=this.querySelector("a"),e=this.querySelector("img");t?(this.fullImage=t.getAttribute("href"),this._addListeners(t)):e&&(this.fullImage=e.getAttribute("src"),e.tabIndex=0,this._addListeners(e))}},{key:"_addListeners",value:function(t){var e=this;t.addEventListener("click",this.showLightbox.bind(this)),t.addEventListener("keydown",function(t){if(!t.altKey)switch(t.keyCode){case 13:case 32:e.showLightbox();default:return}})}},{key:"showLightbox",value:function(t){var e=this;t.preventDefault(),this.loading||(this.loading=!0,this._showOverlay(this.loadingOverlay),this.img?this.showImage():(this.img=document.createElement("img"),this.img.addEventListener("load",function(){return e.showImage()}),this.img.src=this.fullImage,this.img.tabIndex=1,["click","keydown"].forEach(function(t){return e.overlay.addEventListener(t,function(t){return e._hideOverlay(t.currentTarget)})}),this.overlay.appendChild(this.img)))}},{key:"showImage",value:function(){this.img.style.transform="scale(0.1)",this._hideOverlay(this.loadingOverlay),this._showOverlay(this.overlay),this.overlay.focus(),this.img.style.transform="scale(1)",this.loading=!1}},{key:"_showOverlay",value:function(t){t.style.display="flex"}},{key:"_hideOverlay",value:function(t){t.style.display=""}}]),n}(),p=document.createElement("template");p.innerHTML='\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id="overlay" tabindex="0"></div>\n<div id="loader">\n <img src="'.concat(d,'">\n</div>\n'),y.prototype.template=p;var g=y;exports.default=g;
5
- },{"../../assets/hourglass.svg":"q71P"}]},{},["wPYj"], "ImgLightbox")
6
- //# sourceMappingURL=img-lightbox.js.map
1
+
2
+ function $parcel$interopDefault(a) {
3
+ return a && a.__esModule ? a.default : a;
4
+ }
5
+
6
+ function $parcel$defineInteropFlag(a) {
7
+ Object.defineProperty(a, '__esModule', {value: true, configurable: true});
8
+ }
9
+
10
+ function $parcel$export(e, n, v, s) {
11
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
12
+ }
13
+
14
+ $parcel$defineInteropFlag(module.exports);
15
+
16
+ $parcel$export(module.exports, "default", () => $a6ba83244539002c$export$2e2bcd8739ae039);
17
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
18
+ var $735957c3b581425f$exports = {};
19
+ $735957c3b581425f$exports = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" enable-background=\"new 0 0 64 64\" version=\"1.1\" viewBox=\"0 0 64 64\" xml:space=\"preserve\"><metadata><rdf:RDF><cc:Work rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/><dc:title/></cc:Work></rdf:RDF></metadata>\n<g>\n\t\t<circle class=\"st0\" cx=\"32\" cy=\"32\" r=\"32\"/>\n\t</g><g class=\"st1\" opacity=\".2\">\n\t\t<path class=\"st2\" d=\"m46 50h-2v-4c0-4.5-3-7.4-3-7.4s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v4h-2c-1.1 0-2 0.9-2 2s0.9 2 2 2h28c1.1 0 2-0.9 2-2s-0.9-2-2-2z\" fill=\"#231f20\"/>\n\t</g>\n\t\t<path class=\"st3\" d=\"m41 36.6s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v5.1h24v-5.1c0-4.5-3-7.4-3-7.4z\" fill=\"#fff\"/>\n\t\n\t\t<path class=\"st4\" d=\"m31 43v-11c0-2.1-1-3.4-1.3-3.7l-4.2-4c-1.5-1.4-1.5-3.7-1.5-3.7h16s0 2.3-1.5 3.7l-4.2 4c-0.4 0.3-1.3 1.6-1.3 3.7v11z\"/>\n\t<g class=\"st5\" opacity=\".3\">\n\t\t<path class=\"st2\" d=\"m48 16c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#231f20\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 14c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 50c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g>\n\t\t<polygon class=\"st4\" points=\"23 48 23 48 32 40 41 48\"/>\n\t</g>\n\n</svg>";
20
+
21
+
22
+ class $a6ba83244539002c$var$ImgLightbox extends HTMLElement {
23
+ constructor(){
24
+ super();
25
+ this.loading = false;
26
+ this.attachShadow({
27
+ mode: 'open'
28
+ });
29
+ }
30
+ connectedCallback() {
31
+ // Template is added to prototype below the
32
+ // class definition.
33
+ // It's from a template tag because it's
34
+ // supposed to be faster this way.
35
+ this.shadowRoot.appendChild(this.template.content.cloneNode(true));
36
+ // Get some element references from shadow DOM:
37
+ this.overlay = this.shadowRoot.querySelector('#overlay');
38
+ this.loadingOverlay = this.shadowRoot.querySelector('#loader');
39
+ // Add the loading SVG to that element:
40
+ this.loadingOverlay.innerHTML = (0, (/*@__PURE__*/$parcel$interopDefault($735957c3b581425f$exports)));
41
+ // Component needs a tabIndex to be focusable.
42
+ this.tabIndex = 0;
43
+ // The slotted elements are actually not in
44
+ // the shadow DOM so we can get them like so:
45
+ const link = this.querySelector('a');
46
+ const img = this.querySelector('img');
47
+ if (link) {
48
+ // Store the URL as the full image URL:
49
+ this.fullImage = link.getAttribute('href');
50
+ // Register a click event that has to
51
+ // prevent default:
52
+ //this._addListeners(link);
53
+ // Prevent ability to focus the link:
54
+ link.tabIndex = -1;
55
+ } else if (img) this.fullImage = img.getAttribute('src');
56
+ this.fullImage && this._addListeners();
57
+ }
58
+ _addListeners() {
59
+ this.addEventListener('click', this.showLightbox.bind(this), true);
60
+ this.addEventListener('keydown', (e)=>{
61
+ // It's common to ignore anything with alt
62
+ // modifiers. I've copied this from Google
63
+ // people.
64
+ if (e.altKey) return;
65
+ // Catch enter and space:
66
+ switch(e.keyCode){
67
+ case 13:
68
+ case 32:
69
+ this.showLightbox(e);
70
+ default:
71
+ return;
72
+ }
73
+ }, true);
74
+ }
75
+ showLightbox(e) {
76
+ // This is required so that the link element does not get
77
+ // followed:
78
+ e.preventDefault();
79
+ // Implement some kind of lock:
80
+ if (!this.loading) {
81
+ this.loading = true;
82
+ // Preload the full image.
83
+ // Show the spinner overlay:
84
+ this._showOverlay(this.loadingOverlay);
85
+ if (!this.img) {
86
+ this.img = document.createElement('img');
87
+ this.img.addEventListener('load', ()=>this.showImage());
88
+ this.img.src = this.fullImage;
89
+ this.img.tabIndex = 1;
90
+ // Prepare the events to close the overlay.
91
+ // I'm doing this here to light up what's
92
+ // happening in connectedCallback.
93
+ // I'm not doing a check for which key was
94
+ // called on purpose, but maybe I should do
95
+ // that alt key check?
96
+ [
97
+ 'click',
98
+ 'keydown'
99
+ ].forEach((type)=>this.overlay.addEventListener(type, (e)=>this._hideOverlay(e.currentTarget)));
100
+ this.overlay.appendChild(this.img);
101
+ } else this.showImage();
102
+ }
103
+ }
104
+ showImage() {
105
+ this.img.style.transform = 'scale(0.1)';
106
+ // Hide the loading overlay:
107
+ this._hideOverlay(this.loadingOverlay);
108
+ this._showOverlay(this.overlay);
109
+ // Focus the overlay (requires it to have a tabIndex):
110
+ this.overlay.focus();
111
+ // Start the CSS transition:
112
+ this.img.style.transform = 'scale(1)';
113
+ // Don't forget to unlock the click event:
114
+ this.loading = false;
115
+ }
116
+ _showOverlay(overlay) {
117
+ overlay.style.display = 'flex';
118
+ }
119
+ _hideOverlay(overlay) {
120
+ overlay.style.display = '';
121
+ }
122
+ }
123
+ // I'm using a true template tag because the Chrome
124
+ // team says it's faster. The template tag has
125
+ // better browser support than web components anyway.
126
+ // The strange comment here is needed for syntax
127
+ // highlighting with a VS Code extension I'm using.
128
+ const $a6ba83244539002c$var$tpl = document.createElement('template');
129
+ $a6ba83244539002c$var$tpl.innerHTML = /*template*/ `
130
+ <style>
131
+ :host {
132
+ display: inline-block;
133
+ cursor: pointer;
134
+ position: relative;
135
+ }
136
+
137
+ :host([hidden]) {
138
+ display: none;
139
+ }
140
+
141
+ :host(:focus), :host(:active) {
142
+ outline: 2px solid #77b;
143
+ }
144
+
145
+ #loader {
146
+ position: absolute;
147
+ z-index: 1;
148
+ top: 0;
149
+ left: 0;
150
+ width: 100%;
151
+ height: 100%;
152
+ background-color: rgba(0,0,0,.2);
153
+ display: none;
154
+ align-items: center;
155
+ justify-content: center;
156
+ }
157
+
158
+ #overlay {
159
+ position: fixed;
160
+ top: 0;
161
+ left: 0;
162
+ bottom: 0;
163
+ right: 0;
164
+ overflow: hidden;
165
+ z-index: 999;
166
+ background-color: rgba(0,0,0,.5);
167
+ display: none;
168
+ align-items: center;
169
+ justify-content: center;
170
+ }
171
+
172
+ #loader img {
173
+ width: 50%;
174
+ opacity: 0.6;
175
+ animation: lightbox-loader 2s infinite;
176
+ }
177
+
178
+ #overlay img {
179
+ max-width: 100%;
180
+ max-height: 100%;
181
+ transition: transform 0.8s;
182
+ }
183
+
184
+ @keyframes lightbox-loader {
185
+ 0% {transform: rotate(0deg);}
186
+ 100% {transform: rotate(360deg);}
187
+ }
188
+ </style>
189
+ <slot></slot>
190
+ <div id="overlay" tabindex="0"></div>
191
+ <div id="loader">
192
+ </div>
193
+ `;
194
+ $a6ba83244539002c$var$ImgLightbox.prototype.template = $a6ba83244539002c$var$tpl;
195
+ var $a6ba83244539002c$export$2e2bcd8739ae039 = $a6ba83244539002c$var$ImgLightbox;
196
+
197
+
198
+ //# sourceMappingURL=img-lightbox.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["img-lightbox.js"],"names":["ImgLightbox","loaderSvgUrl","require","loading","attachShadow","mode","HTMLElement","shadowRoot","appendChild","template","content","cloneNode","overlay","querySelector","loadingOverlay","link","img","fullImage","getAttribute","_addListeners","tabIndex","el","addEventListener","showLightbox","bind","e","altKey","keyCode","preventDefault","_showOverlay","showImage","document","createElement","src","forEach","type","_hideOverlay","currentTarget","style","transform","focus","display","tpl","innerHTML","prototype"],"mappings":"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","file":"img-lightbox.js","sourceRoot":"../src/shadow","sourcesContent":["const loaderSvgUrl = require('../../assets/hourglass.svg');\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({mode: 'open'});\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n this._addListeners(link);\n } else if (img) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n img.tabIndex = 0;\n this._addListeners(img);\n }\n }\n\n _addListeners(el) {\n el.addEventListener('click', this.showLightbox.bind(this));\n el.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox();\n default:\n return;\n }\n });\n }\n\n showLightbox(e) {\n e.preventDefault();\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) => \n this.overlay.addEventListener(\n type, \n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n <img src=\"${loaderSvgUrl}\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;"]}
1
+ {"mappings":"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","sources":["src/shadow/img-lightbox.js","node_modules/@parcel/runtime-js/lib/bundles/runtime-4f432e39aae9d60a.js"],"sourcesContent":["// const loaderSvgUrl = require('../../assets/hourglass.svg');\nimport loaderSvg from 'bundle-text:../../assets/hourglass.svg';\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // Add the loading SVG to that element:\n this.loadingOverlay.innerHTML = loaderSvg;\n // Component needs a tabIndex to be focusable.\n this.tabIndex = 0;\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n //this._addListeners(link);\n // Prevent ability to focus the link:\n link.tabIndex = -1;\n } else if (img) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n //img.tabIndex = 0;\n //this._addListeners(img);\n }\n this.fullImage && this._addListeners();\n }\n\n _addListeners() {\n this.addEventListener('click', this.showLightbox.bind(this), true);\n this.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox(e);\n default:\n return;\n }\n }, true);\n }\n\n showLightbox(e) {\n // This is required so that the link element does not get \n // followed:\n e.preventDefault();\n\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) =>\n this.overlay.addEventListener(\n type,\n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;\n","module.exports = \"1f3d06fcd1df419a\";"],"names":[],"version":3,"file":"img-lightbox.js.map"}
@@ -0,0 +1,187 @@
1
+
2
+ function $parcel$interopDefault(a) {
3
+ return a && a.__esModule ? a.default : a;
4
+ }
5
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
6
+ var $6ba1613a1599b26d$exports = {};
7
+ $6ba1613a1599b26d$exports = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" enable-background=\"new 0 0 64 64\" version=\"1.1\" viewBox=\"0 0 64 64\" xml:space=\"preserve\"><metadata><rdf:RDF><cc:Work rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/><dc:title/></cc:Work></rdf:RDF></metadata>\n<g>\n\t\t<circle class=\"st0\" cx=\"32\" cy=\"32\" r=\"32\"/>\n\t</g><g class=\"st1\" opacity=\".2\">\n\t\t<path class=\"st2\" d=\"m46 50h-2v-4c0-4.5-3-7.4-3-7.4s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v4h-2c-1.1 0-2 0.9-2 2s0.9 2 2 2h28c1.1 0 2-0.9 2-2s-0.9-2-2-2z\" fill=\"#231f20\"/>\n\t</g>\n\t\t<path class=\"st3\" d=\"m41 36.6s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v5.1h24v-5.1c0-4.5-3-7.4-3-7.4z\" fill=\"#fff\"/>\n\t\n\t\t<path class=\"st4\" d=\"m31 43v-11c0-2.1-1-3.4-1.3-3.7l-4.2-4c-1.5-1.4-1.5-3.7-1.5-3.7h16s0 2.3-1.5 3.7l-4.2 4c-0.4 0.3-1.3 1.6-1.3 3.7v11z\"/>\n\t<g class=\"st5\" opacity=\".3\">\n\t\t<path class=\"st2\" d=\"m48 16c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#231f20\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 14c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 50c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g>\n\t\t<polygon class=\"st4\" points=\"23 48 23 48 32 40 41 48\"/>\n\t</g>\n\n</svg>";
8
+
9
+
10
+ class $ef17987508a11d23$var$ImgLightbox extends HTMLElement {
11
+ constructor(){
12
+ super();
13
+ this.loading = false;
14
+ this.attachShadow({
15
+ mode: 'open'
16
+ });
17
+ }
18
+ connectedCallback() {
19
+ // Template is added to prototype below the
20
+ // class definition.
21
+ // It's from a template tag because it's
22
+ // supposed to be faster this way.
23
+ this.shadowRoot.appendChild(this.template.content.cloneNode(true));
24
+ // Get some element references from shadow DOM:
25
+ this.overlay = this.shadowRoot.querySelector('#overlay');
26
+ this.loadingOverlay = this.shadowRoot.querySelector('#loader');
27
+ // Add the loading SVG to that element:
28
+ this.loadingOverlay.innerHTML = (0, (/*@__PURE__*/$parcel$interopDefault($6ba1613a1599b26d$exports)));
29
+ // Component needs a tabIndex to be focusable.
30
+ this.tabIndex = 0;
31
+ // The slotted elements are actually not in
32
+ // the shadow DOM so we can get them like so:
33
+ const link = this.querySelector('a');
34
+ const img = this.querySelector('img');
35
+ if (link) {
36
+ // Store the URL as the full image URL:
37
+ this.fullImage = link.getAttribute('href');
38
+ // Register a click event that has to
39
+ // prevent default:
40
+ //this._addListeners(link);
41
+ // Prevent ability to focus the link:
42
+ link.tabIndex = -1;
43
+ } else if (img) this.fullImage = img.getAttribute('src');
44
+ this.fullImage && this._addListeners();
45
+ }
46
+ _addListeners() {
47
+ this.addEventListener('click', this.showLightbox.bind(this), true);
48
+ this.addEventListener('keydown', (e)=>{
49
+ // It's common to ignore anything with alt
50
+ // modifiers. I've copied this from Google
51
+ // people.
52
+ if (e.altKey) return;
53
+ // Catch enter and space:
54
+ switch(e.keyCode){
55
+ case 13:
56
+ case 32:
57
+ this.showLightbox(e);
58
+ default:
59
+ return;
60
+ }
61
+ }, true);
62
+ }
63
+ showLightbox(e) {
64
+ // This is required so that the link element does not get
65
+ // followed:
66
+ e.preventDefault();
67
+ // Implement some kind of lock:
68
+ if (!this.loading) {
69
+ this.loading = true;
70
+ // Preload the full image.
71
+ // Show the spinner overlay:
72
+ this._showOverlay(this.loadingOverlay);
73
+ if (!this.img) {
74
+ this.img = document.createElement('img');
75
+ this.img.addEventListener('load', ()=>this.showImage());
76
+ this.img.src = this.fullImage;
77
+ this.img.tabIndex = 1;
78
+ // Prepare the events to close the overlay.
79
+ // I'm doing this here to light up what's
80
+ // happening in connectedCallback.
81
+ // I'm not doing a check for which key was
82
+ // called on purpose, but maybe I should do
83
+ // that alt key check?
84
+ [
85
+ 'click',
86
+ 'keydown'
87
+ ].forEach((type)=>this.overlay.addEventListener(type, (e)=>this._hideOverlay(e.currentTarget)));
88
+ this.overlay.appendChild(this.img);
89
+ } else this.showImage();
90
+ }
91
+ }
92
+ showImage() {
93
+ this.img.style.transform = 'scale(0.1)';
94
+ // Hide the loading overlay:
95
+ this._hideOverlay(this.loadingOverlay);
96
+ this._showOverlay(this.overlay);
97
+ // Focus the overlay (requires it to have a tabIndex):
98
+ this.overlay.focus();
99
+ // Start the CSS transition:
100
+ this.img.style.transform = 'scale(1)';
101
+ // Don't forget to unlock the click event:
102
+ this.loading = false;
103
+ }
104
+ _showOverlay(overlay) {
105
+ overlay.style.display = 'flex';
106
+ }
107
+ _hideOverlay(overlay) {
108
+ overlay.style.display = '';
109
+ }
110
+ }
111
+ // I'm using a true template tag because the Chrome
112
+ // team says it's faster. The template tag has
113
+ // better browser support than web components anyway.
114
+ // The strange comment here is needed for syntax
115
+ // highlighting with a VS Code extension I'm using.
116
+ const $ef17987508a11d23$var$tpl = document.createElement('template');
117
+ $ef17987508a11d23$var$tpl.innerHTML = /*template*/ `
118
+ <style>
119
+ :host {
120
+ display: inline-block;
121
+ cursor: pointer;
122
+ position: relative;
123
+ }
124
+
125
+ :host([hidden]) {
126
+ display: none;
127
+ }
128
+
129
+ :host(:focus), :host(:active) {
130
+ outline: 2px solid #77b;
131
+ }
132
+
133
+ #loader {
134
+ position: absolute;
135
+ z-index: 1;
136
+ top: 0;
137
+ left: 0;
138
+ width: 100%;
139
+ height: 100%;
140
+ background-color: rgba(0,0,0,.2);
141
+ display: none;
142
+ align-items: center;
143
+ justify-content: center;
144
+ }
145
+
146
+ #overlay {
147
+ position: fixed;
148
+ top: 0;
149
+ left: 0;
150
+ bottom: 0;
151
+ right: 0;
152
+ overflow: hidden;
153
+ z-index: 999;
154
+ background-color: rgba(0,0,0,.5);
155
+ display: none;
156
+ align-items: center;
157
+ justify-content: center;
158
+ }
159
+
160
+ #loader img {
161
+ width: 50%;
162
+ opacity: 0.6;
163
+ animation: lightbox-loader 2s infinite;
164
+ }
165
+
166
+ #overlay img {
167
+ max-width: 100%;
168
+ max-height: 100%;
169
+ transition: transform 0.8s;
170
+ }
171
+
172
+ @keyframes lightbox-loader {
173
+ 0% {transform: rotate(0deg);}
174
+ 100% {transform: rotate(360deg);}
175
+ }
176
+ </style>
177
+ <slot></slot>
178
+ <div id="overlay" tabindex="0"></div>
179
+ <div id="loader">
180
+ </div>
181
+ `;
182
+ $ef17987508a11d23$var$ImgLightbox.prototype.template = $ef17987508a11d23$var$tpl;
183
+ var $ef17987508a11d23$export$2e2bcd8739ae039 = $ef17987508a11d23$var$ImgLightbox;
184
+
185
+
186
+ export {$ef17987508a11d23$export$2e2bcd8739ae039 as default};
187
+ //# sourceMappingURL=img-lightbox.mjs.map
@@ -0,0 +1 @@
1
+ {"mappings":";;;;AAAA,8DAA8D;;ACA9D,4BAAiB;;;ADGjB,MAAM,0CAAoB;IAExB,aAAc;QACZ,KAAK;QACL,IAAI,CAAC,OAAO,GAAG;QACf,IAAI,CAAC,YAAY,CAAC;YAAE,MAAM;QAAO;IACnC;IAEA,oBAAoB;QAClB,4CAA4C;QAC5C,oBAAoB;QACpB,yCAAyC;QACzC,kCAAkC;QAClC,IAAI,CAAC,UAAU,CAAC,WAAW,CACzB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;QAElC,+CAA+C;QAC/C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAC7C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QACpD,uCAAuC;QACvC,IAAI,CAAC,cAAc,CAAC,SAAS,GAAG,CAAA,GAAA,gEAAQ;QACxC,8CAA8C;QAC9C,IAAI,CAAC,QAAQ,GAAG;QAChB,4CAA4C;QAC5C,6CAA6C;QAC7C,MAAM,OAAO,IAAI,CAAC,aAAa,CAAC;QAChC,MAAM,MAAM,IAAI,CAAC,aAAa,CAAC;QAC/B,IAAI,MAAM;YACR,uCAAuC;YACvC,IAAI,CAAC,SAAS,GAAG,KAAK,YAAY,CAAC;YACnC,sCAAsC;YACtC,mBAAmB;YACnB,2BAA2B;YAC3B,qCAAqC;YACrC,KAAK,QAAQ,GAAG;QAClB,OAAO,IAAI,KACT,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC;QAOpC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa;IACtC;IAEA,gBAAgB;QACd,IAAI,CAAC,gBAAgB,CAAC,SAAS,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG;QAC7D,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC;YAChC,0CAA0C;YAC1C,0CAA0C;YAC1C,UAAU;YACV,IAAI,EAAE,MAAM,EAAE;YACd,yBAAyB;YACzB,OAAQ,EAAE,OAAO;gBACf,KAAK;gBACL,KAAK;oBACH,IAAI,CAAC,YAAY,CAAC;gBACpB;oBACE;YACJ;QACF,GAAG;IACL;IAEA,aAAa,CAAC,EAAE;QACd,0DAA0D;QAC1D,YAAY;QACZ,EAAE,cAAc;QAEhB,+BAA+B;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACjB,IAAI,CAAC,OAAO,GAAG;YACf,0BAA0B;YAC1B,4BAA4B;YAC5B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc;YACrC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACb,IAAI,CAAC,GAAG,GAAG,SAAS,aAAa,CAAC;gBAClC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,QAAQ,IAAM,IAAI,CAAC,SAAS;gBACtD,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS;gBAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG;gBACpB,2CAA2C;gBAC3C,yCAAyC;gBACzC,kCAAkC;gBAClC,0CAA0C;gBAC1C,2CAA2C;gBAC3C,sBAAsB;gBACtB;oBAAC;oBAAS;iBAAU,CAAC,OAAO,CAC1B,CAAC,OACC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAC3B,MACA,CAAC,IAAM,IAAI,CAAC,YAAY,CAAC,EAAE,aAAa;gBAG9C,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG;YACnC,OACE,IAAI,CAAC,SAAS;QAElB;IACF;IAEA,YAAY;QACV,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG;QAC3B,4BAA4B;QAC5B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO;QAC9B,sDAAsD;QACtD,IAAI,CAAC,OAAO,CAAC,KAAK;QAClB,4BAA4B;QAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG;QAC3B,0CAA0C;QAC1C,IAAI,CAAC,OAAO,GAAG;IACjB;IAEA,aAAa,OAAO,EAAE;QACpB,QAAQ,KAAK,CAAC,OAAO,GAAG;IAC1B;IAEA,aAAa,OAAO,EAAE;QACpB,QAAQ,KAAK,CAAC,OAAO,GAAG;IAC1B;AAEF;AAEA,mDAAmD;AACnD,+CAA+C;AAC/C,qDAAqD;AACrD,gDAAgD;AAChD,mDAAmD;AACnD,MAAM,4BAAM,SAAS,aAAa,CAAC;AACnC,0BAAI,SAAS,GAAG,UAAU,GAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgE7B,CAAC;AACD,kCAAY,SAAS,CAAC,QAAQ,GAAG;IAEjC,2CAAe","sources":["src/shadow/img-lightbox.js","node_modules/@parcel/runtime-js/lib/bundles/runtime-7833d3a46095a7f4.js"],"sourcesContent":["// const loaderSvgUrl = require('../../assets/hourglass.svg');\nimport loaderSvg from 'bundle-text:../../assets/hourglass.svg';\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // Add the loading SVG to that element:\n this.loadingOverlay.innerHTML = loaderSvg;\n // Component needs a tabIndex to be focusable.\n this.tabIndex = 0;\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n //this._addListeners(link);\n // Prevent ability to focus the link:\n link.tabIndex = -1;\n } else if (img) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n //img.tabIndex = 0;\n //this._addListeners(img);\n }\n this.fullImage && this._addListeners();\n }\n\n _addListeners() {\n this.addEventListener('click', this.showLightbox.bind(this), true);\n this.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox(e);\n default:\n return;\n }\n }, true);\n }\n\n showLightbox(e) {\n // This is required so that the link element does not get \n // followed:\n e.preventDefault();\n\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) =>\n this.overlay.addEventListener(\n type,\n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;\n","module.exports = \"0470ae78683fa4f4\";"],"names":[],"version":3,"file":"img-lightbox.mjs.map"}
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@dkvz/img-lightbox",
3
- "version": "0.1.1",
3
+ "version": "1.0.0",
4
4
  "description": "Web component to add a lightbox effect to img elements",
5
5
  "main": "dist/img-lightbox.js",
6
+ "module": "dist/img-lightbox.mjs",
7
+ "source": "src/shadow/img-lightbox.js",
6
8
  "scripts": {
7
9
  "start": "parcel src/shadow/index.pug",
8
- "build": "parcel build src/shadow/img-lightbox.js --public-url ./ --global ImgLightbox",
10
+ "build": "rimraf dist && parcel build",
9
11
  "start-no-shadow": "parcel src/no-shadow/index.pug",
10
- "build-no-shadow": "parcel build src/no-shadow/img-lightbox.js --public-url ./ --global ImgLightbox"
12
+ "build-no-shadow": "parcel build src/no-shadow/img-lightbox.js --public-url ./"
11
13
  },
12
14
  "repository": {
13
15
  "type": "git",
@@ -16,9 +18,10 @@
16
18
  "author": "dkvz",
17
19
  "license": "MIT",
18
20
  "devDependencies": {
19
- "parcel-bundler": "^1.12.4",
20
- "parcel-plugin-clean-dist": "0.0.6",
21
- "parcel-plugin-url-loader": "^1.3.1",
22
- "pug": "^2.0.4"
21
+ "@parcel/transformer-inline-string": "^2.15.4",
22
+ "@parcel/transformer-pug": "^2.15.4",
23
+ "parcel": "^2.15.4",
24
+ "pug": "^2.0.4",
25
+ "rimraf": "^6.0.1"
23
26
  }
24
27
  }
@@ -1,11 +1,12 @@
1
- const loaderSvgUrl = require('../../assets/hourglass.svg');
1
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
2
+ import loaderSvg from 'bundle-text:../../assets/hourglass.svg';
2
3
 
3
4
  class ImgLightbox extends HTMLElement {
4
5
 
5
6
  constructor() {
6
7
  super();
7
8
  this.loading = false;
8
- this.attachShadow({mode: 'open'});
9
+ this.attachShadow({ mode: 'open' });
9
10
  }
10
11
 
11
12
  connectedCallback() {
@@ -19,6 +20,10 @@ class ImgLightbox extends HTMLElement {
19
20
  // Get some element references from shadow DOM:
20
21
  this.overlay = this.shadowRoot.querySelector('#overlay');
21
22
  this.loadingOverlay = this.shadowRoot.querySelector('#loader');
23
+ // Add the loading SVG to that element:
24
+ this.loadingOverlay.innerHTML = loaderSvg;
25
+ // Component needs a tabIndex to be focusable.
26
+ this.tabIndex = 0;
22
27
  // The slotted elements are actually not in
23
28
  // the shadow DOM so we can get them like so:
24
29
  const link = this.querySelector('a');
@@ -28,20 +33,23 @@ class ImgLightbox extends HTMLElement {
28
33
  this.fullImage = link.getAttribute('href');
29
34
  // Register a click event that has to
30
35
  // prevent default:
31
- this._addListeners(link);
36
+ //this._addListeners(link);
37
+ // Prevent ability to focus the link:
38
+ link.tabIndex = -1;
32
39
  } else if (img) {
33
40
  this.fullImage = img.getAttribute('src');
34
41
  // Nothing wrong with giving the same tabIndex
35
42
  // to things, they're ordered by position.
36
43
  // I think.
37
- img.tabIndex = 0;
38
- this._addListeners(img);
44
+ //img.tabIndex = 0;
45
+ //this._addListeners(img);
39
46
  }
47
+ this.fullImage && this._addListeners();
40
48
  }
41
49
 
42
- _addListeners(el) {
43
- el.addEventListener('click', this.showLightbox.bind(this));
44
- el.addEventListener('keydown', (e) => {
50
+ _addListeners() {
51
+ this.addEventListener('click', this.showLightbox.bind(this), true);
52
+ this.addEventListener('keydown', (e) => {
45
53
  // It's common to ignore anything with alt
46
54
  // modifiers. I've copied this from Google
47
55
  // people.
@@ -50,15 +58,18 @@ class ImgLightbox extends HTMLElement {
50
58
  switch (e.keyCode) {
51
59
  case 13:
52
60
  case 32:
53
- this.showLightbox();
61
+ this.showLightbox(e);
54
62
  default:
55
63
  return;
56
64
  }
57
- });
65
+ }, true);
58
66
  }
59
67
 
60
68
  showLightbox(e) {
69
+ // This is required so that the link element does not get
70
+ // followed:
61
71
  e.preventDefault();
72
+
62
73
  // Implement some kind of lock:
63
74
  if (!this.loading) {
64
75
  this.loading = true;
@@ -77,9 +88,9 @@ class ImgLightbox extends HTMLElement {
77
88
  // called on purpose, but maybe I should do
78
89
  // that alt key check?
79
90
  ['click', 'keydown'].forEach(
80
- (type) =>
91
+ (type) =>
81
92
  this.overlay.addEventListener(
82
- type,
93
+ type,
83
94
  (e) => this._hideOverlay(e.currentTarget)
84
95
  )
85
96
  );
@@ -127,6 +138,14 @@ tpl.innerHTML = /*template*/`
127
138
  position: relative;
128
139
  }
129
140
 
141
+ :host([hidden]) {
142
+ display: none;
143
+ }
144
+
145
+ :host(:focus), :host(:active) {
146
+ outline: 2px solid #77b;
147
+ }
148
+
130
149
  #loader {
131
150
  position: absolute;
132
151
  z-index: 1;
@@ -174,9 +193,8 @@ tpl.innerHTML = /*template*/`
174
193
  <slot></slot>
175
194
  <div id="overlay" tabindex="0"></div>
176
195
  <div id="loader">
177
- <img src="${loaderSvgUrl}">
178
196
  </div>
179
197
  `;
180
198
  ImgLightbox.prototype.template = tpl;
181
199
 
182
- export default ImgLightbox;
200
+ export default ImgLightbox;
@@ -15,8 +15,20 @@ html
15
15
 
16
16
  /* Progressive enhancement & component styles */
17
17
  img-lightbox {
18
+ display: inline-block;
18
19
  border: 1px solid #333;
19
20
  box-shadow: 0px 0px 4px rgba(0,0,0,0.6);
21
+ background-color: #333;
22
+ }
23
+
24
+ /* Both slotted elements should be display: block */
25
+ img-lightbox a, img-lightbox img {
26
+ display: block;
27
+ max-width: 200px;
28
+ }
29
+
30
+ img-lightbox:active, img-lightbox:focus {
31
+ outline: 2px solid darkblue;
20
32
  }
21
33
 
22
34
  /* Quick hacks to help me debug things */
@@ -2,9 +2,9 @@
2
2
  <p>The image should still show and link to the full version with JS disabled.</p>
3
3
 
4
4
  <img-lightbox>
5
- <a href="../../assets/example.png" target="_blank" rel="noopener noreferrer">
6
- <img src="../../assets/example_preview.png"
7
- alt="Rabbit with a trumpet mute on its head">
5
+ <a href="../../assets/example.jpg" target="_blank" rel="noopener noreferrer">
6
+ <img src="../../assets/example_preview.jpg"
7
+ alt="Some cute cat">
8
8
  </a>
9
9
  </img-lightbox>
10
10
 
@@ -14,4 +14,4 @@
14
14
 
15
15
  </div>
16
16
 
17
- <script src="./example.js"></script>
17
+ <script type="module" src="./example.js"></script>
@@ -1,140 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
-
4
- <svg
5
- xmlns:dc="http://purl.org/dc/elements/1.1/"
6
- xmlns:cc="http://creativecommons.org/ns#"
7
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
- xmlns:svg="http://www.w3.org/2000/svg"
9
- xmlns="http://www.w3.org/2000/svg"
10
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
- version="1.1"
13
- x="0px"
14
- y="0px"
15
- viewBox="0 0 64 64"
16
- style="enable-background:new 0 0 64 64;"
17
- xml:space="preserve"
18
- id="svg38"
19
- sodipodi:docname="Circle-icons-hourglass.svg"
20
- inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
21
- id="metadata44"><rdf:RDF><cc:Work
22
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
23
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
24
- id="defs42">
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
- </defs><sodipodi:namedview
34
- pagecolor="#ffffff"
35
- bordercolor="#666666"
36
- borderopacity="1"
37
- objecttolerance="10"
38
- gridtolerance="10"
39
- guidetolerance="10"
40
- inkscape:pageopacity="0"
41
- inkscape:pageshadow="2"
42
- inkscape:window-width="1680"
43
- inkscape:window-height="987"
44
- id="namedview40"
45
- showgrid="false"
46
- inkscape:zoom="7.375"
47
- inkscape:cx="2.9605891"
48
- inkscape:cy="39.918967"
49
- inkscape:window-x="892"
50
- inkscape:window-y="-8"
51
- inkscape:window-maximized="1"
52
- inkscape:current-layer="svg38" />
53
- <style
54
- type="text/css"
55
- id="style2">
56
- .st0{fill:#C75C5C;}
57
- .st1{opacity:0.2;}
58
- .st2{fill:#231F20;}
59
- .st3{fill:#FFFFFF;}
60
- .st4{fill:#4F5D73;}
61
- .st5{opacity:0.3;}
62
- .st6{fill:#F5CF87;}
63
- </style>
64
- <g
65
- id="g6"
66
- style="fill:#000000">
67
- <circle
68
- style="fill:#000000"
69
- id="circle4"
70
- r="32"
71
- cy="32"
72
- cx="32"
73
- class="st0" />
74
- </g><g
75
- style="opacity:0.2"
76
- id="g10"
77
- class="st1">
78
- <path
79
- style="fill:#231f20"
80
- inkscape:connector-curvature="0"
81
- id="path8"
82
- d="m 46,50 h -2 c 0,-0.7 0,-2 0,-4 0,-4.5 -3,-7.4 -3,-7.4 0,0 -3,-2.8 -3.9,-3.7 -0.9,-0.9 0,-1.8 0,-1.8 0,0 1.3,-1.3 4.2,-4 2.8,-2.7 2.7,-6.7 2.7,-6.7 v -5.1 l -12,-1 -12,1 v 5.1 c 0,0 -0.1,3.9 2.7,6.7 2.8,2.7 4.2,4 4.2,4 0,0 0.9,0.9 0,1.8 -0.9,0.9 -3.9,3.7 -3.9,3.7 0,0 -3,2.8 -3,7.4 0,2 0,3.3 0,4 h -2 c -1.1,0 -2,0.9 -2,2 0,1.1 0.9,2 2,2 h 28 c 1.1,0 2,-0.9 2,-2 0,-1.1 -0.9,-2 -2,-2 z"
83
- class="st2" />
84
- </g><g
85
- id="g14">
86
- <path
87
- style="fill:#ffffff"
88
- inkscape:connector-curvature="0"
89
- id="path12"
90
- d="m 41,36.6 c 0,0 -3,-2.8 -3.9,-3.7 -0.9,-0.9 0,-1.8 0,-1.8 0,0 1.3,-1.3 4.2,-4 2.8,-2.7 2.7,-6.7 2.7,-6.7 v -5.1 l -12,-1 -12,1 v 5.1 c 0,0 -0.1,3.9 2.7,6.7 2.8,2.7 4.2,4 4.2,4 0,0 0.9,0.9 0,1.8 -0.9,0.9 -3.9,3.7 -3.9,3.7 0,0 -3,2.8 -3,7.4 0,4.5 0,5.1 0,5.1 h 12 12 c 0,0 0,-0.5 0,-5.1 0,-4.5 -3,-7.4 -3,-7.4 z"
91
- class="st3" />
92
- </g><g
93
- id="g18">
94
- <path
95
- style="fill:#000000"
96
- inkscape:connector-curvature="0"
97
- id="path16"
98
- d="M 31,43 V 32 c 0,-2.1 -1,-3.4 -1.3,-3.7 l -4.2,-4 C 24,22.9 24,20.6 24,20.6 h 8 8 c 0,0 0,0 0,0 0,0 0,2.3 -1.5,3.7 l -4.2,4 C 33.9,28.6 33,29.9 33,32 v 11 z"
99
- class="st4" />
100
- </g><g
101
- style="opacity:0.3"
102
- id="g22"
103
- class="st5">
104
- <path
105
- style="fill:#231f20"
106
- inkscape:connector-curvature="0"
107
- id="path20"
108
- d="m 48,16 c 0,1.1 -0.9,2 -2,2 H 18 c -1.1,0 -2,-0.9 -2,-2 v 0 c 0,-1.1 0.9,-2 2,-2 h 28 c 1.1,0 2,0.9 2,2 z"
109
- class="st2" />
110
- </g><g
111
- id="g26"
112
- style="fill:#ffffff">
113
- <path
114
- style="fill:#ffffff"
115
- inkscape:connector-curvature="0"
116
- id="path24"
117
- d="m 48,14 c 0,1.1 -0.9,2 -2,2 H 18 c -1.1,0 -2,-0.9 -2,-2 v 0 c 0,-1.1 0.9,-2 2,-2 h 28 c 1.1,0 2,0.9 2,2 z"
118
- class="st6" />
119
- </g><g
120
- id="g30"
121
- style="fill:#ffffff">
122
- <path
123
- style="fill:#ffffff"
124
- inkscape:connector-curvature="0"
125
- id="path28"
126
- d="m 48,50 c 0,1.1 -0.9,2 -2,2 H 18 c -1.1,0 -2,-0.9 -2,-2 v 0 c 0,-1.1 0.9,-2 2,-2 h 28 c 1.1,0 2,0.9 2,2 z"
127
- class="st6" />
128
- </g><g
129
- id="g34"
130
- style="fill:#000000">
131
- <polygon
132
- style="fill:#000000"
133
- id="polygon32"
134
- points="23,48 23,48 32,40 41,48 "
135
- class="st4" />
136
- </g>
137
- <g
138
- id="Layer_2">
139
- </g>
140
- </svg>
Binary file