@eodash/eodash 5.0.0-alpha.1.14 → 5.0.0-alpha.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/App.vue CHANGED
@@ -8,7 +8,16 @@
8
8
 
9
9
  <!-- loading state -->
10
10
  <template #fallback>
11
- Loading...
11
+ <v-row class="d-flex justify-center align-center ">
12
+ <v-col class="flex-column justify-center align-center">
13
+ <Suspense>
14
+ <component v-if="loading.component" :is="loading.component" v-bind="loading.props"></component>
15
+ <div v-else class="text-center">
16
+ Loading...
17
+ </div>
18
+ </Suspense>
19
+ </v-col>
20
+ </v-row>
12
21
  </template>
13
22
  </Suspense>
14
23
  </template>
@@ -17,5 +26,11 @@
17
26
  </template>
18
27
 
19
28
  <script setup>
20
- //
29
+ import { inject } from 'vue';
30
+ import { eodashKey } from './store/Keys';
31
+ import { useDefineWidgets } from './composables/DefineWidgets';
32
+
33
+ const eodash = /** @type {import("@/types").Eodash} */ (inject(eodashKey))
34
+
35
+ const [loading] = useDefineWidgets([eodash.template.loading])
21
36
  </script>
@@ -7,8 +7,8 @@
7
7
  <eox-layout-item v-for="(config, idx) in widgetsConfig" ref="itemEls" :key="idx" class="custom-widget"
8
8
  :x="config.layout.x" :y="config.layout.y" :h="config.layout.h" :w="config.layout.w">
9
9
 
10
- <v-btn position="absolute" variant="tonal" :style="slideBtns[idx].style" class="slide-btn"
11
- @click="slideInOut(idx)">
10
+ <v-btn v-if="slideBtns[idx].enabled" position="absolute" variant="tonal" :style="slideBtns[idx].style"
11
+ class="slide-btn" @click="slideInOut(idx)">
12
12
  <v-icon :icon="slideBtns[idx].active ? slideBtns[idx].icon.in : slideBtns[idx].icon.out" />
13
13
  </v-btn>
14
14
  <component :key="importedWidgets[idx].value.id" :is="importedWidgets[idx].value.component"
@@ -43,6 +43,7 @@ const { slideBtns, slideInOut } = useSlidePanels(itemEls, widgetsConfig)
43
43
  </script>
44
44
  <style scoped>
45
45
  eox-layout-item {
46
+ border-radius: 0px;
46
47
  background: rgb(var(--v-theme-surface))
47
48
  }
48
49
 
@@ -2,10 +2,13 @@
2
2
  <v-footer ref="footer" :height="mdAndDown ? '48px' : 'auto'" color="secondary" app
3
3
  class="d-flex justify-space-between">
4
4
  <p class="pt-0 footer-text">
5
- Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet. Mauris cursus commodo interdum.
5
+ {{ eodash.brand.footerText ?? "" }}
6
6
  </p>
7
7
  <div class="footer-text">
8
- {{ new Date().getFullYear() }} — <strong>{{ title }}</strong>
8
+ <a href="https://github.com/eodash/eodash" target="_blank">eodash</a> by
9
+ <a href="https://eox.at" target="_blank">
10
+ <img :src='`data:image/svg+xml;base64,${base64Logo}`' height="11px">
11
+ </a>
9
12
  </div>
10
13
  </v-footer>
11
14
  </template>
@@ -22,11 +25,16 @@ import { useDisplay } from 'vuetify/lib/framework.mjs';
22
25
  const footer = ref(null)
23
26
  const eodash = /** @type {import("@/types").Eodash} */(inject(eodashKey))
24
27
 
25
- const title = eodash.brand?.shortName ?? eodash.brand?.name
26
28
  const { mdAndDown } = useDisplay()
