@eodash/eodash 5.0.0-alpha.2.4 → 5.0.0-alpha.2.6

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 (80) hide show
  1. package/README.md +31 -7
  2. package/core/client/App.vue +6 -7
  3. package/core/client/SuspensedDashboard.ce.vue +59 -45
  4. package/core/client/asWebComponent.d.ts +10 -5
  5. package/core/client/asWebComponent.js +6 -6
  6. package/core/client/components/DashboardLayout.vue +63 -21
  7. package/core/client/components/DynamicWebComponent.vue +44 -44
  8. package/core/client/components/ErrorAlert.vue +24 -7
  9. package/core/client/components/Footer.vue +34 -15
  10. package/core/client/components/Header.vue +10 -5
  11. package/core/client/components/IframeWrapper.vue +4 -4
  12. package/core/client/components/Loading.vue +17 -18
  13. package/core/client/components/MobileLayout.vue +82 -29
  14. package/core/client/composables/DefineEodash.js +38 -28
  15. package/core/client/composables/DefineWidgets.js +105 -79
  16. package/core/client/composables/index.js +43 -141
  17. package/core/client/eodash.js +46 -39
  18. package/core/client/main.js +2 -2
  19. package/core/client/plugins/index.js +11 -9
  20. package/core/client/plugins/vuetify.js +9 -10
  21. package/core/client/render.js +4 -5
  22. package/core/client/store/States.js +8 -13
  23. package/core/client/store/index.js +14 -11
  24. package/core/client/store/stac.js +51 -37
  25. package/core/client/types.d.ts +173 -248
  26. package/core/client/utils/eodashSTAC.js +151 -66
  27. package/core/client/utils/helpers.js +18 -20
  28. package/core/client/utils/index.js +25 -14
  29. package/core/client/utils/keys.js +2 -2
  30. package/core/client/views/Dashboard.vue +70 -42
  31. package/core/client/vite-env.d.ts +19 -17
  32. package/dist/client/DashboardLayout-BuDcv6LM.js +156 -0
  33. package/dist/client/{DynamicWebComponent-C4Hotc4H.js → DynamicWebComponent-BEP4rVce.js} +7 -7
  34. package/dist/client/EodashDatePicker-oFb1zt5E.js +1211 -0
  35. package/dist/client/EodashItemFilter-BElmgrST.js +63 -0
  36. package/dist/client/{EodashMap-CGrQjZ1P.js → EodashMap-DXyOgcEd.js} +11333 -14025
  37. package/dist/client/Footer-CoPx6UXQ.js +115 -0
  38. package/dist/client/Header-C-zX31Ys.js +635 -0
  39. package/dist/client/{IframeWrapper-Cg3GMmfW.js → IframeWrapper-2w2ye0zM.js} +4 -4
  40. package/dist/client/MobileLayout-C9OVcP12.js +945 -0
  41. package/dist/client/{VMain-BHYlmRic.js → VMain-Dm43jd43.js} +8 -8
  42. package/dist/client/{WidgetsContainer-dje9QSk0.js → WidgetsContainer-BS87sLqk.js} +12 -5
  43. package/dist/client/asWebComponent-CpQUVi2N.js +20135 -0
  44. package/dist/client/{basedecoder-Qm25PwVp-CHo5Pomv.js → basedecoder-DHcBySSe-BmCFNFnw.js} +5 -6
  45. package/dist/client/{decoder-HRvnjnEI-BQ2rajuJ.js → decoder-CP4lv0Kb-BHrv68IA.js} +1 -1
  46. package/dist/client/deflate-BXt-9JA_-CWfClgpK.js +10 -0
  47. package/dist/client/eo-dash.js +3 -3
  48. package/dist/client/eodashSTAC-Q7kbX1Gy.js +2788 -0
  49. package/dist/client/{eox-itemfilter-DcQkRD2l.js → eox-itemfilter-TaBxgqq_.js} +1002 -974
  50. package/dist/client/{eox-map-C3DL31fp.js → eox-map-L7abwKTR.js} +5677 -5695
  51. package/dist/client/forwardRefs-BVFQ82G4.js +183 -0
  52. package/dist/client/{index-CaDDfJYE.js → index-dOzyv_xR.js} +43 -74
  53. package/dist/client/{jpeg-DNfUpLwy-Fjan-04T.js → jpeg-BAgeD1d3-oeHbFPUL.js} +5 -6
  54. package/dist/client/{lerc-_E46UbWQ-Beu35ovS.js → lerc-DzVumYtB-rm1Xco54.js} +5 -7
  55. package/dist/client/{lzw-BOMhmEDy-Dboc93VO.js → lzw-LAGDNbSC-DkP96qO9.js} +1 -1
  56. package/dist/client/{packbits-DaUD6MLm-Bu1PoTGa.js → packbits-BlDR4Kj5-C66n1-zr.js} +1 -1
  57. package/dist/client/{pako.esm-C3kYPGGQ-BMki8cQY.js → pako.esm-CB1uQYY0-DB0PYm1P.js} +6 -12
  58. package/dist/client/{raw-CcGKjn8q-DFOt-i8n.js → raw-CMGvRjfu-BRi6E4i1.js} +1 -1
  59. package/dist/client/{ssrBoot-Dd7m-btU.js → ssrBoot-L9KejErM.js} +3 -3
  60. package/dist/client/style.css +2 -2
  61. package/dist/client/transition-DCePIwYR.js +34 -0
  62. package/dist/client/{webfontloader-CyOFAuFB.js → webfontloader-qotgY98I.js} +56 -92
  63. package/dist/client/{webimage-D2c098k3-DLj1LQxB.js → webimage-BM_pbLN3-L2cGWK5l.js} +1 -1
  64. package/dist/node/cli.js +3 -3
  65. package/dist/node/types.d.ts +32 -38
  66. package/package.json +13 -14
  67. package/widgets/EodashDatePicker.vue +145 -41
  68. package/widgets/EodashItemFilter.vue +41 -22
  69. package/widgets/EodashMap.vue +87 -20
  70. package/widgets/WidgetsContainer.vue +45 -27
  71. package/dist/client/DashboardLayout-ZaSRMD1M.js +0 -149
  72. package/dist/client/EodashDatePicker-C4kKjxKy.js +0 -1653
  73. package/dist/client/EodashItemFilter-cBHC0YEM.js +0 -51
  74. package/dist/client/Footer-pS636dEP.js +0 -118
  75. package/dist/client/Header-DQuaLdjl.js +0 -605
  76. package/dist/client/MobileLayout-BLXFBWI_.js +0 -987
  77. package/dist/client/asWebComponent-Bvb3xkxI.js +0 -13311
  78. package/dist/client/deflate-Be2Arps5-hDqMz3RA.js +0 -10
  79. package/dist/client/forwardRefs-Bxeu9Obx.js +0 -142
  80. package/dist/client/index-DlNICb3T.js +0 -34
