@panoramax/web-viewer 4.0.3 → 4.1.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/build/index.css +9 -9
  3. package/build/index.css.map +1 -1
  4. package/build/index.js +640 -456
  5. package/build/index.js.map +1 -1
  6. package/build/photo.html +1 -1
  7. package/build/viewer.html +3 -3
  8. package/build/widgets.html +1 -1
  9. package/config/jest/mocks.js +9 -1
  10. package/docs/03_URL_settings.md +21 -0
  11. package/docs/09_Develop.md +6 -0
  12. package/docs/images/comparative_3drender.jpg +0 -0
  13. package/docs/index.md +13 -0
  14. package/docs/reference/components/core/Editor.md +18 -0
  15. package/docs/reference/components/core/PhotoViewer.md +1 -0
  16. package/docs/reference/components/core/Viewer.md +1 -0
  17. package/docs/reference/components/menus/MapLegend.md +17 -0
  18. package/docs/reference/components/menus/MiniPictureLegend.md +15 -0
  19. package/docs/reference/components/menus/PictureLegend.md +17 -0
  20. package/docs/reference/components/ui/AnnotationsSwitch.md +15 -0
  21. package/docs/reference/components/ui/Button.md +1 -1
  22. package/docs/reference/components/ui/CopyButton.md +1 -1
  23. package/docs/reference/components/ui/LinkButton.md +1 -1
  24. package/docs/reference/components/ui/Map.md +18 -2
  25. package/docs/reference/components/ui/MapMore.md +6 -2
  26. package/docs/reference/components/ui/SemanticsEditor.md +87 -0
  27. package/docs/reference/components/ui/widgets/Legend.md +5 -4
  28. package/docs/reference/utils/URLHandler.md +7 -0
  29. package/docs/reference.md +3 -1
  30. package/docs/tutorials/aerial_imagery.md +13 -11
  31. package/mkdocs.yml +3 -1
  32. package/package.json +7 -7
  33. package/public/photo.html +1 -1
  34. package/public/viewer.html +3 -3
  35. package/public/widgets.html +32 -0
  36. package/src/components/core/Basic.css +2 -0
  37. package/src/components/core/Basic.js +3 -1
  38. package/src/components/core/CoverageMap.js +6 -0
  39. package/src/components/core/Editor.css +1 -0
  40. package/src/components/core/Editor.js +58 -7
  41. package/src/components/core/PhotoViewer.css +5 -10
  42. package/src/components/core/PhotoViewer.js +55 -20
  43. package/src/components/core/Viewer.css +9 -2
  44. package/src/components/core/Viewer.js +62 -33
  45. package/src/components/layout/BottomDrawer.js +2 -1
  46. package/src/components/layout/Tabs.js +4 -0
  47. package/src/components/menus/AnnotationsList.js +13 -9
  48. package/src/components/menus/MapBackground.js +8 -3
  49. package/src/components/menus/MapFilters.js +11 -2
  50. package/src/components/menus/MapLayers.js +3 -2
  51. package/src/components/menus/MapLegend.js +28 -4
  52. package/src/components/menus/MiniPictureLegend.js +74 -0
  53. package/src/components/menus/PictureLegend.js +88 -33
  54. package/src/components/menus/PictureMetadata.js +49 -17
  55. package/src/components/menus/PlayerOptions.js +3 -3
  56. package/src/components/menus/Share.js +3 -3
  57. package/src/components/menus/index.js +5 -4
  58. package/src/components/styles.js +11 -0
  59. package/src/components/ui/AnnotationsSwitch.js +169 -0
  60. package/src/components/ui/Button.js +1 -1
  61. package/src/components/ui/CopyButton.js +1 -1
  62. package/src/components/ui/LinkButton.js +1 -1
  63. package/src/components/ui/Map.css +4 -0
  64. package/src/components/ui/Map.js +17 -5
  65. package/src/components/ui/MapMore.js +61 -25
  66. package/src/components/ui/Photo.css +11 -2
  67. package/src/components/ui/Photo.js +6 -3
  68. package/src/components/ui/SemanticsEditor.js +157 -0
  69. package/src/components/ui/index.js +2 -1
  70. package/src/components/ui/widgets/GeoSearch.js +3 -2
  71. package/src/components/ui/widgets/Legend.js +69 -14
  72. package/src/components/ui/widgets/MapFiltersButton.js +3 -3
  73. package/src/components/ui/widgets/MapLayersButton.js +3 -3
  74. package/src/components/ui/widgets/OSMEditors.js +2 -2
  75. package/src/components/ui/widgets/PictureLegendActions.js +24 -42
  76. package/src/components/ui/widgets/Player.js +3 -3
  77. package/src/components/ui/widgets/Zoom.js +4 -2
  78. package/src/translations/ar.json +1 -0
  79. package/src/translations/da.json +3 -2
  80. package/src/translations/de.json +64 -13
  81. package/src/translations/en.json +5 -1
  82. package/src/translations/eo.json +32 -2
  83. package/src/translations/fr.json +7 -1
  84. package/src/translations/it.json +33 -2
  85. package/src/translations/nl.json +53 -11
  86. package/src/translations/zh_Hant.json +29 -2
  87. package/src/utils/API.js +17 -1
  88. package/src/utils/InitParameters.js +46 -4
  89. package/src/utils/URLHandler.js +9 -1
  90. package/src/utils/map.js +24 -1
  91. package/src/utils/semantics.js +53 -1
  92. package/src/utils/services.js +16 -0
  93. package/src/utils/widgets.js +20 -0
  94. package/tests/components/core/Editor.test.js +1 -1
  95. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +18 -6
  96. package/tests/components/core/__snapshots__/Viewer.test.js.snap +15 -3
  97. package/tests/components/ui/Photo.test.js +1 -0
  98. package/tests/components/ui/__snapshots__/Map.test.js.snap +164 -0
  99. package/tests/utils/InitParameters.test.js +27 -0
  100. package/tests/utils/map.test.js +12 -0
  101. package/tests/utils/semantics.test.js +34 -5
  102. package/docs/reference/components/ui/HashTags.md +0 -15
  103. package/src/components/ui/HashTags.js +0 -98