29
+ const eoxLogo = `<svg width="100%" height="100%" viewBox="0 0 355 85" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><g id="ink_ext_XXXXXX"><path id="path5076" d="M152.986,40.52l-0.75,-0.019l-0.737,-0.056l-0.725,-0.093l-0.713,-0.127l-0.7,-0.162l-0.7,-0.196l-0.675,-0.228l-0.65,-0.261l-0.65,-0.292l-0.625,-0.319l-0.612,-0.352l-0.588,-0.377l-0.562,-0.407l-0.55,-0.431l-0.538,-0.457l-0.5,-0.481l-0.487,-0.505l-0.45,-0.528l-0.438,-0.55l-0.4,-0.57l-0.375,-0.59l-0.35,-0.609l-0.325,-0.627l-0.287,-0.645l-0.263,-0.66l-0.225,-0.676l-0.2,-0.69l-0.162,-0.704l-0.125,-0.717l-0.1,-0.728l-0.05,-0.739l-0.025,-0.748c0,-8.023 6.512,-14.532 14.537,-14.532c8.038,0 14.538,6.509 14.538,14.532c0,8.036 -6.5,14.544 -14.538,14.544Z" style="fill:none;"/><path id="path5078" d="M165.748,-0.002c-42.009,0 -76.06,18.985 -76.06,42.402c0,13.268 10.921,25.102 28.021,32.875c-8.081,-5.487 -13.403,-12.973 -14.584,-21.859c-2.685,-20.186 16.83,-40.82 45.148,-49.615c-14.687,6.665 -24.923,21.427 -24.923,38.599c0,23.218 18.648,42.046 41.773,42.383c-0.037,0.005 -0.087,0.015 -0.137,0.02c0.263,0 0.512,0.009 0.762,0.009c42.013,0 76.076,-18.984 76.076,-42.412c0,-13.261 -10.937,-25.097 -28.037,-32.871l0.75,0.522l0.736,0.531l0.713,0.543l0.7,0.555l0.687,0.566l0.664,0.578l0.649,0.588l0.625,0.6l0.613,0.609l0.588,0.621l0.574,0.631l0.562,0.643l0.538,0.652l0.513,0.662l0.5,0.672l0.475,0.684l0.449,0.693l0.438,0.703l0.425,0.713l0.387,0.723l0.375,0.73l0.352,0.74l0.336,0.75l0.3,0.76l0.287,0.77l0.264,0.777l0.25,0.787l0.211,0.795l0.188,0.805l0.175,0.812l0.151,0.82l0.125,0.831c2.675,20.19 -16.838,40.825 -45.151,49.619c14.688,-6.665 24.926,-21.426 24.926,-38.614c0,-23.202 -18.65,-42.026 -41.775,-42.367c0.05,-0.005 0.1,-0.015 0.15,-0.025c-0.262,0 -0.526,-0.01 -0.789,-0.01Zm-13.248,11.314c7.817,0 14.25,6.433 14.25,14.25c0,0.001 0,0.001 0,0.001c0,7.817 -6.433,14.249 -14.25,14.249c-7.817,0 -14.25,-6.432 -14.25,-14.249c0,-0.001 0,-0.001 0,-0.001c0,-7.817 6.433,-14.25 14.25,-14.25Z" style="fill:#fff;fill-rule:nonzero;"/><path id="path5080" d="M213.786,9.529l0.75,0.521l0.738,0.532l0.712,0.544l0.7,0.555l0.688,0.566l0.662,0.577l0.65,0.588l0.625,0.6l0.613,0.61l0.587,0.62l0.575,0.631l0.563,0.643l0.537,0.652l0.513,0.663l0.5,0.672l0.475,0.684l0.45,0.692l0.437,0.703l0.425,0.712l0.388,0.723l0.375,0.731l0.35,0.741l0.337,0.75l0.3,0.76l0.288,0.769l0.262,0.777l0.25,0.786l0.213,0.797l0.187,0.804l0.175,0.812l0.15,0.821l0.125,0.83c2.675,20.19 -16.837,40.825 -45.15,49.619c14.688,-6.665 24.925,-21.426 24.925,-38.614c0,-23.202 -18.65,-42.025 -41.775,-42.367c0.05,-0.005 0.1,-0.015 0.15,-0.025c-0.262,0 -0.525,-0.01 -0.787,-0.01c-42.01,0 -76.062,18.985 -76.062,42.402c0,13.268 10.922,25.103 28.022,32.876c-8.081,-5.487 -13.403,-12.973 -14.584,-21.859c-2.685,-20.187 16.831,-40.82 45.149,-49.615c-14.688,6.665 -24.925,21.426 -24.925,38.598c0,23.218 18.65,42.046 41.775,42.383c-0.038,0.005 -0.088,0.015 -0.138,0.02c0.263,0 0.513,0.01 0.763,0.01c42.012,-0.001 76.075,-18.985 76.075,-42.413c0,-13.261 -10.938,-25.097 -28.038,-32.871Z" style="fill:none;"/><path id="path5082" d="M354.323,82.586l-41.999,-42.002l38.524,-38.515l-29.913,0l-23.562,23.559l-23.563,-23.559l-29.924,0l38.525,38.515l-42,42.002l29.913,0l27.049,-27.046l27.05,27.046l29.9,0" style="fill:#fff;fill-rule:nonzero;"/><path id="path5084" d="M354.323,82.586l-41.999,-42.002l38.524,-38.515l-29.913,0l-23.562,23.559l-23.563,-23.559l-29.924,0l38.525,38.515l-42,42.002l29.913,0l27.049,-27.046l27.05,27.046l29.9,0Z" style="fill:none;"/><path id="path5086" d="M0,2.069l75.033,0l0,16.489l-51.629,0l0,14.931l40.258,0l0,16.495l-40.258,0l0,16.05l53.124,0l0,16.488l-76.528,0l0,-80.453" style="fill:#fff;fill-rule:nonzero;"/><path id="path5088" d="M0,2.069l75.033,0l0,16.489l-51.629,0l0,14.931l40.258,0l0,16.495l-40.258,0l0,16.05l53.124,0l0,16.488l-76.528,0l0,-80.453Z" style="fill:none;"/></g></svg>`
30
+ const base64Logo = window.btoa(eoxLogo)
27
31
  </script>