@@ -1,57 +1,161 @@
1
1
  <template>
2
- <span class="fill-height fill-width align-center justify-center">
3
- <div v-if="inline" class="fill-height fill-width">
4
-
5
- <v-text-field ref="inlineDatePicker" base-color="primary" class="fill-height fill-width pa-2 align-center"
6
- type="date" bg-color="surface" color="primary" density="comfortable" label="Select Date" v-model="currentDate"
7
- variant="plain" hide-details />
8
- </div>
9
-
10
- <v-date-picker v-else ref="datePicker" :width="width" :height="height" hide-header v-model="currentDate"
11
- color="primary" bg-color="surface" location="center" class="overflow-auto fill-height fill-width"
12
- position="relative" show-adjacent-months></v-date-picker>
13
- </span>
2
+ <VCDatePicker v-model="currentDate" :masks="masks" :attributes="attributes">
3
+ <template #default="{ inputValue, inputEvents }">
4
+ <div
5
+ class="flex rounded-lg border border-gray-300 dark:border-gray-600"
6
+ style="margin: 2px"
7
+ >
8
+ <input
9
+ :value="inputValue"
10
+ v-on="inputEvents"
11
+ style="margin: 1px"
12
+ class="flex-grow px-1 py-1 bg-white dark:bg-gray-700"
13
+ />
14
+ </div>
15
+ </template>
16
+ </VCDatePicker>
17
+ <v-row align="center" justify="center" style="margin-top: 6px">
18
+ <v-btn
19
+ style="padding: 0px; margin-right: 4px"
20
+ density="compact"
21
+ v-tooltip:bottom="'Set date to oldest available dataset'"
22
+ @click="jumpDate(true)"
23
+ >
24
+ <v-icon :icon="[mdiRayEndArrow]" />
25
+ </v-btn>
26
+ <v-btn
27
+ style="padding: 0px; margin-left: 4px"
28
+ density="compact"
29
+ v-tooltip:bottom="'Set date to latest available dataset'"
30
+ @click="jumpDate(false)"
31
+ >
32
+ <v-icon :icon="[mdiRayStartArrow]" />
33
+ </v-btn>
34
+ </v-row>
14
35
  </template>