@@ -2,11 +2,10 @@
2
2
 
3
3
  import "./Viewer.css";
4
4
  import { linkMapAndPhoto, saveMapParamsToLocalStorage, getMapParamsFromLocalStorage } from "../../utils/map";
5
- import PhotoViewer from "./PhotoViewer";
6
- import Basic from "./Basic";
5
+ import PhotoViewer, {KEYBOARD_SKIP_FOCUS_WIDGETS} from "./PhotoViewer";
7
6
  import MapMore from "../ui/MapMore";
8
7
  import { initMapKeyboardHandler } from "../../utils/map";
9
- import { isNullId } from "../../utils/utils";
8
+ import { isNullId, isInIframe } from "../../utils/utils";
10
9
  import { createWebComp } from "../../utils/widgets";
11
10
  import { fa } from "../../utils/widgets";
12
11
  import { faPanorama } from "@fortawesome/free-solid-svg-icons/faPanorama";
@@ -16,7 +15,6 @@ import { default as InitParameters, alterMapState, alterViewerState } from "../.
16
15
 
17
16
 
18
17
  export const PSV_ZOOM_DELTA = 20;
19
- const PSV_MOVE_DELTA = Math.PI / 6;
20
18
  const MAP_MOVE_DELTA = 100;
21
19
 
22
20
 
@@ -95,6 +93,7 @@ export default class Viewer extends PhotoViewer {
95
93
  * @property {object} [map] An object with [any map option available in Map or MapMore class](#Panoramax.components.ui.MapMore).<br />Example: `map="{'background': 'aerial', 'theme': 'age'}"`
96
94
  * @property {object} [psv] [Any option to pass to Photo component](#Panoramax.components.ui.Photo) as an object.<br />Example: `psv="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"`
97
95
  * @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
96
+ * @property {string} [keyboard-shortcuts=true] Should keyboard shortcuts be enabled ? Set to "false" to fully disable any keyboard shortcuts.
98
97
  * @property {string} [focus=pic] The component showing up as main component (pic, map)
99
98
  * @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API)
100
99
  * @property {string} [widgets=true] Use default set of widgets ? Set to false to avoid any widget to show up, and use slots to populate as you like.
@@ -149,20 +148,25 @@ export default class Viewer extends PhotoViewer {
149
148
  _parent: this
150
149
  }));
151
150
 