28
32
  <style scoped lang='scss'>
29
33
  .footer-text {
30
34
  font-size: 0.8rem;
31
35
  }
36
+
37
+ .footer-text a {
38
+ color: white;
39
+ }
32
40
  </style>
@@ -1,29 +1,29 @@
1
1
  <template>
2
- <v-main class="overflow-none" style="height: 91dvh;">
2
+ <v-main class="overflow-hidden" style="height: 91dvh;">
3
3
 
4
4
  <component :is="bgWidget.component" v-bind="bgWidget.props"></component>
5
5
 
6
- <v-row no-gutters class="d-flex justify-center align-end">
7
- <v-col v-for="(importedWidget, idx) in importedWidgets" :key="idx" :cols="cols"
8
- class="flex-column fill-height fill-width elevation-1 align-start ma-0 justify-center">
9
- <span class="d-flex pa-2 justify-center ma-0 panel-header align-center fill-width"
10
- @click="handleSelection(idx)">
11
- {{ importedWidget.value.title }}
12
- </span>
13
- <div v-show="activeIdx === idx" class="overlay align-self-end overflow-auto pa-2">
14
- <v-btn icon variant="text" class="close-btn" @click="activeIdx = -1">&#x2715;</v-btn>
15
- <component :key="importedWidget.value.id" :is="importedWidget.value.component" v-show="activeIdx === idx"
16
- v-bind="importedWidget.value.props" />
17
- </div>
18
- </v-col>
19
- </v-row>
6
+ <div v-show="activeIdx === idx" class="overlay pa-2" :style="{ bottom: tabsBottom }"
7
+ v-for="(importedWidget, idx) in importedWidgets" :key="idx">
8
+ <v-btn icon variant="text" class="close-btn" @click="activeIdx = -1">&#x2715;</v-btn>
9
+ <component :key="importedWidget.value.id" :is="importedWidget.value.component" v-show="activeIdx === idx"
10
+ v-bind="importedWidget.value.props" />
11
+ </div>
12
+
13
+ <v-tabs ref="tabs" align-tabs="center" bg-color="surface"
14
+ :style="{ position: 'relative', bottom: mainRect.bottom + 'px', zIndex: 10 }" show-arrows v-model="activeIdx">
15
+ <v-tab v-for="(importedWidget, idx) in importedWidgets" :key="idx" :value="idx">
16
+ {{ importedWidget.value.title }}
17
+ </v-tab>
18
+ </v-tabs>
19
+
20
20
  </v-main>