36
+
15
37
  <script setup>
16
- import { computed, ref, onMounted } from "vue";
17
- import { datetime } from "@/store/States"
38
+ import { DatePicker as VCDatePicker } from "v-calendar";
39
+ import "v-calendar/style.css";
40
+ import { computed, ref, onMounted, watch, inject } from "vue";
41
+ import { eodashKey } from "@/utils/keys";
42
+ import { toAbsolute } from "stac-js/src/http.js";
43
+ import { storeToRefs } from "pinia";
44
+ import { useSTAcStore } from "@/store/stac";
45
+ import { datetime } from "@/store/States";
46
+ import { mdiRayStartArrow, mdiRayEndArrow } from "@mdi/js";
47
+ import { extractCollectionUrls } from "@/utils/eodashSTAC";
18
48
 
19
- const props = defineProps({
20
- inline: {
21
- type: Boolean
49
+ /**
50
+ * @param {boolean} reverse
51
+ */
52
+ function jumpDate(reverse) {
53
+ if (attributes.value && attributes.value.length > 0) {
54
+ // We have potentially multiple collections we need to iterate (currently only one)
55
+ let latestDateMS = reverse ? Infinity : -Infinity;
56
+ attributes.value.forEach((coll) => {
57
+ if (coll?.dates) {
58
+ coll.dates.forEach((d) => {
59
+ // TODO: we need to handle time ranges and other options here
60
+ if (d instanceof Date) {
61
+ if (
62
+ (!reverse && d.getTime() > latestDateMS) ||
63
+ (reverse && d.getTime() < latestDateMS)
64
+ ) {
65
+ latestDateMS = d.getTime();
66
+ }
67
+ }
68
+ });
69
+ }
70
+ });
71
+ if (latestDateMS !== 0) {
72
+ currentDate.value = new Date(latestDateMS);
73
+ }
22
74
  }
23
- })
75
+ }
76
+
77
+ const eodashConfig = /** @type {import("@/types").Eodash} */ inject(eodashKey);
78
+
79
+ const masks = ref({
80
+ input: "YYYY-MM-DD",
81
+ });
82
+
83
+ /**
84
+ * Attributes displayed on datepicker
85
+ *
86
+ * @type {import("vue").Ref<
87
+ * (
88
+ * | import("v-calendar/dist/types/src/utils/attribute").AttributeConfig
89
+ * | undefined
90
+ * )[]
91
+ * >}
92
+ */
93
+ const attributes = ref([]);
24
94
 
25
95
  const currentDate = computed({
26
96
  get() {
27
- return props.inline ? datetime.value.split("T")[0] : new Date(datetime.value) ?? new Date()
97
+ return datetime.value ? new Date(datetime.value) : new Date();
28
98
  },
29
99
  /** @param {Date | string} updatedDate */
30
100
  set(updatedDate) {
31
- if (props.inline) {
32
- updatedDate = new Date(updatedDate);
33
- }
34
- //@ts-expect-error
35
- if (updatedDate instanceof Date && !isNaN(updatedDate)) {
36
- datetime.value = new Date(updatedDate.getTime() - updatedDate.getTimezoneOffset() * 60000).toISOString()
101
+ if (updatedDate instanceof Date && !isNaN(updatedDate.getTime())) {
102
+ datetime.value = new Date(
103
+ updatedDate.getTime() - updatedDate.getTimezoneOffset() * 60000,
104
+ ).toISOString();
37
105
  } else {
38
- datetime.value = new Date().toISOString()
106
+ datetime.value = new Date().toISOString();
39
107
  }
40
- }
108
+ },
41
109
  });
42
-
43
- /**
44
- * @type {import("vue").Ref<import("vuetify/components").VDatePicker | null>}
45
- **/
46
- const datePicker = ref(null)
47
- /** @type {import("vue").Ref<string|undefined>} */
48
- const width = ref()
49
- /** @type {import("vue").Ref<string|undefined>} */
50
- const height = ref()
110
+ /** @type {import("@/types").WebComponentProps["onMounted"]} */
51
111
  onMounted(() => {
52
- /** @type {HTMLElement} */
53
- const parentEl = datePicker.value?.$el.parentElement?.parentElement
54
- width.value = parentEl?.clientWidth ? parentEl.clientWidth + "px" : undefined
55
- height.value = parentEl?.clientHeight ? parentEl.clientHeight + "px" : undefined
56
- })
112
+ const { selectedStac } = storeToRefs(useSTAcStore());
113
+ watch(
114
+ [selectedStac],
115
+ async ([updatedStac]) => {
116
+ if (updatedStac) {
117
+ const parentCollUrl = toAbsolute(
118
+ `./${updatedStac.id}/collection.json`,
119
+ eodashConfig.stacEndpoint,
120
+ );
121
+ const collectionUrls = extractCollectionUrls(
122
+ selectedStac.value,
123
+ parentCollUrl,
124
+ );
125
+ const wongPalette = [
126
+ "#009E73",
127
+ "#0072B2",
128
+ "#E69F00",
129
+ "#CC79A7",
130
+ "#56B4E9",
131
+ "#D55E00",
132
+ ];
133
+ for (let idx = 0; idx < collectionUrls.length; idx++) {
134
+ const stacCollection = await (
135
+ await fetch(collectionUrls[idx])
136
+ ).json();
137
+ const dates = stacCollection.links
138
+ .filter(
139
+ (/** @type {{ rel: string; datetime: string }} */ item) =>
140
+ item.rel === "item" && "datetime" in item,
141
+ )
142
+ .map(
143
+ (/** @type {{ datetime: string }} */ it) => new Date(it.datetime),
144
+ );
145
+ attributes.value = [
146
+ {
147
+ bar: {
148
+ style: {
149
+ backgroundColor: wongPalette[idx % wongPalette.length],
150
+ },
151
+ },
152
+ dates,
153
+ },
154
+ ];
155
+ }
156
+ }
157
+ },
158
+ { immediate: true },
159
+ );
160
+ });
57
161
  </script>
