@massimo-cassandro/minimo 1.17.1 → 1.18.1

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.
Files changed (57) hide show
  1. package/design-tokens/tokens/src/components/unsplash-page/unsplash-page.minimo.tokens.jsonc +3 -3
  2. package/dev-tools/starter-kit/templates/__project__.code-workspace +2 -2
  3. package/dev-tools/starter-kit/webpack-modules/css-rules.mjs +1 -0
  4. package/dev-tools/starter-kit/webpack-modules/postcss.config.mjs +7 -0
  5. package/dev-tools/starter-kit/webpack-modules/purgecss-setup.mjs +95 -0
  6. package/dev-tools/starter-kit/webpack.config.mjs +102 -74
  7. package/index.js +1 -2
  8. package/package.json +9 -1
  9. package/snippets/error-pages/bundles/TwigBundle/Exception/error.html.twig +6 -6
  10. package/snippets/error-pages/error-pages.js +2 -2
  11. package/src/components/dismiss-alerts.js +1 -0
  12. package/src/components/form-reset-submit.js +1 -0
  13. package/src/components/inner-nav/inner-nav.css +2 -0
  14. package/src/components/inner-nav/inner-nav.js +1 -0
  15. package/src/components/modal-alert/modal-alert.js +12 -7
  16. package/src/components/modal-alert/modal-alert.module.css +11 -8
  17. package/src/components/modal-popup/modal-popup.js +1 -0
  18. package/src/components/modal-popup/modal-popup.module.css +1 -0
  19. package/src/components/overlay/overlay.css +2 -0
  20. package/src/components/overlay/overlay.js +1 -0
  21. package/src/components/sf-macro/sf-macro.js +1 -0
  22. package/src/components/slide-up-down-toggle/slide-up-down-toggle.js +1 -0
  23. package/src/components/slide-up-down-toggle/slide-up-down-toggle.module.css +1 -0
  24. package/src/components/snackbar/snackbar.js +1 -0
  25. package/src/components/snackbar/snackbar.module.css +2 -0
  26. package/src/components/unsplash-page/README.md +23 -0
  27. package/src/components/unsplash-page/unsplash-page.js +249 -119
  28. package/src/components/unsplash-page/unsplash-page.minimo.tokens.mjs +3 -3
  29. package/src/components/unsplash-page/unsplash-page.module.css +79 -77
  30. package/src/custom-properties.css +23 -23
  31. package/src/utilities/better-text.js +1 -0
  32. package/src/utilities/build-picture-tag.js +1 -0
  33. package/src/utilities/classnames.js +1 -0
  34. package/src/utilities/cookies.js +1 -0
  35. package/src/utilities/create-id.js +1 -0
  36. package/src/utilities/disable-btns-on-submit.js +1 -0
  37. package/src/utilities/dom-builder/dom-builder.js +2 -1
  38. package/src/utilities/enable-submit-btns.js +1 -0
  39. package/src/utilities/escape-html.js +1 -0
  40. package/src/utilities/generate-pwd.js +1 -0
  41. package/src/utilities/linked-dates.js +1 -0
  42. package/src/utilities/parse-file-size.js +1 -0
  43. package/src/utilities/random-id.js +1 -0
  44. package/src/utilities/relative-date.js +1 -0
  45. package/src/utilities/sentence-case.js +1 -0
  46. package/src/utilities/strip-tags.js +1 -0
  47. package/src/utilities/title-case.js +1 -0
  48. package/src/utilities/truncate-string.js +1 -0
  49. package/src/utilities/validation-error-class.js +1 -0
  50. package/src/components/unsplash-page/TODO unsplash-page-demo/README.md +0 -194
  51. package/src/components/unsplash-page/TODO unsplash-page-demo/changelog.md +0 -5
  52. package/src/components/unsplash-page/TODO unsplash-page-demo/unsplash-page/demo.js +0 -15
  53. package/src/components/unsplash-page/TODO unsplash-page-demo/unsplash-page/rollup.config.mjs +0 -26
  54. package/src/components/unsplash-page/TODO unsplash-page-demo/unsplash-page/unsplash-page-demo.min.js +0 -3
  55. package/src/components/unsplash-page/TODO.md +0 -3
  56. package/src/components/unsplash-page/img-breakpoints.js +0 -66
  57. package/src/components/unsplash-page/unsplash-page-body-reset.css +0 -14