21
21
  </template>
22
22
  <script setup>
23
23
  import { eodashKey } from '@/store/Keys';
24
- import { inject } from 'vue';
24
+ import { inject, ref, onMounted } from 'vue';
25
25
  import { useDefineWidgets } from '@/composables/DefineWidgets'
26
- import { ref } from 'vue';
26
+ import { useLayout } from "vuetify"
27
27
 
28
28
  const eodash = /** @type {import("@/types").Eodash} */(inject(eodashKey));
29
29
 
@@ -32,47 +32,30 @@ const widgetsConfig = eodash.template.widgets
32
32
  const importedWidgets = useDefineWidgets(widgetsConfig)
33
33
  const [bgWidget] = useDefineWidgets([eodash.template?.background])
34
34
 
35
+ const { mainRect } = useLayout()
35
36
 
36
-
37
- /**
38
- * number of flex columns
39
- */
40
- const cols = importedWidgets.length / 12
41
-
42
- /**
43
- * index of the active tab
44
- */
45
37
  const activeIdx = ref(-1)
46
38
 
47
- /**
48
- * @param {number} idx
49
- **/
50
- const handleSelection = (idx) => {
51
- activeIdx.value = activeIdx.value === idx ? -1 : idx
52
- }
39
+ /** @type {import("vue").Ref<import("vuetify/components").VTabs|null>} */
40
+ const tabs = ref(null)
41
+ const tabsBottom = ref('')
42
+ onMounted(() => {
43
+ tabsBottom.value = mainRect.value.bottom + (/** @type {HTMLElement} */(tabs.value?.$el)?.clientHeight ?? 0) + "px"
44
+ })
53
45
  </script>
54
46
  <style scoped lang='scss'>
55
- .panel-header {
56
- height: auto;
57
- margin: 0;
58
- width: 100%;
59
- position: relative;
60
- bottom: 64px;
61
- z-index: 10;
62
- background: rgb(var(--v-theme-background));
63
- }
64
-
65
47
  .overlay {
66
48
  position: absolute;
67
49
  width: 100%;
68
50
  left: 0;
69
51
  top: 64px;
70
- bottom: 64px;
71
52
  z-index: 1;
72
- background: rgb(var(--v-theme-background));
53
+ background: rgb(var(--v-theme-surface));
73
54
  }
74
55
 
75
56
  .close-btn {
76
- justify-self: end;
57
+ position: relative;
58
+ height: 1rem;
59
+ font-size: 0.8rem;
77
60
  }
78
61
  </style>
@@ -94,7 +94,7 @@ const getWidgetDefinition = (config) => {
94
94
  loader: internalWidgets[/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.name],
95
95
  suspensible: true
96
96
  })
97
- importedWidget.props = reactive(/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.props ?? {})
97
+ importedWidget.props = reactive(/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.properties ?? {})
98
98
 
99
99
  break;
100
100
 
@@ -1,12 +1,12 @@
1
1
  // functions of this folder can only be consumed inside setup stores,
2
2
  // setup functions or vue composition api components
3
3
 
4
- import { reactive } from "vue"
5
- import { currentUrl, datetime, mapInstance, indicator } from "@/store/States"
6
- import eodashConfig from "@/eodash"
7
- import { useTheme } from "vuetify/lib/framework.mjs"
8
- import { useRouter } from "vue-router"
9
- import { onMounted, onUnmounted, watch } from "vue"
4
+ import { reactive } from "vue";
5
+ import { currentUrl, datetime, mapInstance, indicator } from "@/store/States";
6
+ import eodashConfig from "@/eodash";
7
+ import { useTheme } from "vuetify/lib/framework.mjs";
8
+ import { useRouter } from "vue-router";
9
+ import { onMounted, onUnmounted, watch } from "vue";
10
10
 