@@ -1,9 +1,13 @@
1
1
  <template>
2
- <DynamicWebComponent :link="link" tag-name="eox-itemfilter" :properties="properties" :on-mounted="onMounted" />
2
+ <DynamicWebComponent
3
+ :link="link"
4
+ tag-name="eox-itemfilter"
5
+ :properties="properties"
6
+ :on-mounted="onMounted"
7
+ />
3
8
  </template>
4
9
  <script setup>
5
10
  import DynamicWebComponent from "@/components/DynamicWebComponent.vue";
6
- import { indicator } from "@/store/States";
7
11
 
8
12
  const link = () => import("@eox/itemfilter");
9
13
 
@@ -15,43 +19,58 @@ const properties = {
15
19
  keys: ["title", "themes"],
16
20
  title: "Search",
17
21
  type: "text",
18
- expanded: true,
22
+ // expanded: true,
19
23
  },
20
24
  {
21
25
  key: "themes",
22
- title: "Theme",
26
+ title: "Theme Filter",
23
27
  type: "multiselect",
24
- featured: true,
28
+ // featured: true,
29
+ // expanded: true
25
30
  },
26
31
  ],
27
32
  aggregateResults: "themes",
28
33
  enableHighlighting: true,
34
+ expandMultipleFilters: false,
35
+ expandMultipleResults: false,
29
36
  },
30
37
  };
31
38
 
