@eodash/eodash 5.0.0-alpha.2.1 → 5.0.0-alpha.2.11

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 (138) hide show
  1. package/README.md +36 -3
  2. package/core/client/App.vue +26 -0
  3. package/core/client/SuspensedDashboard.ce.vue +105 -0
  4. package/core/client/asWebComponent.d.ts +23 -0
  5. package/core/client/asWebComponent.js +12 -0
  6. package/core/client/components/DashboardLayout.vue +77 -0
  7. package/core/client/components/DynamicWebComponent.vue +68 -0
  8. package/core/client/components/ErrorAlert.vue +36 -0
  9. package/core/{components → client/components}/Footer.vue +34 -15
  10. package/core/client/components/Header.vue +19 -0
  11. package/core/client/components/IframeWrapper.vue +11 -0
  12. package/core/client/components/Loading.vue +37 -0
  13. package/core/client/components/MobileLayout.vue +109 -0
  14. package/core/client/composables/DefineEodash.js +67 -0
  15. package/core/client/composables/DefineWidgets.js +161 -0
  16. package/core/client/composables/index.js +155 -0
  17. package/core/client/eodash.js +129 -0
  18. package/core/client/main.js +2 -0
  19. package/core/client/plugins/index.js +20 -0
  20. package/core/client/plugins/vuetify.js +35 -0
  21. package/core/client/render.js +12 -0
  22. package/core/client/store/Actions.js +38 -0
  23. package/core/client/store/States.js +24 -0
  24. package/core/client/store/index.js +20 -0
  25. package/core/client/store/stac.js +81 -0
  26. package/core/client/types.d.ts +287 -0
  27. package/core/client/utils/createLayers.js +131 -0
  28. package/core/client/utils/eodashSTAC.js +259 -0
  29. package/core/client/utils/helpers.js +152 -0
  30. package/core/client/utils/index.js +51 -0
  31. package/core/{utils → client/utils}/keys.js +2 -2
  32. package/core/client/views/Dashboard.vue +116 -0
  33. package/core/client/vite-env.d.ts +39 -0
  34. package/dist/client/DashboardLayout-D5c2wAGC.js +156 -0
  35. package/dist/{DynamicWebComponent-BrHVTesn.js → client/DynamicWebComponent-CBuMCUIj.js} +11 -11
  36. package/dist/client/EodashDatePicker-D0qdMMTE.js +252 -0
  37. package/dist/client/EodashItemFilter-CTRnGRRS.js +10067 -0
  38. package/dist/client/EodashLayerControl-Bpm0BwcW.js +31499 -0
  39. package/dist/client/EodashMap-DaMtQefq.js +114367 -0
  40. package/dist/client/EodashMapBtns-B5z8h8mr.js +50 -0
  41. package/dist/client/ExportState-Bp3n6gba.js +558 -0
  42. package/dist/client/Footer-BROOTKhV.js +115 -0
  43. package/dist/client/Header-C_fKVTsg.js +350 -0
  44. package/dist/{IframeWrapper-Dd9zrX9s.js → client/IframeWrapper-32Q3DBYr.js} +4 -4
  45. package/dist/client/MobileLayout-TVGrYpNT.js +945 -0
  46. package/dist/client/PopUp-BJzmeeKG.js +300 -0
  47. package/dist/client/VImg-BT4Vb0UT.js +291 -0
  48. package/dist/client/VMain-BDVUXNEk.js +39 -0
  49. package/dist/client/VOverlay-Ck_4Lxcb.js +972 -0
  50. package/dist/{WidgetsContainer-DxfCu0I3.js → client/WidgetsContainer-DjjX_n1U.js} +25 -18
  51. package/dist/client/asWebComponent-wn9bbgx9.js +20404 -0
  52. package/dist/{basedecoder-Qm25PwVp-CHo5Pomv.js → client/basedecoder-DHcBySSe-BmCFNFnw.js} +5 -6
  53. package/dist/{decoder-kAoyGIq9-BBR5CgzS.js → client/decoder-Cth6J7EK-CLlwAswr.js} +1 -1
  54. package/dist/client/deflate-BXt-9JA_-CWfClgpK.js +10 -0
  55. package/dist/client/eo-dash.js +6 -0
  56. package/dist/client/eox-stacinfo-l7ALSV90.js +13969 -0
  57. package/dist/client/forwardRefs--PLRH8zp.js +185 -0
  58. package/dist/client/helpers-CoqJPYdE.js +1391 -0
  59. package/dist/{index-DTkOfh2g.js → client/index-Dt0NRXIq.js} +21 -20
  60. package/dist/{jpeg-DNfUpLwy-Fjan-04T.js → client/jpeg-BAgeD1d3-oeHbFPUL.js} +5 -6
  61. package/dist/{lerc-C9VL9kri-cIdbW0sg.js → client/lerc-BgbQqdFI-CCpDWUne.js} +37 -39
  62. package/dist/{lzw-BOMhmEDy-Dboc93VO.js → client/lzw-LAGDNbSC-DkP96qO9.js} +1 -1
  63. package/dist/{packbits-DaUD6MLm-Bu1PoTGa.js → client/packbits-BlDR4Kj5-C66n1-zr.js} +1 -1
  64. package/dist/{pako.esm-C3kYPGGQ-BMki8cQY.js → client/pako.esm-CB1uQYY0-DB0PYm1P.js} +6 -12
  65. package/dist/{raw-CcGKjn8q-DFOt-i8n.js → client/raw-CMGvRjfu-BRi6E4i1.js} +1 -1
  66. package/dist/{ssrBoot-D-b4-M19.js → client/ssrBoot-DjZDIkG_.js} +1 -1
  67. package/dist/client/style.css +5 -0
  68. package/dist/client/transition-C8OQt_kp.js +34 -0
  69. package/dist/{webfontloader-CyOFAuFB.js → client/webfontloader-qotgY98I.js} +56 -92
  70. package/dist/{webimage-D2c098k3-DLj1LQxB.js → client/webimage-BM_pbLN3-L2cGWK5l.js} +1 -1
  71. package/dist/node/cli.js +20 -0
  72. package/dist/node/main.js +2 -0
  73. package/dist/node/types.d.ts +47 -0
  74. package/package.json +57 -51
  75. package/widgets/EodashDatePicker.vue +146 -40
  76. package/widgets/EodashItemFilter.vue +81 -41
  77. package/widgets/EodashLayerControl.vue +16 -0
  78. package/widgets/EodashMap.vue +186 -42
  79. package/widgets/EodashMapBtns.vue +50 -0
  80. package/widgets/ExportState.vue +112 -0
  81. package/widgets/PopUp.vue +40 -0
  82. package/widgets/WidgetsContainer.vue +47 -27
  83. package/bin/app.js +0 -22
  84. package/bin/cli.js +0 -62
  85. package/bin/main.js +0 -9
  86. package/bin/serverConfig.js +0 -165
  87. package/bin/types.d.ts +0 -52
  88. package/bin/utils.js +0 -103
  89. package/core/App.vue +0 -19
  90. package/core/SuspensedDashboard.ce.vue +0 -65
  91. package/core/asWebComponent.d.ts +0 -18
  92. package/core/asWebComponent.js +0 -12
  93. package/core/components/DashboardLayout.vue +0 -44
  94. package/core/components/DynamicWebComponent.vue +0 -68
  95. package/core/components/Header.vue +0 -14
  96. package/core/components/IframeWrapper.vue +0 -11
  97. package/core/components/Loading.vue +0 -27
  98. package/core/components/MobileLayout.vue +0 -49
  99. package/core/composables/DefineEodash.js +0 -57
  100. package/core/composables/DefineWidgets.js +0 -129
  101. package/core/composables/index.js +0 -219
  102. package/core/eodash.js +0 -100
  103. package/core/main.js +0 -2
  104. package/core/plugins/index.js +0 -18
  105. package/core/plugins/vuetify.js +0 -30
  106. package/core/render.js +0 -13
  107. package/core/store/Actions.js +0 -0
  108. package/core/store/States.js +0 -21
  109. package/core/store/index.js +0 -17
  110. package/core/store/stac.js +0 -63
  111. package/core/types.d.ts +0 -356
  112. package/core/utils/eodashSTAC.js +0 -164
  113. package/core/utils/helpers.js +0 -40
  114. package/core/utils/index.js +0 -28
  115. package/core/views/Dashboard.vue +0 -59
  116. package/core/vite-env.d.ts +0 -31
  117. package/dist/DashboardLayout-Dp8AnYD9.js +0 -141
  118. package/dist/EodashDatePicker-D_udZ26j.js +0 -1645
  119. package/dist/EodashItemFilter-BLAGx2UD.js +0 -51
  120. package/dist/EodashMap-Bxl_aqY2.js +0 -53405
  121. package/dist/Footer-AohCH8U7.js +0 -118
  122. package/dist/Header-DC50S6GR.js +0 -609
  123. package/dist/MobileLayout-CgToA7Gp.js +0 -523
  124. package/dist/VBtn-Bz7ruRUg.js +0 -1106
  125. package/dist/VMain-BHfWJU2j.js +0 -35
  126. package/dist/asWebComponent-C8rb3b1D.js +0 -11323
  127. package/dist/color-DpYEub1f.js +0 -115
  128. package/dist/deflate-Be2Arps5-hDqMz3RA.js +0 -10
  129. package/dist/dimensions-CJaGeSrj.js +0 -53
  130. package/dist/eo-dash.js +0 -6
  131. package/dist/eox-itemfilter-DcQkRD2l.js +0 -7537
  132. package/dist/eox-map-BJ9SIixs.js +0 -36205
  133. package/dist/eox-stacinfo-B-YrT7Ug.js +0 -13698
  134. package/dist/forwardRefs-Bxeu9Obx.js +0 -142
  135. package/dist/index-Sa2Vg_gx.js +0 -65
  136. package/dist/style.css +0 -5
  137. /package/dist/{.gitkeep → client/.gitkeep} +0 -0
  138. /package/dist/{_commonjsHelpers-DaMA6jEr.js → client/_commonjsHelpers-DaMA6jEr.js} +0 -0