11
11
  /**
12
12
  * Creates an absolute URL from a relative link and assignes it to `currentUrl`
@@ -15,10 +15,10 @@ import { onMounted, onUnmounted, watch } from "vue"
15
15
  * @returns {import('vue').Ref<string>} - returns `currentUrl`
16
16
  * @see {@link '@/store/States.js'}
17
17
  */
18
- export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
19
- if (!rel || rel.includes('http')) {
20
- currentUrl.value = base
21
- return currentUrl
18
+ export const useAbsoluteUrl = (rel = "", base = eodashConfig.stacEndpoint) => {
19
+ if (!rel || rel.includes("http")) {
20
+ currentUrl.value = base;
21
+ return currentUrl;
22
22
  }
23
23
 
24
24
  const st = base.split("/");
@@ -26,17 +26,14 @@ export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
26
26
  st.pop();
27
27
 
28
28
  for (let i = 0; i < arr.length; i++) {
29
- if (arr[i] == ".")
30
- continue;
31
- if (arr[i] == "..")
32
- st.pop();
33
- else
34
- st.push(arr[i]);
29
+ if (arr[i] == ".") continue;
30
+ if (arr[i] == "..") st.pop();
31
+ else st.push(arr[i]);
35
32
  }
36
33
 
37
34
  currentUrl.value = st.join("/");
38
- return currentUrl
39
- }
35
+ return currentUrl;
36
+ };
40
37
 
41
38
  /**
42
39
  * Adds slide in and out functionality to Elements
@@ -44,84 +41,107 @@ export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
44
41
  * @param {import("@/types").Widget[]} configs
45
42
  */