@@ -1,7 +1,10 @@
1
+ /*! minimo - Modal Alert */
2
+
1
3
  .malert {
2
4
  width: 600px;
3
5
  max-width: 90vw;
4
6
  padding: 0;
7
+ margin: auto;
5
8
  background-color: var(--malert-background-color);
6
9
  border: none;
7
10
  border-radius: var(--malert-border-radius);
@@ -19,23 +22,23 @@
19
22
  }
20
23
 
21
24
  .success {
22
- --_malert-color: var(--malert-success-bg);
25
+ --_malert-color-bg: var(--malert-success-bg);
23
26
  --_malert-color-fg: var(--malert-success-fg);
24
27
  }
25
28
  .info {
26
- --_malert-color: var(--malert-info-bg);
29
+ --_malert-color-bg: var(--malert-info-bg);
27
30
  --_malert-color-fg: var(--malert-info-fg);
28
31
  }
29
32
  .warning {
30
- --_malert-color: var(--malert-warning-bg);
33
+ --_malert-color-bg: var(--malert-warning-bg);
31
34
  --_malert-color-fg: var(--malert-warning-fg);
32
35
  }
33
36
  .error {
34
- --_malert-color: var(--malert-error-bg);
37
+ --_malert-color-bg: var(--malert-error-bg);
35
38
  --_malert-color-fg: var(--malert-error-fg);
36
39
  }
37
40
  .confirm {
38
- --_malert-color: var(--malert-confirm-bg);
41
+ --_malert-color-bg: var(--malert-confirm-bg);
39
42
  --_malert-color-fg: var(--malert-confirm-fg);
40
43
  }
41
44
 
@@ -55,7 +58,6 @@
55
58
 
56
59
  .mMark {
57
60
  display: flex;
58
- flex: 0;
59
61
  align-items: center;
60
62
  justify-content: center;
61
63
  width: 100%;
@@ -65,6 +67,7 @@
65
67
  svg {
66
68
  width: 100px;
67
69
  aspect-ratio: 1;
70
+ background-color: transparent;
68
71
  fill: var(--_malert-color-fg);
69
72
  }
70
73
 
@@ -112,13 +115,13 @@
112
115
  flex-flow: column nowrap;
113
116
  gap: 1rem;
114
117
  align-items: center;
115
- justify-content: flex-start;
118
+ justify-content: flex-end;
116
119
 
117
120
  padding-top: 1rem;
118
121
  margin-top: auto;
119
122
 
120
123
  @media screen and (min-width: 600px) {
121
- flex-direction: row;
124
+ flex-direction: row-reverse;
122
125
  justify-content: space-between;
123
126
  }
124
127
  }
@@ -1,3 +1,4 @@
1
+ /*! minimo - Modal Popup */
1
2
  import { domBuilder } from '../../utilities/dom-builder/dom-builder.js';
2
3
  import { classnames } from '../../utilities/classnames.js';
3
4
  import { spinner } from '../spinner/spinner.js';