152
- if(!this.isWidthSmall()) {
151
+ if(isInIframe()) {
153
152
  this.legend = createWebComp("pnx-widget-legend", {
154
- slot: this.isWidthSmall() ? "top" : "top-left",
153
+ slot: "bottom-right",
154
+ light: true,
155
155
  _parent: this,
156
156
  focus: this._initParams.getParentPostInit().focus,
157
157
  picture: this._initParams.getParentPostInit().picture,
158
158
  });
159
159
  this.grid.appendChild(this.legend);
160
-
161
- this.grid.appendChild(createWebComp("pnx-hashtags", {
162
- slot: "top-right",
160
+ }
161
+ else if(!this.isWidthSmall()) {
162
+ this.legend = createWebComp("pnx-widget-legend", {
163
+ slot: this.isWidthSmall() ? "top" : "top-left",
163
164
  _parent: this,
164
- class: "pnx-only-psv pnx-print-hidden",
165
- }));
165
+ focus: this._initParams.getParentPostInit().focus,
166
+ picture: this._initParams.getParentPostInit().picture,
167
+ });
168
+ this._miniPicLegend = createWebComp("pnx-mini-picture-legend", { _parent: this });
169
+ this.grid.appendChild(this.legend);
166
170
  }
167
171
  else {
168
172
  this.legend = createWebComp("pnx-picture-legend", { _parent: this });
@@ -179,30 +183,47 @@ export default class Viewer extends PhotoViewer {
179
183
  });
180
184
  }
181
185
 
182
- this.grid.appendChild(createWebComp("pnx-widget-player", {
183
- slot: "top",
184
- _parent: this,
185
- class: "pnx-only-psv pnx-print-hidden",
186
- size: this.isHeightSmall() ? "md": "xl",
187
- }));
186
+ if(!isInIframe()) {
187
+ this.grid.appendChild(createWebComp("pnx-widget-player", {
188
+ slot: "top",
189
+ _parent: this,
190
+ class: "pnx-only-psv pnx-print-hidden",
191
+ size: this.isHeightSmall() ? "md": "xl",
192
+ }));
193
+
194
+ this.grid.appendChild(createWebComp("pnx-annotations-switch", {
195
+ slot: "top",
196
+ _parent: this,
197
+ class: "pnx-only-psv pnx-print-hidden",
198
+ size: this.isHeightSmall() ? "md": "xl",
199
+ }));
188
200
 
189
- this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
190
- slot: this.isWidthSmall() ? "top-right" : "top-left",
191
- _parent: this,
192
- class: "pnx-only-map pnx-print-hidden",
193
- geocoder: this._initParams.getParentPostInit().geocoder,
194
- }));
195
- this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
196
- slot: this.isWidthSmall() ? "top-right" : "top-left",
197
- _parent: this,
198
- "user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
199
- "quality-score": this.map?._hasQualityScore?.() || false,
200
- class: "pnx-only-map pnx-print-hidden",
201
- }));
202
- this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
201
+ this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
202
+ slot: this.isWidthSmall() ? "top-right" : "top-left",
203
+ _parent: this,
204
+ class: "pnx-only-map pnx-print-hidden",
205
+ geocoder: this._initParams.getParentPostInit().geocoder,
206
+ }));
207
+
208
+ this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
209
+ slot: this.isWidthSmall() ? "top-right" : "top-left",
210
+ _parent: this,
211
+ "user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
212
+ "quality-score": this.map?._hasQualityScore?.() || false,
213
+ class: "pnx-only-map pnx-print-hidden",
214
+ }));
215
+
216
+ this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
217
+ }
203
218
  }
204
219
  }
205
220
 
221
+ /** @private */
222
+ disconnectedCallback() {
223
+ super.disconnectedCallback();
224
+ this.map?.destroy();
225
+ }
226
+
206
227
  getClassName() {
207
228
  return "Viewer";
208
229
  }