46
43
  export const useSlidePanels = (elements, configs) => {
47
-
48
44
  /**
49
45
  * Sliding direction
50
46
  */
51
- const slideDirs = configs.map(m => m.layout.x == 0 ? 'left' : m.layout.x == 12 - m.layout.w ? 'right' : m.layout.y < 6 ? 'up' : 'down')
47
+ const slideDirs = configs.map((m) =>
48
+ m.layout.x == 0
49
+ ? "left"
50
+ : m.layout.x == 12 - m.layout.w
51
+ ? "right"
52
+ : m.layout.y < 6
53
+ ? "up"
54
+ : "down"
55
+ );
52
56
 
53
57
  /**
54
58
  * Array of sliding button's style and icons
55
59
  */
56
- const slideBtns = slideDirs.map(d => {
57
- const btn = reactive({ style: {}, icon: { in: '', out: '' }, active: false })
58
- switch (d) {
59
- case 'left':
60
- btn.style = { 'top': '50%', 'right': '-11%' }
61
- btn.icon.in = 'mdi-chevron-double-right'
62
- btn.icon.out = 'mdi-chevron-double-left'
60
+ const slideBtns = slideDirs.map((dir, idx) => {
61
+ const btn = reactive({
62
+ style: {},
63
+ icon: { in: "", out: "" },
64
+ active: false,
65
+ enabled: true,
66
+ });
67
+ if (configs[idx].slidable === false) {
68
+ btn.enabled = false;
69
+ return btn;
70
+ }
71
+
72
+ switch (dir) {
73
+ case "left":
74
+ btn.style = { top: "50%", right: "-11%" };
75
+ btn.icon.in = "mdi-chevron-double-right";
76
+ btn.icon.out = "mdi-chevron-double-left";
63
77
 
64
78
  break;
65
- case 'right':
66
- btn.style = { 'top': '50%', 'left': '-11%' }
67
- btn.icon.in = 'mdi-chevron-double-left'
68
- btn.icon.out = 'mdi-chevron-double-right'
79
+ case "right":
80
+ btn.style = { top: "50%", left: "-11%" };
81
+ btn.icon.in = "mdi-chevron-double-left";
82
+ btn.icon.out = "mdi-chevron-double-right";
69
83
 
70
84
  break;
71
- case 'up':
72
- btn.style = { 'right': '50%', 'bottom': '-17%' }
73
- btn.icon.in = 'mdi-chevron-double-down'
74
- btn.icon.out = 'mdi-chevron-double-up'
85
+ case "up":
86
+ btn.style = { right: "50%", bottom: "-17%" };
87
+ btn.icon.in = "mdi-chevron-double-down";
88
+ btn.icon.out = "mdi-chevron-double-up";
75
89
 
76
90
  break;
77
- case 'down':
78
- btn.style = { 'right': '50%', 'top': '-17%' }
79
- btn.icon.in = 'mdi-chevron-double-up'
80
- btn.icon.out = 'mdi-chevron-double-down'
91
+ case "down":
92
+ btn.style = { right: "50%", top: "-17%" };
93
+ btn.icon.in = "mdi-chevron-double-up";
94
+ btn.icon.out = "mdi-chevron-double-down";
81
95
  break;
82
96
 
83
97
  default:
84
- console.error('sliding error')
98
+ console.error("sliding error");
85
99
  break;
86
100
  }
87
- return btn
88
- })
101
+ return btn;
102
+ });
89
103
 
90
104
  /**
91
105
  * Transforms the element's position based on the direction
92
106
  * @param {number} idx - index of the pressed element
93
107
  */
94
108
  const slideInOut = (idx) => {
95
- const parentStyle = /** @type {CSSStyleDeclaration} */ (elements.value?.[idx].style)
109
+ const parentStyle = /** @type {CSSStyleDeclaration} */ (
110
+ elements.value?.[idx].style
111
+ );
96
112
  if (parentStyle?.transform.length) {
97
- slideBtns[idx].active = false
113
+ slideBtns[idx].active = false;
98
114
  parentStyle.transform = "";
99
115
  } else {
100
- slideBtns[idx].active = true
101
- parentStyle.transition = "transform 0.3s ease-in-out"
116
+ slideBtns[idx].active = true;
117
+ parentStyle.transition = "transform 0.3s ease-in-out";
102
118
  switch (slideDirs[idx]) {
103
- case 'left':
104
- parentStyle.transform = "translateX(-100%)"
119
+ case "left":
120
+ parentStyle.transform = "translateX(-100%)";
105
121
  break;
106
- case 'right':
107
- parentStyle.transform = "translateX(100%)"
122
+ case "right":
123
+ parentStyle.transform = "translateX(100%)";
108
124
  break;
109
- case 'up':
110
- parentStyle.transform = `translateY(-${((configs[idx].layout.y / configs[idx].layout.h) * 100) + 100}%)`
125
+ case "up":
126
+ parentStyle.transform = `translateY(-${(configs[idx].layout.y / configs[idx].layout.h) * 100 + 100
127
+ }%)`;
111
128
  break;
112
- case 'down':
113
- parentStyle.transform = `translateY(${((Math.max(0, 12 - configs[idx].layout.y - configs[idx].layout.h) / configs[idx].layout.h) * 100) + 100}%)`;
129
+ case "down":
130
+ parentStyle.transform = `translateY(${(Math.max(0, 12 - configs[idx].layout.y - configs[idx].layout.h) /
131
+ configs[idx].layout.h) *
132
+ 100 +
133
+ 100
134
+ }%)`;
114
135
  break;
115
136
 
116
137
  default:
117
- console.error('sliding error')
138
+ console.error("sliding error");
118
139
  break;
119
140
  }
120
141
  }
121
- }
122
- return { slideBtns, slideInOut }
123
- }
124
-
142
+ };
143
+ return { slideBtns, slideInOut };
144
+ };
125
145
 
126
146
  /**
127
147
  * Updates an existing Vuetify theme.
@@ -133,63 +153,82 @@ export const useSlidePanels = (elements, configs) => {
133
153
  export const useUpdateTheme = (themeName, themeDefinition = {}) => {
134
154
  const theme = useTheme();
135
155
 
136
- /** @type {Array<keyof import('vuetify').ThemeDefinition>} */(Object.keys(themeDefinition)).forEach((key) => {
137
- if (key === 'dark') {
138
- theme.themes.value[themeName][key] = /** @type {Boolean} */ (themeDefinition[key])
156
+ /** @type {Array<keyof import('vuetify').ThemeDefinition>} */ (
157
+ Object.keys(themeDefinition)
158
+ ).forEach((key) => {
159
+ if (key === "dark") {
160
+ theme.themes.value[themeName][key] = /** @type {Boolean} */ (
161
+ themeDefinition[key]
162
+ );
139
163
  } else {
140
164
  //@ts-expect-error
141
165
  theme.themes.value[themeName][key] = {
142
166
  ...theme.themes.value[themeName][key],
143
- ...themeDefinition[key]
144
- }
167
+ ...themeDefinition[key],
168
+ };
145
169
  }
146
- })
147
- return theme
148
- }
149
-
170
+ });
171
+ return theme;
172
+ };
150
173
 