32
- /** @type {import("@/types").WebComponentProps["onMounted"]}*/
39
+ /** @type {import("@/types").WebComponentProps["onMounted"]} */
33
40
  const onMounted = (el, store) => {
41
+ /** @type {any} */ (el).style.height = "100%";
42
+
43
+ const style = document.createElement("style");
44
+ style.innerHTML = `
45
+ section {
46
+ margin: 0 !important;
47
+ }
48
+ section button#filter-reset {
49
+ padding: 0 8px;
50
+ top: 8px;
51
+ right: 8px;
52
+ }
53
+ `;
54
+ el?.shadowRoot?.appendChild(style);
55
+
56
+ const filterstitle = document.createElement("div");
57
+ filterstitle.setAttribute("slot", "filterstitle");
58
+ filterstitle.innerHTML = `<h4 style="margin: 14px 8px">Indicators</h4>`;
59
+ /** @type {any} */ (el).appendChild(filterstitle);
60
+ const resultstitle = document.createElement("div");
61
+ resultstitle.setAttribute("slot", "resultstitle");
62
+ /** @type {any} */ (el).appendChild(resultstitle);
63
+
34
64
  /**
35
65
  * @typedef {object} Item
36
66
  * @property {string} href
37
- * */
67
+ */
38
68
  /** @type {any} */ (el).apply(
39
- // Only list child elements in list
40
- store.stac?.filter((item) => item.rel === "child")
41
- );
42
- // Check if selected indicator was already set in store
43
- if (indicator && indicator.value !== "") {
44
- const match = store.stac?.find((item) => item.id === indicator.value);
45
- if (match) {
46
- //@ts-expect-error
47
- (el).selectedResult = match;
48
- store.loadSelectedSTAC(match.href);
49
- }
50
- }
69
+ // Only list child elements in list
70
+ store.stac?.filter((item) => item.rel === "child"),
71
+ );
51
72
  /** @type {any} */ (el).config.onSelect =