@@ -1,3 +1,4 @@
1
+ /*! minimo - Modal Popup */
1
2
  /*
2
3
  NB:
3
4
  `--modal-popup-width` and `--modal-popup-height` are used with a fallback value,
@@ -1,3 +1,5 @@
1
+ /*! minimo - Overlay */
2
+
1
3
  .overlay {
2
4
  position: fixed;
3
5
  inset: 0;
@@ -1,3 +1,4 @@
1
+ /*! minimo - Overlay */
1
2
  import './overlay.css';
2
3
 
3
4
  /**
@@ -1,3 +1,4 @@
1
+ /*! minimo - Symfony Macro */
1
2
  // import './sf-macro.css'; // import in the consuming project
2
3
 
3
4
  /**
@@ -1,4 +1,5 @@
1
1
  // @ts-check
2
+ /*! minimo - Slide Up/Down Toggle */
2
3
 
3
4
  import * as styles from './slide-up-down-toggle.module.css';
4
5
 
@@ -1,3 +1,4 @@
1
+ /*! minimo - Slide Up/Down Toggle */
1
2
  /*
2
3
  * CSS Module for slide-up-down-toggle.js
3
4
  *
@@ -1,3 +1,4 @@
1
+ /*! minimo - Snackbar */
1
2
  import { domBuilder } from '../../utilities/dom-builder/dom-builder.js';
2
3
  import { classnames } from '../../utilities/classnames.js';
3
4
  import * as styles from './snackbar.module.css';
@@ -1,3 +1,5 @@
1
+ /*! minimo - Snackbar */
2
+
1
3
  /* purgecss start ignore */
2
4
 
3
5
  .snackbarOuter {
@@ -0,0 +1,23 @@
1
+ # Unsplash page
2
+ Single page with random photo from [Unsplash](https://unsplash.com/) to display some messages (useful for error pages).
3
+
4
+ This component comes from some experiments I did with the Unsplash API. The initial purpose was to display more appealing error pages, but you can use it for any use.
5
+
6
+ For best results, it is advisable to display images from a photo collection prepared on Unsplash. The demos in this repository use my collection ["World"](https://unsplash.com/collections/3660951/world).
7
+
8
+ You need to create a server script to retrieve the JSON data of a random image from Unsplash (see [Get a Random Photo](https://unsplash.com/documentation#get-a-random-photo) on Unsplash API docs).
9
+
10
+ The script also implements [BlurHash](https://blurha.sh/), to show a placeholder of the image until it loads.
11
+
12
+ For more details and examples take a look at:
13
+
14
+ * <https://unsplash.com/developers>
15
+ * [A Random Image Slideshow With Unsplash and React](https://betterprogramming.pub/a-random-image-slideshow-with-unsplash-and-react-1b6aee698652)
16
+ * [Unsplash Random Photo 1](https://github.com/massimo-cassandro/area-test/tree/main/2023-03-unsplash-random-photo-1)
17
+ * [Random Unsplash Photos Slideshow](https://github.com/massimo-cassandro/area-test/tree/main/2023-05-unsplash-random-photo-2)
18
+ * [A Split Image Effect in React](https://medium.com/better-programming/a-split-image-effect-in-react-beb2baa3fe5f) and [split image](https://github.com/massimo-cassandro/area-test/tree/main/2023-07-split-image)
19
+
20
+
21
+ The SVG icons used in the script are from [Phosphor Icon](https://phosphoricons.com/). At the moment it is not possible to use different ones without modifying the source code.
22
+
23
+ The `snippets` directory contains an example of implementing Unsplash Page for an error page system in twig/Symfony
@@ -1,8 +1,12 @@
1
- import imageIcon from '../../icons/image-duotone.svg';
2
- import arrowIcon from '../../icons/arrow-fat-lines-left-duotone.svg';
3
- import { breakpoints } from './img-breakpoints.js';
1
+ /*! minimo - unsplashPage */
2
+ import { domBuilder } from '../../utilities/dom-builder/dom-builder.js';
3
+ import { classnames } from '../../utilities/classnames.js';
4
+
4
5
  import { fetchUnsplashData } from './fetch-unsplash-data.js';
6
+ import imageIcon from '../../icons/image-duotone.svg?inline';
7
+ import arrowIcon from '../../icons/arrow-fat-lines-left-duotone.svg?inline';
5
8
  import { decode } from 'blurhash';
9
+ import * as styles from './unsplash-page.module.css';
6
10
 
7
11
  /**
8
12
  * Initialises an Unsplash full-page photo with blurhash placeholder, responsive picture element,
@@ -16,10 +20,11 @@ import { decode } from 'blurhash';
16
20
  * @param {string | null} [settings.text=null] - Optional body text.
17
21
  * @param {string | null} [settings.backLink=null] - Optional back-link HTML.
18
22
  * @param {boolean} [settings.hidePhotoLink=true] - When true, the Unsplash link is shown only on hover.
19
- * @param {Record<string, string> | null} [settings.cssModulesObj=null] - CSS Modules class map; when null, class names are used as-is.
20
- * @returns {void}
23
+ * @returns {Promise<void>}
21
24
  */
22
- export function unsplashPageJS(settings) {
25
+
26
+
27
+ export async function unsplashPage(settings) {
23
28
 
24
29
  const default_settings = {
25
30
  targetElement : null,
@@ -49,122 +54,247 @@ export function unsplashPageJS(settings) {
49
54
 
50
55
  const targetElement = /** @type {HTMLElement} */ (settings.targetElement);
51
56
 
52
- const cssClass = /** @param {string} classname */ classname =>
53
- settings.cssModulesObj? settings.cssModulesObj[classname] : classname;
54
-
55
- targetElement.innerHTML = `<div class="${cssClass('upContainer') + (settings.className? ` ${settings.className}` : '')}"></div>`;
56
- const container = /** @type {HTMLElement} */ (targetElement.querySelector('.' + cssClass('upContainer')));
57
- container.innerHTML = `<div class="${cssClass('upLoaderWrapper')}"><div class="${cssClass('upLoader')}"></div></div>`;
58
-
59
- fetchUnsplashData({unsplash_data_url: settings.unsplashDataUrl})
60
- .then(photo => {
61
- if (!photo) return;
62
-
63
- const pixels = decode(photo.blur_hash, container.offsetWidth, container.offsetHeight);
64
-
65
- const canvas = document.createElement('canvas');
66
- canvas.className = cssClass('upCanvas');
67
- canvas.width = container.offsetWidth;
68
- canvas.height = container.offsetHeight;
69
- const ctx = canvas.getContext('2d');
70
- if (ctx) {
71
- const imageData = ctx.createImageData(container.offsetWidth, container.offsetHeight);
72
- imageData.data.set(pixels);
73
- ctx.putImageData(imageData, 0, 0);
74
- }
75
-
76
-
77
- container.insertAdjacentElement('afterbegin', canvas);
78
-
79
- const formats = ['avif', 'webp', 'pjpg']; // `fm` parameter, in order of use
80
-
81
- container.insertAdjacentHTML('beforeend',
82
- '<picture>' +
83
- breakpoints.map((brk, idx) => {
84
-
85
- const is_last_brk = idx === breakpoints.length - 1;
86
- return formats.map(fmt => {
87
- const is_default_fmt = fmt === formats.at(-1);
88
-
89
- // https://unsplash.com/documentation#supported-parameters
90
- // https://docs.imgix.com/apis/rendering/size/w
91
- // https://docs.imgix.com/apis/rendering/size/h
92
- // https://docs.imgix.com/apis/rendering/size/ar
93
- // https://docs.imgix.com/apis/rendering/size/fit
94
- // https://docs.imgix.com/apis/rendering/size/crop
95
- // https://docs.imgix.com/apis/rendering/format/q
96
-
97
- let url = photo.base_url + (/\?/.test(photo.base_url)? '&' : '?') +
98
- 'fit=crop&crop=faces,entropy,edges' + // top, bottom, left, right, faces, focalpoint, edges, and entropy
99
- '&q=60' +
100
- `&w=${brk.w}&h=${brk.h}` +
101
- `&fm=${fmt}`;
102
-
103
- if(is_last_brk && is_default_fmt) {
104
-
105
- return '<img ' +
106
- `class="${cssClass('unsplashPhoto')}" `+
107
- `src="${url}" `+
108
- `srcset="${url}${brk.dpr2? ` 1x, ${url}&dpr=2 2x` : ''}" `+
109
- `alt="${photo.alt_description?? `${photo.author} / Unsplash`}" `+
110
- `width="${brk.w}" height="${brk.h}">`;
111
-
112
- } else {
113
- return '<source ' +
114
- `srcset="${url}${brk.dpr2? ` 1x, ${url}&dpr=2 2x` : ''}" `+
115
- (!is_default_fmt? `type="image/${fmt}" ` : '')+
116
- `media="${brk.mq}" `+
117
- `width="${brk.w}" height="${brk.h}">`;
57
+ const container = /** @type {HTMLElement} */ (domBuilder([
58
+ {
59
+ className: classnames( styles.container, settings.className ),
60
+ children: [
61
+ {
62
+ className: styles.loaderWrapper,
63
+ children: [
64
+ `div.${styles.loader}`
65
+ ]
66
+ }
67
+ ]
68
+ }
69
+ ], targetElement));
70
+
71
+
72
+ const imgData = await fetchUnsplashData({unsplash_data_url: settings.unsplashDataUrl});
73
+ if (!imgData) return;
74
+
75
+ const pixels = decode(imgData.blur_hash, container.offsetWidth, container.offsetHeight);
76
+
77
+ const canvas = document.createElement('canvas');
78
+ canvas.className = styles.canvas;
79
+ canvas.width = container.offsetWidth;
80
+ canvas.height = container.offsetHeight;
81
+ const ctx = canvas.getContext('2d');
82
+ if (ctx) {
83
+ const imageData = ctx.createImageData(container.offsetWidth, container.offsetHeight);
84
+ imageData.data.set(pixels);
85
+ ctx.putImageData(imageData, 0, 0);
86
+ }
87
+
88
+ container.insertAdjacentElement('afterbegin', canvas);
89
+
90
+ const formats = ['avif', 'webp', 'pjpg']; // `fm` parameter, in order of use
91
+
92
+ /*
93
+ - image dimensions grouped by aspect ratio: each group becomes one <source> tag
94
+ per format (avif/webp/pjpg)
95
+ - each aspect ratio is expressed as [w, h] (e.g. [16, 9]); `widths` lists the target
96
+ render widths for that group, used both as the `w` imgix param and as the `Nw`
97
+ descriptor in `srcset`. Height is derived per width from the group's ratio and
98
+ passed to imgix as `h` (see buildImgixUrl), so groups can safely reuse the same
99
+ `widths` list (e.g. 9/16 and 9/20) while still requesting a different crop height
100
+ - orientation and the aspect-ratio media feature are derived from the ratio itself:
101
+ ratio >= 1 -> landscape + min-aspect-ratio, ratio < 1 -> portrait + max-aspect-ratio
102
+ - NB: order matters. <picture> uses "first matching <source> wins" (unlike the CSS
103
+ cascade, where the last matching rule wins), so groups must be ordered from most to
104
+ least restrictive: landscape groups from the widest ratio to the narrowest, portrait
105
+ groups from the narrowest ratio to the widest. Orientation makes the two families
106
+ mutually exclusive, so their relative order doesn't matter
107
+ */
108
+ const sizes = [
109
+ // landscape 16/9
110
+ {
111
+ ar: [16,9],
112
+ widths: [2560, 1920, 1440, 1200, 800, 570]
113
+ },
114
+ // landscape 4/3
115
+ {
116
+ ar: [4,3],
117
+ widths: [1536, 1440, 1280, 840, 570]
118
+ },
119
+ // portrait 9/20 (very tall phones)
120
+ {
121
+ ar: [9,20],
122
+ widths: [1080, 960, 768, 570, 400]
123
+ },
124
+ // portrait 9/16
125
+ {
126
+ ar: [9,16],
127
+ widths: [1080, 960, 768, 570, 400]
128
+ },
129
+ // portrait 3/4 (tablets)
130
+ {
131
+ ar: [3,4],
132
+ widths: [1200, 1024, 840]
133
+ }
134
+ ];
135
+
136
+ // `url`/`searchParams` and the static imgix params (fit/crop/q) are set up once here
137
+ // and reused on every call: `fm`/`w`/`h` are the only parts that change per image, and
138
+ // the returned string is always consumed synchronously before the next call mutates them
139
+ /** @type {(w: number, h: number, fmt: string) => string} */
140
+ const buildImgixUrl = (() => {
141
+ const url = new URL(imgData.base_url),
142
+ searchParams = new URLSearchParams(url.search);
143
+
144
+ searchParams.set('fit', 'crop');
145
+ searchParams.set('crop', 'faces,entropy,edges'); // top, bottom, left, right, faces, focalpoint, edges, and entropy
146
+ searchParams.set('q', '60');
147
+
148
+ return (w, h, fmt) => {
149
+ searchParams.set('fm', fmt);
150
+ searchParams.set('w', String(w));
151
+ searchParams.set('h', String(h));
152
+
153
+ url.search = searchParams.toString();
154
+ return url.toString();
155
+ };
156
+ })();
157
+
158
+ // smallest width of the widest (most common) group, used as the plain <img> fallback
159
+ // for browsers without <picture> support: the <source> tags above cover everything else
160
+ const default_group = sizes[0],
161
+ default_w = default_group.widths[default_group.widths.length - 1],
162
+ default_h = Math.round(default_w * default_group.ar[1] / default_group.ar[0]);
163
+
164
+ // https://unsplash.com/documentation#supported-parameters
165
+ // https://docs.imgix.com/apis/rendering/size/w
166
+ // https://docs.imgix.com/apis/rendering/size/h
167
+ // https://docs.imgix.com/apis/rendering/size/ar
168
+ // https://docs.imgix.com/apis/rendering/size/fit
169
+ // https://docs.imgix.com/apis/rendering/size/crop
170
+ // https://docs.imgix.com/apis/rendering/format/q
171
+ domBuilder([
172
+ {
173
+ tag: 'picture',
174
+ children: [
175
+ ...sizes.flatMap(({ar, widths}) => {
176
+ const ratio = ar[0] / ar[1],
177
+ orientation = ratio >= 1 ? 'landscape' : 'portrait',
178
+ aspectFeature = orientation === 'landscape' ? 'min-aspect-ratio' : 'max-aspect-ratio',
179
+ media = `(orientation: ${orientation}) and (${aspectFeature}: ${ar[0]}/${ar[1]})`;
180
+
181
+ return formats.map(fmt => {
182
+ const is_default_fmt = fmt === formats.at(-1),
183
+ srcset = widths
184
+ .map(w => {
185
+ const h = Math.round(w * ar[1] / ar[0]);
186
+ return `${buildImgixUrl(w, h, fmt)} ${w}w`;
187
+ })
188
+ .join(', ');
189
+
190
+ return {
191
+ tag: 'source',
192
+ attrs: {
193
+ type: is_default_fmt? null : `image/${fmt}`,
194
+ media,
195
+ sizes: '100vw',
196
+ srcset
197
+ }
198
+ };
199
+ });
200
+ }),
201
+
202
+ // =>> img and its listener
203
+ {
204
+ tag: 'img',
205
+ className: styles.unsplashPhoto,
206
+ attrs: {
207
+ src: buildImgixUrl(default_w, default_h, formats[formats.length - 1]),
208
+ alt: imgData.alt_description ?? `${imgData.author} / Unsplash`
209
+ },
210
+ callback: el => {
211
+ el.onload = () => {
212
+ try {
213
+ container.querySelector(`.${styles.loaderWrapper}`)?.remove();
214
+ container.classList.add(styles.show);
215
+
216
+ domBuilder([
217
+ {
218
+ className: styles.messageBox,
219
+ children: [
220
+ {
221
+ className: styles.message,
222
+ children: [
223
+ { tag: 'h1', content: settings.title },
224
+ {
225
+ tag: 'p',
226
+ content: settings.text,
227
+ condition: !!settings.text
228
+ },
229
+ {
230
+ tag: 'p',
231
+ className: styles.backLink,
232
+ content: settings.backLink,
233
+ condition: !!settings.backLink
234
+ },
235
+ {
236
+ className: styles.arrowWrapper,
237
+ attrs: { role: 'button' },
238
+ children: [
239
+ { tag: 'img', attrs: { src: arrowIcon, alt: 'Icona freccia' } }
240
+ ],
241
+ callback: arrowEl => {
242
+ arrowEl.addEventListener('click', e => {
243
+ const target = /** @type {HTMLElement} */ (e.target);
244
+ target.closest(`.${styles.message}`)?.classList.toggle(styles.hidden);
245
+ }, false);
246
+ }
247
+ }
248
+ ]
249
+ },
250
+ {
251
+ className: styles.credits,
252
+ children: [
253
+ { tag: 'em', content: imgData.image_description },
254
+ {
255
+ tag: 'span',
256
+ content: `Photo <a href="${imgData.author_profile}?utmSource=${settings.utmSource}&utm_medium=referral">${imgData.author} / Unsplash</a>`
257
+ }
258
+ ]
259
+ }
260
+ ]
261
+ },
262
+ {
263
+ className: classnames( styles.unsplashPhotoLink, settings.hidePhotoLink ? styles.showOnHover : null ),
264
+ children: [
265
+ {
266
+ tag: 'a',
267
+ attrs: {
268
+ href: `${imgData.unsplash_url}?utm_source=${settings.utmSource}&utm_medium=referral`,
269
+ target: '_blank',
270
+ rel: 'noopener noreferrer'
271
+ },
272
+ children: [
273
+ { tag: 'img', attrs: { src: imageIcon, alt: 'Icona immagine' } }
274
+ ]
275
+ }
276
+ ]
277
+ }
278
+ ], container);
279
+
280
+ } catch(e) {
281
+ console.error( '[Unsplash Page] ' + e ); // eslint-disable-line
118
282
  }
119
- }).join('');
120
- }).join('') +
121
- '</picture>'
122
- ); // end insert <picture>
123
-
124
- const img = /** @type {HTMLImageElement | null} */ (container.querySelector('.' + cssClass('unsplashPhoto')));
125
- if (img) {
126
- img.onload = () => {
127
- container.querySelector('.' + cssClass('upLoaderWrapper'))?.remove();
128
- container.classList.add(cssClass('show'));
129
-
130
- container.insertAdjacentHTML('beforeend', `<div class="${cssClass('upMessageBox')}">
131
- <div class="${cssClass('upMessage')}">
132
- <h1>${settings.title}</h1>
133
- ${settings.text? `<p>${settings.text}</p>` : ''}
134
- ${settings.backLink ? `<p class="${cssClass('upBackLink')}">${settings.backLink}</p>` : ''}
135
-
136
- <div class="${cssClass('upArrowWrapper')}" role="button">
137
- <img src="${arrowIcon}" alt="Icona freccia">
138
- </div>
139
- </div>
140
-
141
- <div class="${cssClass('upCredits')}">
142
- <em>${photo.image_description}</em>
143
- <span>Photo
144
- <a href="${`${photo.author_profile}?utmSource=${settings.utmSource}&utm_medium=referral`}">
145
- ${photo.author} / Unsplash
146
- </a>
147
- </span>
148
- </div>
149
- </div>
150
- <div class="${cssClass('unsplashPhotoLink')}${settings.hidePhotoLink? ` ${cssClass('upShowOnHover')}` : ''}">
151
- <a href="${`${photo.unsplash_url}?utm_source=${settings.utmSource}&utm_medium=referral`}" target="_blank" rel="noopener noreferrer">
152
- <img src="${imageIcon}" alt="Icona immagine" />
153
- </a>
154
- </div>`);
155
-
156
- container.querySelector('.' + cssClass('upArrowWrapper'))?.addEventListener('click', e => {
157
- const target = /** @type {HTMLElement} */ (e.target);
158
- target.closest(`.${cssClass('upMessage')}`)?.classList.toggle(cssClass('hidden'));
159
- }, false);
160
-
161
- }; // end img.onload
162
- }
163
-
164
- }); // end .then
283
+ };
284
+
285
+ el.onerror = () => {
286
+ console.error( '[Unsplash Page] Errore nel caricamento dell\'immagine' ); // eslint-disable-line
287
+ container.querySelector('.' + styles.loaderWrapper)?.remove();
288
+ };
289
+ }
290
+ }
291
+ ]
292
+ }
293
+ ], container);
294
+
165
295
 
166
296
  } catch(e) {
167
- console.error( e ); // eslint-disable-line
297
+ console.error( '[Unsplash Page] ' + e ); // eslint-disable-line
168
298
  }
169
299
 
170
300
  }
@@ -1,5 +1,5 @@
1
1
  export default {
2
- up: {
2
+ 'uspg': {
3
3
  bg: {
4
4
  color: {
5
5
  $type: 'color',
@@ -59,7 +59,7 @@ export default {
59
59
  h1: {
60
60
  color: {
61
61
  $type: 'color',
62
- $value: '{up.text.color}'
62
+ $value: '{uspg.text.color}'
63
63
  },
64
64
  font: {
65
65
  size: {
@@ -86,7 +86,7 @@ export default {
86
86
  box: {
87
87
  bg: {
88
88
  $type: 'color',
89
- $value: '{up.link.color}'
89
+ $value: '{uspg.link.color}'
90
90
  }
91
91
  },
92
92
  fill: {