@@ -321,7 +342,10 @@ export default class Viewer extends PhotoViewer {
321
342
  this._moveChildToGrid();
322
343
 
323
344
  alterViewerState(this, myPostInitParams);
324
- this._handleKeyboardManagement();
345
+
346
+ if(myPostInitParams.keyboardShortcuts) {
347
+ this._handleKeyboardManagement();
348
+ }
325
349
 
326
350
  if(myPostInitParams.picture) {
327
351
  this.psv.addEventListener("picture-loaded", () => {
@@ -367,7 +391,10 @@ export default class Viewer extends PhotoViewer {
367
391
 
368
392
  // Widgets
369
393
  for(let cn of this.grid.childNodes) {
370
- if(cn.getAttribute("slot") !== "bg") {
394
+ if(
395
+ cn.getAttribute("slot") !== "bg"
396
+ && !KEYBOARD_SKIP_FOCUS_WIDGETS.includes(cn.tagName.toLowerCase())
397
+ ) {
371
398
  cn.addEventListener("focusin", () => keytonone());
372
399
  cn.addEventListener("focusout", () => {
373
400
  if(this.popup.getAttribute("visible") === null) {
@@ -471,6 +498,7 @@ export default class Viewer extends PhotoViewer {
471
498
  // Add PSV to mini
472
499
  this.mini.appendChild(this.psvContainer);
473
500
  this.mini.icon = fa(faPanorama);
501
+ if(this._miniPicLegend) { this.mini.appendChild(this._miniPicLegend); }
474
502
 
475
503
  // Hide mini icon if no picture selected
476
504
  if(isNullId(this.picture)) { this.mini.classList.add("pnx-hidden"); }
@@ -488,6 +516,7 @@ export default class Viewer extends PhotoViewer {
488
516
  // Remove PSV from mini
489
517
  if(this.psvContainer.parentNode == this.mini) {
490
518
  this.mini.removeChild(this.psvContainer);
519
+ if(this._miniPicLegend) { this.mini.removeChild(this._miniPicLegend); }
491
520
  }
492
521
 
493
522
  // Add PSV to grid
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { classMap } from "lit/directives/class-map.js";
3
+ import { onceParentAvailable } from "../../utils/widgets";
3
4
 
4
5
  const OPENNESS_Y_PCT = { "opened": 0, "half-opened": 0.7, "closed": 1 };
5
6
 
@@ -104,7 +105,7 @@ export default class BottomDrawer extends LitElement {
104
105
  drawer.style.height = `${this._drawerHeight}px`;
105
106
  drawer.style.maxHeight = `${this._drawerHeight}px`;
106
107
 
107
- this._parent?.onceReady().then(() => {
108
+ onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
108
109
  this._parent.map?.addEventListener("click", () => this.openness = "closed");
109
110
  this._parent.psv?.addEventListener("click", () => this.openness = "closed");
110
111
  });
@@ -33,6 +33,10 @@ export default class Tabs extends LitElement {
33
33
  align-items: stretch;
34
34
  overflow-x: auto;
35
35
  touch-action: pan-x;
36
+ position: sticky;
37
+ top: 0;
38
+ background: white;
39
+ z-index: 125;
36
40
  }
37
41
  nav ::slotted(*) {
38
42
  color: var(--grey-dark);
@@ -3,6 +3,7 @@ import { faSvg, iconify } from "../styles";
3
3
  import { fa, moreIcons } from "../../utils/widgets";
4
4
  import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight";
5
5
  import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft";
6
+ import { onceParentAvailable } from "../../utils/widgets";
6
7
  import "iconify-icon";
7
8
 
8
9
  /**
@@ -42,15 +43,18 @@ export default class AnnotationsList extends LitElement {
42
43
  super.connectedCallback();
43
44
 
44
45
  this._onPicChange();
45
- this._parent?.psv?.addEventListener("picture-loaded", this._onPicChange.bind(this));
46
-
47
- this._parent?.psv?.addEventListener("annotation-click", e => {
48
- const aPos = this._meta.properties?.annotations?.findIndex(a => a.id === e.detail.annotationId);
49
- if(aPos >= 0) { this._onListItemClick(Object.assign({nb: aPos+1}, this._meta.properties.annotations[aPos])); }
50
- });
51
-
52
- this._parent?.psv?.addEventListener("annotations-unfocused", () => {
53
- this._onListItemClick(null);
46
+
47
+ onceParentAvailable(this).then(() => {
48
+ this._parent.psv?.addEventListener("picture-loaded", this._onPicChange.bind(this));
49
+
50
+ this._parent.psv?.addEventListener("annotation-click", e => {
51
+ const aPos = this._meta.properties?.annotations?.findIndex(a => a.id === e.detail.annotationId);
52
+ if(aPos >= 0) { this._onListItemClick(Object.assign({nb: aPos+1}, this._meta.properties.annotations[aPos])); }
53
+ });
54
+
55
+ this._parent.psv?.addEventListener("annotations-unfocused", () => {
56
+ this._onListItemClick(null);
57
+ });
54
58
  });
55
59
  }
56
60
 
@@ -1,6 +1,8 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import BackgroundAerial from "../../img/bg_aerial.jpg";
3
3
  import BackgroundStreets from "../../img/bg_streets.jpg";
4
+ import { onceParentAvailable } from "../../utils/widgets";
5
+
4
6
 
5
7
  /**
6
8
  * Map Background menu allows user to select background.
@@ -60,10 +62,13 @@ export default class MapBackground extends LitElement {
60
62
  /** @private */
61
63
  connectedCallback() {
62
64
  super.connectedCallback();
63
- this._parent?.map?.on("background-changed", e => {
64
- this.bg = e.background;
65
+
66
+ onceParentAvailable(this).then(() => {
67
+ this._parent.map?.on("background-changed", e => {
68
+ this.bg = e.background;
69
+ });
70
+ this.bg = this._parent.map?.getBackground();
65
71
  });
66
- this.bg = this._parent?.map?.getBackground();
67
72
  }
68
73
 
69
74
  /** @private */
@@ -8,6 +8,7 @@ import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight";
8
8
  import { faMedal } from "@fortawesome/free-solid-svg-icons/faMedal";
9
9
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
10
10
  import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
11
+ import { onceParentAvailable } from "../../utils/widgets";
11
12
 
12
13
  /**
13
14
  * Map Filters menu allows user to select map data they want displayed.
@@ -180,12 +181,20 @@ export default class MapFilters extends LitElement {
180
181
  }
181
182
 
182
183
  // Map zoom
183
- this._parent?.onceMapReady?.().then(() => {
184
+ onceParentAvailable(this).then(() => this._parent.onceMapReady?.().then(async () => {
184
185
  this._parent.map.on("zoomend", this._onMapZoom.bind(this));
185
186
  this._parent.map.on("filters-changed", this._onParentFilterChange.bind(this));
186
187
  this._onMapZoom();
187
188
  this._onParentFilterChange(this._parent.map._mapFilters);
188
- });
189
+
190
+ // Load default users filter
191
+ const vu = this._parent.map.getVisibleUsers();
192
+ if(vu?.length > 0 && vu[0] != "geovisio") {
193
+ this.user = vu[0];
194
+ const username = await this._parent.api.getUserName(vu[0]);
195
+ if(username) { this.user = username; }
196
+ }
197
+ }));
189
198
  }
190
199
 
191
200
  /**
@@ -5,6 +5,7 @@ import { COLORS } from "../../utils/utils";
5
5
  import { faEarthEurope } from "@fortawesome/free-solid-svg-icons/faEarthEurope";
6
6
  import { faPalette } from "@fortawesome/free-solid-svg-icons/faPalette";
7
7
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
8
+ import { onceParentAvailable } from "../../utils/widgets";
8
9
 
9
10
  /**
10
11
  * Map Layers menu allows user to select background and map theme.
@@ -56,10 +57,10 @@ export default class MapLayers extends LitElement {
56
57
  /** @private */
57
58
  connectedCallback() {
58
59
  super.connectedCallback();
59
- this._parent?.onceMapReady?.().then(() => {
60
+ onceParentAvailable(this).then(() => this._parent?.onceMapReady?.().then(() => {
60
61
  this.theme = this._parent.map._mapFilters.theme;
61
62
  this._parent.map.on("filters-changed", e => this.theme = e.theme);
62
- });
63
+ }));
63
64
  }
64
65
 
65
66
  /** @private */
@@ -14,20 +14,44 @@ export default class MapLegend extends LitElement {
14
14
  /** @private */
15
15
  static styles = css`
16
16
  :host {
17
- font-size: 0.9em;
17
+ font-size: 0.7em;
18
18
  }
19
19
  small {
20
20
  font-size: 1em;
21
21
  }
22
+ .maplibregl-ctrl-attrib-inner {
23
+ display: inline-block;
24
+ }
22
25
  `;
23
26
 
27
+ /**
28
+ * Component properties.
29
+ * @memberof Panoramax.components.menus.MapLegend#
30
+ * @type {Object}
31
+ * @property {boolean} [light=false] Lighter version (for iframes)
32
+ */
33
+ static properties = {
34
+ light: {type: Boolean},
35
+ };
36
+
37
+ constructor() {
38
+ super();
39
+ this.light = false;
40
+ }
41
+
24
42
  /** @private */
25
43
  render() {
44
+ /* eslint-disable indent */
26
45
  const mapAttrib = this._parent?.map?._attribution?._innerContainer;
46
+ const mapLabelParts = this._parent?._t.map.map_data.split("{m}");
27
47
 
28
- return html`
29
- ${mapAttrib && mapAttrib.innerHTML.length > 0 ? html`${this._parent?._t.map.map_data}<br />${mapAttrib}` : nothing}
30
- `;
48
+ return this.light ?
49
+ (mapAttrib && mapAttrib.innerHTML.length > 0 ? mapAttrib : nothing)
50
+ : html`
51
+ ${mapAttrib && mapAttrib.innerHTML.length > 0
52
+ ? html`${mapLabelParts.shift()}${mapAttrib}${mapLabelParts.shift()}`
53
+ : nothing}
54
+ `;
31
55
  }
32
56
  }
33
57
 
@@ -0,0 +1,74 @@
1
+ import { LitElement, nothing, css, html } from "lit";
2
+ import { onceParentAvailable } from "../../utils/widgets";
3
+ import { panel } from "../styles";
4
+
5
+ /**
6
+ * Mini picture legend shows info about picture capture date, when seen in mini component of viewer.
7
+ * @class Panoramax.components.menus.MiniPictureLegend
8
+ * @element pnx-mini-picture-legend
9
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
10
+ * @example
11
+ * ```html
12
+ * <pnx-mini-picture-legend ._parent=${viewer} />
13
+ * ```
14
+ */
15
+ export default class MiniPictureLegend extends LitElement {
16
+ /** @private */
17
+ static styles = [panel, css`
18
+ .pnx-panel {
19
+ bottom: 0;
20
+ right: 0;
21
+ width: unset;
22
+ min-width: unset;
23
+ border-radius: 10px;
24
+ border-top-right-radius: 0;
25
+ border-bottom-left-radius: 0;
26
+ border-right: none;
27
+ border-bottom: none;
28
+ padding: 2px 5px;
29
+ font-size: 0.7em;
30
+ }
31
+ `];
32
+
33
+ /** @private */
34
+ static properties = {
35
+ _caption: {state: true},
36
+ };
37
+
38
+ /** @private */
39
+ connectedCallback() {
40
+ super.connectedCallback();
41
+
42
+ onceParentAvailable(this)
43
+ .then(() => this._parent.onceReady())
44
+ .then(() => {
45
+ this._onPicChange(this._parent.psv.getPictureMetadata());
46
+ this._parent.psv.addEventListener("picture-loaded", () => {
47
+ this._onPicChange(this._parent.psv.getPictureMetadata());
48
+ });
49
+ this._parent.psv.addEventListener("sequence-stopped", () => {
50
+ this._onPicChange(this._parent.psv.getPictureMetadata());
51
+ });
52
+ });
53
+ }
54
+
55
+ /** @private */
56
+ _onPicChange(picMeta) {
57
+ this._caption = picMeta?.caption;
58
+ }
59
+
60
+ /** @private */
61
+ render() {
62
+ /* eslint-disable indent */
63
+ return this._caption?.date ?
64
+ html`<div class="pnx-panel">${
65
+ this._caption.date.toLocaleDateString(
66
+ this._parent?.lang || window.navigator.language,
67
+ { year: "numeric", month: "long", day: "numeric" }
68
+ )
69
+ }</div>`
70
+ : nothing;
71
+ }
72
+ }
73
+
74
+ customElements.define("pnx-mini-picture-legend", MiniPictureLegend);
@@ -1,6 +1,7 @@
1
- import { LitElement, html, nothing, css } from "lit";
1
+ import { LitElement, nothing, css } from "lit";
2
+ import { html, unsafeStatic } from "lit/static-html.js";
2
3
  import { classMap } from "lit/directives/class-map.js";
3
- import { fa } from "../../utils/widgets";
4
+ import { fa, onceParentAvailable } from "../../utils/widgets";
4
5
  import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft";
5
6
  import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
6
7
  import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
@@ -26,16 +27,17 @@ export default class PictureLegend extends LitElement {
26
27
  /** @private */
27
28
  static styles = [placeholder, panel, hidden, css`
28
29
  :host {
29
- overflow-y: auto;
30
- overflow-x: hidden;
31
- display: block;
30
+ display: flex;
31
+ flex-direction: column;
32
32
  margin: 0;
33
33
  font-family: var(--font-family);
34
+ flex-wrap: nowrap;
34
35
  }
35
36
 
36
37
  @media screen and (min-width: 576px) {
37
- :host { max-height: 70vh; }
38
- pnx-picture-metadata { width: 30vw; }
38
+ :host {
39
+ max-height: 70vh;
40
+ }
39
41
  }
40
42
 
41
43
  /* Top bar */
@@ -45,6 +47,12 @@ export default class PictureLegend extends LitElement {
45
47
  align-items: center;
46
48
  margin: 10px 10px 5px 10px;
47
49
  justify-content: space-between;
50
+ flex: 1;
51
+ }
52
+
53
+ .headline-buttons {
54
+ display: flex;
55
+ gap: 5px;
48
56
  }
49
57
 
50
58
  /* Address line */
@@ -54,6 +62,9 @@ export default class PictureLegend extends LitElement {
54
62
  margin-bottom: 2px;
55
63
  flex-grow: 5;
56
64
  font-weight: 800;
65
+ text-overflow: ellipsis;
66
+ overflow: hidden;
67
+ white-space: nowrap;
57
68
  }
58
69
 
59
70
  #pic-legend-addr span {
@@ -84,6 +95,7 @@ export default class PictureLegend extends LitElement {
84
95
  display: block;
85
96
  margin-top: 5px;
86
97
  max-width: 100%;
98
+ flex: 1;
87
99
  }
88
100
  #pic-legend-expand::part(btn) {
89
101
  border-radius: 10px;
@@ -93,10 +105,11 @@ export default class PictureLegend extends LitElement {
93
105
 
94
106
  /* Details block */
95
107
  pnx-picture-metadata {
96
- margin: 5px 10px 10px;
108
+ margin: 5px 10px;
97
109
  display: block;
98
- max-width: 450px;
99
110
  box-sizing: border-box;
111
+ flex: 1;
112
+ overflow-y: auto;
100
113
  }
101
114
 
102
115
  /* Details actions */
@@ -107,6 +120,7 @@ export default class PictureLegend extends LitElement {
107
120
  border-bottom-right-radius: 10px;
108
121
  gap: 5px;
109
122
  flex-wrap: wrap;
123
+ flex: 1;
110
124
  }
111
125
 
112
126
  /* More options menu */
@@ -114,10 +128,22 @@ export default class PictureLegend extends LitElement {
114
128
 
115
129
  /* Editors */
116
130
  #pic-legend-editors { margin: 0 10px; }
131
+
132
+ /* Light version */
133
+ .pnx-picture-legend-light {
134
+ width: max-content;
135
+ font-size: 10px;
136
+ }
117
137
  `];
118
138
 
119
- /** @private */
139
+ /**
140
+ * Component properties.
141
+ * @memberof Panoramax.components.menus.PictureLegend#
142
+ * @type {Object}
143
+ * @property {boolean} [light=false] Lighter version (for iframes)
144
+ */
120
145
  static properties = {
146
+ light: {type: Boolean},
121
147
  _caption: { state: true },
122
148
  _addr: { state: true },
123
149
  _expanded: { state: true },
@@ -129,6 +155,7 @@ export default class PictureLegend extends LitElement {
129
155
  super();
130
156
  this._expanded = true;
131
157
  this.collapsable = false;
158
+ this.light = false;
132
159
  }
133
160
 
134
161
  /** @private */
@@ -138,18 +165,20 @@ export default class PictureLegend extends LitElement {
138
165
  this._expanded = !this.collapsable;
139
166
  this._prevSearches = {};
140
167
 
141
- this._parent.onceReady().then(() => {
142
- this._onPicChange(this._parent.psv.getPictureMetadata());
143
- this._parent.psv.addEventListener("picture-loaded", () => {
168
+ onceParentAvailable(this)
169
+ .then(() => this._parent.onceReady())
170
+ .then(() => {
144
171
  this._onPicChange(this._parent.psv.getPictureMetadata());
172
+ this._parent.psv.addEventListener("picture-loaded", () => {
173
+ this._onPicChange(this._parent.psv.getPictureMetadata());
174
+ });
175
+ this._parent.psv.addEventListener("sequence-stopped", () => {
176
+ this._onPicChange(this._parent.psv.getPictureMetadata());
177
+ });
178
+ this._parent.psv.addEventListener("annotation-click", () => {
179
+ this._expanded = true;
180
+ });
145
181
  });
146
- this._parent.psv.addEventListener("sequence-stopped", () => {
147
- this._onPicChange(this._parent.psv.getPictureMetadata());
148
- });
149
- this._parent.psv.addEventListener("annotation-click", () => {
150
- this._expanded = true;
151
- });
152
- });
153
182
  }
154
183
 
155
184
  /** @private */
@@ -196,6 +225,22 @@ export default class PictureLegend extends LitElement {
196
225
  const hiddenExpanded = classMap({"pnx-hidden": this._expanded});
197
226
  const shownExpanded = classMap({"pnx-hidden": !this._expanded});
198
227
 
228
+ if(this.light) {
229
+ return html`<div class="pnx-picture-legend-light">
230
+ ${this._caption.producer?.length > 0 ? html`
231
+ <a
232
+ href=${window.location.href}
233
+ target="_blank"
234
+ title=${this._parent?._t.pnx.share_page}
235
+ >${this._caption.producer[this._caption.producer.length-1]}</a>
236
+ </div>` : nothing}
237
+
238
+ ${this._caption.producer?.length > 0 && this._caption?.license ? "|" : ""}
239
+
240
+ ${this._caption?.license ? html`${unsafeStatic(this._caption.license)}` : nothing}
241
+ `;
242
+ }
243
+
199
244
  return html`
200
245
  <div class="headline">
201
246
  ${this._parent._setFocus ? html`
@@ -207,15 +252,26 @@ export default class PictureLegend extends LitElement {
207
252
  </pnx-button>
208
253
  ` : nothing}
209
254
 
210
- <div id="pic-legend-addr">
255
+ <div id="pic-legend-addr" title=${this._addr || ""}>
211
256
  ${this._addr?.length > 0 ? this._addr : html`<span class="pnx-placeholder-loading">&nbsp;</span>`}
212
257
  </div>
213
258
 
214
- <pnx-picture-legend-actions
215
- @click=${e => e.stopPropagation()}
216
- ._parent=${this._parent}
217
- ?full=${this._expanded}
218
- ></pnx-picture-legend-actions>
259
+ <div class="headline-buttons">
260
+ <pnx-button
261
+ size="sm"
262
+ class=${hiddenExpanded}
263
+ title=${this._parent?._t.pnx.share}
264
+ @click=${() => this._parent._showShareOptions()}
265
+ >
266
+ ${fa(faShareNodes)}
267
+ </pnx-button>
268
+
269
+ <pnx-picture-legend-actions
270
+ @click=${e => e.stopPropagation()}
271
+ ._parent=${this._parent}
272
+ ?full=${this._expanded}
273
+ ></pnx-picture-legend-actions>
274
+ </div>
219
275
  </div>
220
276
 
221
277
  <div id="pic-legend-info" class=${hiddenExpanded}>
@@ -226,21 +282,20 @@ export default class PictureLegend extends LitElement {
226
282
 
227
283
  ${this._caption.date ? html`<div class="info-block">
228
284
  ${fa(faCalendarAlt)}
229
- ${this._caption.date.toLocaleDateString(this._parent?.lang || window.navigator.language, { year: "numeric", month: "long" })}
230
- </div>` : nothing}
285
+ ${this._caption.date.toLocaleDateString(this._parent?.lang || window.navigator.language, { year: "numeric", month: "long", day: "numeric" })} </div>` : nothing}
231
286
  </div>
232
287
 
233
288
  <div id="pic-legend-cta" class=${shownExpanded}>
289
+ <pnx-button size="sm" @click=${() => this._parent._showShareOptions()}>
290
+ ${fa(faShareNodes)} ${this._parent?._t.pnx.share}
291
+ </pnx-button>
292
+
234
293
  ${this._parent.api._endpoints.report ? html`
235
- <pnx-button size="sm" @click=${() => this._parent._showReportForm()}>
294
+ <pnx-button kind="fullwarn" size="sm" @click=${() => this._parent._showReportForm()}>
236
295
  ${fa(faTriangleExclamation)} ${this._parent?._t.pnx.report}
237
296
  </pnx-button>
238
297
  ` : nothing}
239
298
 
240
- <pnx-button size="sm" @click=${() => this._parent._showShareOptions()}>
241
- ${fa(faShareNodes)} ${this._parent?._t.pnx.share}
242
- </pnx-button>
243
-
244
299
  <slot name="editors">
245
300
  <pnx-widget-osmeditors ._parent=${this._parent} />
246
301
  </slot>