52
- /**
53
- * @param {Item} item
54
- * */
73
+ /** @param {Item} item */
55
74
  async (item) => {
56
75
  console.log(item);
57
76
  await store.loadSelectedSTAC(item.href);
@@ -1,11 +1,16 @@
1
1
  <template>
2
- <DynamicWebComponent :link="link" tag-name="eox-map" :properties="properties" :on-mounted="onMounted"
3
- :on-unmounted="onUnmounted" />
2
+ <DynamicWebComponent
3
+ :link="link"
4
+ tag-name="eox-map"
5
+ :properties="properties"
6
+ :on-mounted="onMounted"
7
+ :on-unmounted="onUnmounted"
8
+ />
4
9
  </template>
5
10
  <script setup>
6
11
  import { inject, watch } from "vue";
7
12
  import { toAbsolute } from "stac-js/src/http.js";
8
- import { EodashCollection } from "@/utils/eodashSTAC";
13
+ import { EodashCollection, extractCollectionUrls } from "@/utils/eodashSTAC";
9
14
  import { eodashKey } from "@/utils/keys";
10
15
  import { datetime, mapPosition } from "@/store/States";
11
16
  import DynamicWebComponent from "@/components/DynamicWebComponent.vue";
@@ -14,26 +19,53 @@ import "@eox/map/dist/eox-map-advanced-layers-and-sources.js";
14
19
 
15
20
  const eodashConfig = /** @type {import("@/types").Eodash} */ inject(eodashKey);
16
21
 
17
- /** @type {Record<string,unknown>} */
22
+ /** @type {Record<string, unknown>} */
18
23
  const properties = {
19
24
  class: "fill-height fill-width overflow-none",
20
25
  center: [15, 48],
21
- layers: [{ type: "Tile", source: { type: "OSM" } }],
26
+ zoom: 4,
27
+ // TODO: we should probably introduce some way of defining
28
+ layers: [
29
+ {
30
+ type: "Vector",
31
+ source: {
32
+ type: "Vector",
33
+ url: "https://openlayers.org/data/vector/ecoregions.json",
34
+ format: "GeoJSON",
35
+ },
36
+ },
37
+ {
38
+ type: "Tile",
39
+ properties: {
40
+ id: "osm",
41
+ title: "Background",
42
+ },
43
+ source: {
44
+ type: "OSM",
45
+ },
46
+ },
47
+ ],
22
48
  };
23
49
  // Check if selected indicator was already set in store
24
50
  if (mapPosition && mapPosition.value && mapPosition.value.length === 3) {
25
51
  // TODO: do further checks for invalid values?
52
+ // TODO: can we expect the values to be in a specific projection
26
53
  properties.center = [mapPosition.value?.[0], mapPosition.value[1]];
27
54
  properties.zoom = mapPosition.value[2];
28
55
  }
29
56
 
30
57
  const link = () => import("@eox/map");
31
58
 
32
- /** @type {import("openlayers").EventsListenerFunctionType}*/
59
+ /** @type {import("openlayers").EventsListenerFunctionType} */
33
60
  const handleMoveEnd = (evt) => {
34
61
  const map = /** @type {import("openlayers").Map | undefined} */ (
35
- /** @type {*} */ (evt).map
62
+ /** @type {any} */ (evt).map
36
63
  );
64
+ /*
65
+ const currentProj = map?.getView().getProjection();
66
+ const transFunc = getTransform(currentProj?.getCode(), 'EPSG:4326');
67
+ const [x, y] = transFunc(map?.getView().getCenter() ?? [0, 0], undefined, undefined);
68
+ */
37
69
  const [x, y] = map?.getView().getCenter() ?? [0, 0];
38
70
  const z = map?.getView().getZoom();
39
71
  if (!Number.isNaN(x) && !Number.isNaN(y) && !Number.isNaN(z)) {
@@ -45,7 +77,6 @@ const handleMoveEnd = (evt) => {
45
77
  const onMounted = (el, store) => {
46
78
  /** @type {any} */
47
79
  (el)?.map?.on("moveend", handleMoveEnd);
48
-
49
80
  const { selectedStac } = storeToRefs(store);
50
81
 
51
82
  watch(
@@ -54,23 +85,59 @@ const onMounted = (el, store) => {
54
85
  if (updatedStac) {
55
86
  const parentCollUrl = toAbsolute(
56
87
  `./${updatedStac.id}/collection.json`,
57
- eodashConfig.stacEndpoint
58
- );
59
- const childCollUrl = toAbsolute(
60
- updatedStac.links[1].href,
61
- parentCollUrl
88
+ eodashConfig.stacEndpoint,
62
89
  );
63
- const eodash = new EodashCollection(childCollUrl);
64
- if (updatedTime) {
65
- /** @type {any} */ (el).layers = await eodash.createLayersJson(
66
- new Date(updatedTime)
90
+ const collectionUrls = extractCollectionUrls(
91
+ selectedStac.value,
92
+ parentCollUrl,
67
93
  );
68
- } else {
69
- /** @type {any} */ (el).layers = await eodash.createLayersJson();
94
+ /** @type {import("@/utils/eodashSTAC").EodashCollection[]} */
95
+ const eodashCollections = [];
96
+ collectionUrls.forEach((cu) => {
97
+ eodashCollections.push(new EodashCollection(cu));
98
+ });
99
+ const layersCollection = [];
100
+ for (let idx = 0; idx < eodashCollections.length; idx++) {
101
+ const ec = eodashCollections[idx];
102
+ let layers;
103
+ if (updatedTime) {
104
+ layers = await ec.createLayersJson(new Date(updatedTime));
105
+ } else {
106
+ layers = await ec.createLayersJson();
107
+ }
108
+ if (layers) {
109
+ layersCollection.push(...layers);
110
+ }
70
111
  }
112
+ // TODO: add base layers and overlays as defined in the top collection / indicator
113
+ // Probably best also to introduce background and overlay groups
114
+ // For now adding OSM as background
115
+ layersCollection.push({
116
+ type: "Tile",
117
+ properties: {
118
+ id: "osm",
119
+ title: "Background",
120
+ },
121
+ source: {
122
+ type: "OSM",
123
+ },
124
+ });
125
+
126
+ // TODO: we can check if the collection / indicator has a specific
127
+ // projection it wants to be displayed in the map we can register
128
+ // and set the attribute here, e.g. like following
129
+ /*
130
+ (el)?.registerProjection(
131
+ 'EPSG:3031','+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +type=crs'
132
+ );
133
+ (el)?.projection = "EPSG:3031";
134
+ */
135
+
136
+ /** @type {any} */
137
+ (el).layers = layersCollection;
71
138
  }
72
139
  },
73
- { immediate: true }
140
+ { immediate: true },
74
141
  );
75
142
  };
76
143
 
@@ -1,6 +1,12 @@
1
1
  <template>
2
- <details is="animated-details" v-for="mod, idx in importedWidgets" ref="detailsEls" :key="idx" class="overflow-auto"
3
- exclusive>
2
+ <details
3
+ is="animated-details"
4
+ v-for="(mod, idx) in importedWidgets"
5
+ ref="detailsEls"
6
+ :key="idx"
7
+ class="overflow-auto"
8
+ exclusive
9
+ >
4
10
  <summary ref="summaryEls">{{ mod.value.title }}</summary>
5
11
  <span :style="{ height: widgetHeight }" class="d-flex flex-column">
6
12
  <component :is="mod.value.component" v-bind="mod.value.props" />
@@ -8,41 +14,53 @@
8
14
  </details>
9
15
  </template>
10
16
  <script setup>
11
- import { useDefineWidgets } from '@/composables/DefineWidgets';
12
- import { nextTick, onMounted } from 'vue';
13
- import { ref } from 'vue';
14
- import { useLayout } from 'vuetify/lib/framework.mjs';
15
- import 'animated-details'
17
+ import { useDefineWidgets } from "@/composables/DefineWidgets";
18
+ import { nextTick, onMounted } from "vue";
19
+ import { ref } from "vue";
20
+ import { useLayout } from "vuetify/lib/framework.mjs";
21
+ import "animated-details";
16
22
 
17
23
  const props = defineProps({
18
24
  widgets: {
19
- /** @type {import('vue').PropType<Omit<import("@/types").Widget,'layout'>[]>} */
25
+ /**
26
+ * @type {import("vue").PropType<
27
+ * Omit<import("@/types").Widget, "layout">[]
28
+ * >}
29
+ */
20
30
  type: Array,
21
31
  required: true,
22
- }
23
- })
32
+ },
33
+ });
24
34
 
25
- const importedWidgets = useDefineWidgets(props.widgets)
35
+ const importedWidgets = useDefineWidgets(props.widgets);
26
36
 
27
37
  /**
28
- * details elements template ref
29
- * @type {import('vue').Ref<HTMLDetailsElement[]>}
30
- **/
31
- const detailsEls = ref([])
38
+ * Details elements template ref
39
+ *
40
+ * @type {import("vue").Ref<HTMLDetailsElement[]>}
41
+ */
42
+ const detailsEls = ref([]);
32
43
  /**
33
- * summary elements template ref
34
- * @type {import('vue').Ref<HTMLDetailsElement[]>}
35
- **/
36
- const summaryEls = ref([])
37
- const widgetHeight = ref('')
38
- const summariesHeights = ref(0)
44
+ * Summary elements template ref
45
+ *
46
+ * @type {import("vue").Ref<HTMLDetailsElement[]>}
47
+ */
48
+ const summaryEls = ref([]);
49
+ const widgetHeight = ref("");
50
+ const summariesHeights = ref(0);
39
51
 
40
-
41
- const { mainRect } = useLayout()
52
+ const { mainRect } = useLayout();
42
53
  onMounted(async () => {
43
54
  await nextTick(() => {
44
- summariesHeights.value = summaryEls.value.reduce((acc, el) => acc += el.clientHeight, 0)
45
- widgetHeight.value = ((detailsEls.value[0].parentElement?.scrollHeight ?? 0) - summariesHeights.value - mainRect.value['top']) + 'px'
46
- })
47
- })
55
+ summariesHeights.value = summaryEls.value.reduce(
56
+ (acc, el) => (acc += el.clientHeight),
57
+ 0,
58
+ );
59
+ widgetHeight.value =
60
+ (detailsEls.value[0].parentElement?.scrollHeight ?? 0) -
61
+ summariesHeights.value -
62
+ mainRect.value["top"] +
63
+ "px";
64
+ });
65
+ });
48
66
  </script>