151
174
  /**
152
175
  * Composable that initiates route query params to store
153
176
  * STAC related values
154
177
  */
155
178
  export const useRouteParams = () => {
156
- const router = useRouter()
179
+ const router = useRouter();
157
180
  /**
158
181
  * @type {import("openlayers").EventsListenerFunctionType}
159
182
  */
160
183
  const handleMoveEnd = (evt) => {
161
- const map = /** @type {import("openlayers").Map | undefined} */ (/** @type {*} */ (evt).map)
162
- const [x, y] = map?.getView().getCenter() ?? [0, 0]
163
- const z = map?.getView().getZoom()
164
- const currentQuery = router.currentRoute.value.query
184
+ const map = /** @type {import("openlayers").Map | undefined} */ (
185
+ /** @type {*} */ (evt).map
186
+ );
187
+ const [x, y] = map?.getView().getCenter() ?? [0, 0];
188
+ const z = map?.getView().getZoom();
189
+ const currentQuery = router.currentRoute.value.query;
165
190
  router.push({
166
191
  query: {
167
192
  ...currentQuery,
168
- x, y, z
169
- }
170
- })
171
-
172
- }
193
+ x: x.toFixed(4),
194
+ y: y.toFixed(4),
195
+ z: z?.toFixed(4),
196
+ },
197
+ });
198
+ };
173
199
  onMounted(() => {
174
- watch([datetime, mapInstance, currentUrl, indicator], ([updatedDate, updatedMap, updatedUrl, updatedIndicator]) => {
175
- const [x, y] = updatedMap?.getView().getCenter() ?? [0, 0]
176
- const currentQuery = router.currentRoute.value.query
177
- router.push({
178
- query: {
179
- ...currentQuery,
180
- indicator: updatedIndicator,
181
- x,
182
- y,
183
- z: updatedMap?.getView().getZoom(),
184
- datetime: updatedDate,
185
- url: updatedUrl,
186
- }
187
- })
188
- updatedMap?.on("moveend", handleMoveEnd)
189
- })
190
- })
200
+ // Set datetime based on kvp
201
+ if (
202
+ "datetime" in router.currentRoute.value.query &&
203
+ router.currentRoute.value.query["datetime"] !== ""
204
+ ) {
205
+ // @ts-ignore
206
+ datetime.value =
207
+ /** @type {string} */ router.currentRoute.value.query["datetime"];
208
+ }
209
+ watch(
210
+ [datetime, mapInstance, currentUrl, indicator],
211
+ ([updatedDate, updatedMap, _updatedUrl, updatedIndicator]) => {
212
+ const [x, y] = updatedMap?.getView().getCenter() ?? [0, 0];
213
+ // lets reduce unnecessary accuracy
214
+ const currentQuery = router.currentRoute.value.query;
215
+ router.push({
216
+ query: {
217
+ ...currentQuery,
218
+ indicator: updatedIndicator,
219
+ x: x.toFixed(4),
220
+ y: y.toFixed(4),
221
+ z: updatedMap?.getView().getZoom().toFixed(),
222
+ datetime: updatedDate,
223
+ // url: updatedUrl,
224
+ },
225
+ });
226
+ updatedMap?.on("moveend", handleMoveEnd);
227
+ }
228
+ );
229
+ });
191
230
 
192
231
  onUnmounted(() => {
193
- mapInstance.value?.un("moveend", handleMoveEnd)
194
- })
195
- }
232
+ mapInstance.value?.un("moveend", handleMoveEnd);
233
+ });
234
+ };