@@ -0,0 +1,259 @@
1
+ import { Collection, Item } from "stac-js";
2
+ import { toAbsolute } from "stac-js/src/http.js";
3
+ import {
4
+ extractLayerConfig,
5
+ extractRoles,
6
+ fetchStyle,
7
+ generateFeatures,
8
+ setMapProjFromCol,
9
+ uid,
10
+ } from "./helpers";
11
+ import { registerProjection } from "@/store/Actions";
12
+ import {
13
+ createLayersFromDataAssets,
14
+ createLayersFromLinks,
15
+ } from "./createLayers";
16
+ import axios from "axios";
17
+
18
+ export class EodashCollection {
19
+ #collectionUrl = "";
20
+
21
+ /** @type {import("stac-ts").StacCollection | undefined} */
22
+ #collectionStac;
23
+
24
+ /**
25
+ * @type {import("stac-ts").StacLink
26
+ * | import("stac-ts").StacItem
27
+ * | undefined}
28
+ */
29
+ selectedItem;
30
+
31
+ /** @param {string} collectionUrl */
32
+ constructor(collectionUrl) {
33
+ this.#collectionUrl = collectionUrl;
34
+ }
35
+
36
+ /**
37
+ * @async
38
+ * @param {import('stac-ts').StacLink | Date} [linkOrDate]
39
+ * @returns
40
+ */
41
+ createLayersJson = async (linkOrDate) => {
42
+ /**
43
+ * @type {import("stac-ts").StacLink | undefined}
44
+ **/
45
+ let stacItem;
46
+
47
+ /**
48
+ * @type {import("stac-ts").StacCollection | undefined}
49
+ **/
50
+ let stac;
51
+ // TODO get auxiliary layers from collection
52
+ /** @type {Record<string,any>[]} */
53
+ let layersJson = [];
54
+
55
+ // Load collectionstac if not yet initialized
56
+ if (!this.#collectionStac) {
57
+ stac = await axios.get(this.#collectionUrl).then((resp) => resp.data);
58
+ this.#collectionStac = new Collection(stac);
59
+ }
60
+
61
+ // set availabe map projection
62
+ setMapProjFromCol(this.#collectionStac);
63
+
64
+ const isGeoDB = stac?.endpointtype === "GeoDB";
65
+
66
+ if (linkOrDate instanceof Date) {
67
+ // if collectionStac not yet initialized we do it here
68
+ stacItem = this.getItem(linkOrDate);
69
+ } else {
70
+ stacItem = linkOrDate;
71
+ }
72
+
73
+ const stacItemUrl = stacItem
74
+ ? toAbsolute(stacItem.href, this.#collectionUrl)
75
+ : this.#collectionUrl;
76
+
77
+ stac = await axios.get(stacItemUrl).then((resp) => resp.data);
78
+
79
+ if (!stacItem) {
80
+ // no specific item was requested; render last item
81
+ this.#collectionStac = new Collection(stac);
82
+ this.selectedItem = this.getItem();
83
+
84
+ if (this.selectedItem) {
85
+ layersJson = /** @type {Record<string,any>[]} */ (
86
+ await this.createLayersJson(this.selectedItem)
87
+ );
88
+ } else {
89
+ console.warn(
90
+ "[eodash] the selected collection does not include any items",
91
+ );
92
+ }
93
+ return [];
94
+ } else {
95
+ // specific item was requested
96
+ const item = new Item(stac);
97
+ this.selectedItem = item;
98
+ const title = this.#collectionStac.title || this.#collectionStac.id;
99
+ layersJson.unshift(
100
+ ...(await this.buildJsonArray(item, stacItemUrl, title, isGeoDB)),
101
+ );
102
+ return layersJson;
103
+ }
104
+ };
105
+
106
+ /**
107
+ * @param {import("stac-ts").StacItem} item
108
+ * @param {string} itemUrl
109
+ * @param {string} title
110
+ * @param {boolean} isGeoDB
111
+ * @returns {Promise<Record<string,any>[]>} arrays
112
+ * */
113
+ async buildJsonArray(item, itemUrl, title, isGeoDB) {
114
+ await registerProjection(
115
+ /** @type {number | undefined} */ (item?.["proj:epsg"]),
116
+ );
117
+
118
+ const jsonArray = [];
119
+
120
+ if (isGeoDB) {
121
+ const allFeatures = generateFeatures(this.#collectionStac?.links);
122
+
123
+ return [
124
+ {
125
+ type: "Vector",
126
+ properties: {
127
+ id: item.id,
128
+ title: this.#collectionStac?.title || item.id,
129
+ },
130
+ source: {
131
+ type: "Vector",
132
+ url: "data:," + encodeURIComponent(JSON.stringify(allFeatures)),
133
+ format: "GeoJSON",
134
+ },
135
+ style: {
136
+ "circle-radius": 5,
137
+ "circle-fill-color": "#00417077",
138
+ "circle-stroke-color": "#004170",
139
+ "fill-color": "#00417077",
140
+ "stroke-color": "#004170",
141
+ },
142
+ },
143
+ ];
144
+ }
145
+
146
+ // I propose following approach, we "manually" create configurations
147
+ // for the rendering options we know and expect.
148
+ // If we don't find any we fallback to using the STAC ol item that
149
+ // will try to extract anything it supports but for which we have
150
+ // less control.
151
+
152
+ const { layerConfig, style } = extractLayerConfig(
153
+ await fetchStyle(item, itemUrl),
154
+ );
155
+
156
+ const dataAssets = Object.keys(item?.assets ?? {}).reduce((data, ast) => {
157
+ if (item.assets[ast].roles?.includes("data")) {
158
+ data[ast] = item.assets[ast];
159
+ }
160
+ return data;
161
+ }, /** @type {Record<string,import('stac-ts').StacAsset>} */ ({}));
162
+
163
+ const isSupported =
164
+ item.links.some((link) => ["wms", "xyz"].includes(link.rel)) ||
165
+ Object.keys(dataAssets).length;
166
+
167
+ if (isSupported) {
168
+ jsonArray.push(
169
+ ...createLayersFromLinks(uid(), title, item),
170
+
171
+ ...(await createLayersFromDataAssets(
172
+ uid(),
173
+ title || this.#collectionStac?.title || item.id,
174
+ dataAssets,
175
+ style,
176
+ layerConfig,
177
+ )),
178
+ );
179
+ } else {
180
+ // fallback to STAC
181
+ const json = {
182
+ type: "STAC",
183
+ displayWebMapLink: true,
184
+ displayFootprint: false,
185
+ data: item,
186
+ properties: {
187
+ id: item.id,
188
+ title: title || item.id,
189
+ layerConfig,
190
+ },
191
+ style,
192
+ };
193
+ extractRoles(json.properties, /** @type {string[]} */ (item?.roles));
194
+ jsonArray.push(json);
195
+ }
196
+
197
+ return jsonArray;
198
+ }
199
+
200
+ getItems() {
201
+ return (
202
+ this.#collectionStac?.links
203
+ .filter((i) => i.rel === "item")
204
+ // sort by `datetime`, where oldest is first in array
205
+ .sort((a, b) =>
206
+ /** @type {number} */ (a.datetime) <
207
+ /** @type {number} */ (b.datetime)
208
+ ? -1
209
+ : 1,
210
+ )
211
+ );
212
+ }
213
+
214
+ getDates() {
215
+ return (
216
+ this.#collectionStac?.links
217
+ .filter((i) => i.rel === "item")
218
+ // sort by `datetime`, where oldest is first in array
219
+ .sort((a, b) =>
220
+ /** @type {number} */ (a.datetime) <
221
+ /** @type {number} */ (b.datetime)
222
+ ? -1
223
+ : 1,
224
+ )
225
+ .map((i) => new Date(/** @type {number} */ (i.datetime)))
226
+ );
227
+ }
228
+
229
+ async getExtent() {
230
+ if (!this.#collectionStac) {
231
+ const stac = await axios
232
+ .get(this.#collectionUrl)
233
+ .then((resp) => resp.data);
234
+ this.#collectionStac = new Collection(stac);
235
+ }
236
+ return this.#collectionStac?.extent;
237
+ }
238
+
239
+ /**
240
+ * Get closest Item Link from a certain date,
241
+ * get the latest if no date provided
242
+ * @param {Date} [date]
243
+ **/
244
+ getItem(date) {
245
+ return date
246
+ ? this.getItems()?.sort((a, b) => {
247
+ const distanceA = Math.abs(
248
+ new Date(/** @type {number} */ (a.datetime)).getTime() -
249
+ date.getTime(),
250
+ );
251
+ const distanceB = Math.abs(
252
+ new Date(/** @type {number} */ (b.datetime)).getTime() -
253
+ date.getTime(),
254
+ );
255
+ return distanceA - distanceB;
256
+ })[0]
257
+ : this.getItems()?.at(-1);
258
+ }
259
+ }
@@ -0,0 +1,152 @@
1
+ import { changeMapProjection } from "@/store/Actions";
2
+ import { availableMapProjection } from "@/store/States";
3
+ import { toAbsolute } from "stac-js/src/http.js";
4
+ import axios from "axios";
5
+
6
+ /** @param {import("stac-ts").StacLink[]} [links] */
7
+ export function generateFeatures(links) {
8
+ /**
9
+ * @type {{
10
+ * type: string;
11
+ * geometry: {
12
+ * type: string;
13
+ * coordinates: [number, number];
14
+ * };
15
+ * }[]}
16
+ */
17
+ const features = [];
18
+ links?.forEach((element) => {
19
+ if (element.rel === "item" && "latlng" in element) {
20
+ const [lat, lon] = /** @type {string} */ (element.latlng)
21
+ .split(",")
22
+ .map((it) => Number(it));
23
+ features.push({
24
+ type: "Feature",
25
+ geometry: {
26
+ type: "Point",
27
+ coordinates: [lon, lat],
28
+ },
29
+ });
30
+ }
31
+ });
32
+ const geojsonObject = {
33
+ type: "FeatureCollection",
34
+ crs: {
35
+ type: "name",
36
+ properties: {
37
+ name: "EPSG:4326",
38
+ },
39
+ },
40
+ features,
41
+ };
42
+ return geojsonObject;
43
+ }
44
+
45
+ /** @param { import("ol/layer/WebGLTile").Style & { jsonform?: Record<string,any> } } [style] */
46
+ export function extractLayerConfig(style) {
47
+ /** @type {Record<string,unknown> | undefined} */
48
+ let layerConfig = undefined;
49
+ if (style?.jsonform) {
50
+ layerConfig = { schema: style.jsonform, type: "style" };
51
+ delete style.jsonform;
52
+ }
53
+ return { layerConfig, style };
54
+ }
55
+
56
+ /**
57
+ * checks if there's a projection on the Collection and
58
+ * updates {@link availableMapProjection}
59
+ * @param {import('stac-ts').StacCollection} [STAcCollection]
60
+ */
61
+ export const setMapProjFromCol = (STAcCollection) => {
62
+ // if a projection exists on the collection level
63
+ if (STAcCollection?.["proj:epsg"]) {
64
+ if (
65
+ availableMapProjection.value &&
66
+ availableMapProjection.value !== STAcCollection?.["proj:epsg"]
67
+ ) {
68
+ changeMapProjection(
69
+ /** @type {number} */
70
+ (STAcCollection["proj:epsg"]),
71
+ );
72
+ }
73
+ // set it for `EodashMapBtns`
74
+ availableMapProjection.value = /** @type {string} */ (
75
+ STAcCollection["proj:epsg"]
76
+ );
77
+ } else {
78
+ // reset to default projection
79
+ changeMapProjection((availableMapProjection.value = ""));
80
+ }
81
+ };
82
+
83
+ /**
84
+ * Function to extract collection urls from an indicator
85
+ * @param {import("stac-ts").StacCatalog
86
+ * | import("stac-ts").StacCollection
87
+ * | import("stac-ts").StacItem
88
+ * | null
89
+ * } stacObject
90
+ * @param {string} basepath
91
+ * @returns {string[]}
92
+ */
93
+ export function extractCollectionUrls(stacObject, basepath) {
94
+ const collectionUrls = [];
95
+ // Support for two structure types, flat and indicator, simplified here:
96
+ // Flat assumes Catalog-Collection-Item
97
+ // Indicator assumes Catalog-Collection-Collection-Item
98
+ // TODO: this is not the most stable test approach,
99
+ // we should discuss potential other approaches
100
+
101
+ if (stacObject?.links && stacObject?.links[1].rel === "item") {
102
+ collectionUrls.push(basepath);
103
+ } else if (stacObject?.links[1].rel === "child") {
104
+ // TODO: Iterate through all children to create collections
105
+ stacObject.links.forEach((link) => {
106
+ if (link.rel === "child") {
107
+ collectionUrls.push(toAbsolute(link.href, basepath));
108
+ }
109
+ });
110
+ }
111
+ return collectionUrls;
112
+ }
113
+
114
+ export const uid = () =>
115
+ Date.now().toString(36) + Math.random().toString(36).substring(2);
116
+
117
+ /**
118
+ * Assign extracted roles to layer properties
119
+ * @param {Record<string,any>} properties
120
+ * @param {string[]} roles
121
+ * */
122
+ export const extractRoles = (properties, roles) => {
123
+ roles?.forEach((role) => {
124
+ if (role === "visible") {
125
+ properties.visible = true;
126
+ }
127
+ if (role === "overlay" || role === "baselayer") {
128
+ properties.group = role;
129
+ }
130
+ return properties;
131
+ });
132
+ };
133
+
134
+ /**
135
+ * @param {import("stac-ts").StacItem} item
136
+ * @param {string} itemUrl
137
+ **/
138
+ export const fetchStyle = async (item, itemUrl) => {
139
+ const styleLink = item.links.find((link) => link.rel.includes("style"));
140
+ if (styleLink) {
141
+ let url = "";
142
+ if (styleLink.href.startsWith("http")) {
143
+ url = styleLink.href;
144
+ } else {
145
+ url = toAbsolute(styleLink.href, itemUrl);
146
+ }
147
+
148
+ /** @type {import("ol/layer/WebGLTile").Style & {jsonform?:Record<string,any>}} */
149
+ const styleJson = await axios.get(url).then((resp) => resp.data);
150
+ return styleJson;
151
+ }
152
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Loads font in the app using `webfontloader`
3
+ *
4
+ * @param {string} [family]
5
+ * @param {string} [link]
6
+ * @param {boolean} [isWebComponent]
7
+ * @returns {Promise<string>} - Font family name
8
+ * @see {@link "https://github.com/typekit/webfontloader"}
9
+ */
10
+ export const loadFont = async (
11
+ family = "",
12
+ link = "",
13
+ isWebComponent = false,
14
+ ) => {
15
+ if (family && link) {
16
+ const WebFontLoader = (await import("webfontloader")).default;
17
+ WebFontLoader.load({
18
+ classes: false,
19
+ custom: {
20
+ // Use FVD notation to include families https://github.com/typekit/fvd
21
+ families: [family],
22
+ // Path to stylesheet that defines font-face
23
+ urls: [link],
24
+ },
25
+ fontactive(familyName, _fvd) {
26
+ const stylesheet = new CSSStyleSheet();
27
+ const styles = isWebComponent
28
+ ? `eo-dash {font-family: ${familyName};}`
29
+ : `* {font-family: ${familyName};}`;
30
+ stylesheet.replaceSync(styles);
31
+ document.adoptedStyleSheets.push(stylesheet);
32
+ },
33
+ fontinactive(familyName, _fvd) {
34
+ throw new Error(`error loading font: ${familyName}`);
35
+ },
36
+ });
37
+ }
38
+ return family;
39
+ };
40
+
41
+ /**
42
+ * @param {string} text
43
+ * @param {import("vue").Ref<boolean>} showIcon
44
+ **/
45
+ export const copyToClipBoard = async (text, showIcon) => {
46
+ await navigator.clipboard.writeText(text);
47
+ showIcon.value = true;
48
+ setTimeout(() => {
49
+ showIcon.value = false;
50
+ }, 2000);
51
+ };
@@ -1,6 +1,6 @@
1
1
  /**
2
- * `eodash` injection key.
3
- * @type {Symbol}
2
+ * `eodash` injection key.
3
+ *
4
4
  * @see {@link "@/plugins/index.js"}
5
5
  */
6
6
  export const eodashKey = Symbol("eodash");
@@ -0,0 +1,116 @@
1
+ <template>
2
+ <HeaderComponent ref="headerRef" v-if="!eodash.brand.noLayout" />
3
+ <ErrorAlert v-model="error" />
4
+ <Suspense>
5
+ <TemplateComponent
6
+ @vue:mounted="onTemplateMount?.(hiddenElements)"
7
+ class="template"
8
+ />
9
+ <template #fallback>
10
+ <div class="loading-container">
11
+ <Loading />
12
+ </div>
13
+ </template>
14
+ </Suspense>
15
+ <FooterComponent ref="footerRef" v-if="!eodash.brand.noLayout" />
16
+ </template>
17
+
18
+ <script setup>
19
+ import { useEodashRuntime } from "@/composables/DefineEodash";
20
+ import { useURLSearchParametersSync, useUpdateTheme } from "@/composables";
21
+ import { useSTAcStore } from "@/store/stac";
22
+ import { defineAsyncComponent, onErrorCaptured, onMounted, ref } from "vue";
23
+ import { useDisplay, useLayout } from "vuetify/lib/framework.mjs";
24
+ import { loadFont } from "@/utils";
25
+ import Loading from "@/components/Loading.vue";
26
+ import ErrorAlert from "@/components/ErrorAlert.vue";
27
+
28
+ const props = defineProps({
29
+ config: {
30
+ type: String,
31
+ },
32
+ onTemplateMount: {
33
+ type: Function,
34
+ },
35
+ });
36
+ const eodash = await useEodashRuntime(props.config);
37
+
38
+ useURLSearchParametersSync();
39
+
40
+ const theme = useUpdateTheme("dashboardTheme", eodash.brand?.theme);
41
+ theme.global.name.value = "dashboardTheme";
42
+
43
+ await loadFont(
44
+ eodash.brand?.font?.family,
45
+ eodash.brand?.font?.link,
46
+ !!props.onTemplateMount,
47
+ );
48
+
49
+ const { loadSTAC } = useSTAcStore();
50
+ await loadSTAC();
51
+
52
+ const { smAndDown } = useDisplay();
53
+ const TemplateComponent = smAndDown.value
54
+ ? defineAsyncComponent(() => import(`@/components/MobileLayout.vue`))
55
+ : defineAsyncComponent(() => import(`@/components/DashboardLayout.vue`));
56
+
57
+ const HeaderComponent = defineAsyncComponent(
58
+ () => import(`@/components/Header.vue`),
59
+ );
60
+ const FooterComponent = defineAsyncComponent(
61
+ () => import(`@/components/Footer.vue`),
62
+ );
63
+ const { mainRect } = useLayout();
64
+ const templateHeight = eodash.brand.noLayout
65
+ ? props.onTemplateMount
66
+ ? "100%"
67
+ : "90dvh"
68
+ : `calc(100dvh - ${mainRect.value["top"] + mainRect.value["bottom"]}px)`;
69
+
70
+ const headerRef = ref(null);
71
+ /**
72
+ * @type {import("vue").Ref<InstanceType<
73
+ * typeof import("@/components/Footer.vue").default
74
+ * > | null>}
75
+ */
76
+ const footerRef = ref(null);
77
+
78
+ const hiddenElements = [headerRef, footerRef];
79
+
80
+ onMounted(() => {
81
+ if (props.onTemplateMount && !eodash.brand.noLayout) {
82
+ hiddenElements.forEach((element) => {
83
+ /** @type {HTMLElement} */
84
+ (
85
+ /** @type {import("vue").ComponentPublicInstance} */
86
+ (element.value).$el
87
+ ).style.opacity = "0";
88
+ });
89
+ }
90
+ });
91
+
92
+ const error = ref("");
93
+ onErrorCaptured((e, comp, info) => {
94
+ error.value = `
95
+ ${e}.
96
+ component: ${comp?.$.type.name}.
97
+ info: ${info}.
98
+ `;
99
+ });
100
+ </script>
101
+ <style>
102
+ html {
103
+ overflow: hidden !important;
104
+ }
105
+
106
+ .template {
107
+ height: v-bind("templateHeight");
108
+ }
109
+
110
+ .loading-container {
111
+ height: 100dvh;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ }
116
+ </style>
@@ -0,0 +1,39 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module "*.vue" {
4
+ import type { DefineComponent } from "vue";
5
+ const component: DefineComponent<object, object, unknown>;
6
+ export default component;
7
+ }
8
+ declare interface Window {
9
+ eodashStore: import("@/types").EodashStore;
10
+ }
11
+ declare module "@eox/stacinfo" {
12
+ export const EOxStacInfo: CustomElementConstructor;
13
+ }
14
+ declare module "@eox/layercontrol" {
15
+ export const EOxLayerControl: CustomElementConstructor;
16
+ }
17
+ declare module "@eox/jsonform" {
18
+ export const EOxJSONForm: CustomElementConstructor;
19
+ }
20
+ declare module "@eox/map" {
21
+ export const EOxMap: CustomElementConstructor;
22
+ }
23
+ declare module "@eox/itemfilter" {
24
+ export const EOxItemFilter: CustomElementConstructor;
25
+ }
26
+ declare module "user:config" {
27
+ const eodash: import("@/types").Eodash | Promise<import("@/types").Eodash>;
28
+ export default eodash;
29
+ }
30
+ declare module "stac-js" {
31
+ export const Collection: {
32
+ new (data?: object): import("stac-ts").StacCollection;
33
+ };
34
+ export const Item: { new (data?: object): import("stac-ts").StacItem };
35
+ }
36
+ declare module "stac-js/src/http.js" {
37
+ const toAbsolute: (...args: string[]) => string;
38
+ export { toAbsolute };
39
+ }