@eodash/eodash 5.0.0-alpha.1.13 → 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/bin/serverConfig.js +6 -4
- package/bin/utils.js +6 -2
- package/core/App.vue +17 -2
- package/core/components/DashboardLayout.vue +3 -2
- package/core/components/Footer.vue +11 -3
- package/core/components/MobileLayout.vue +28 -45
- package/core/composables/DefineWidgets.js +18 -11
- package/core/composables/index.js +153 -66
- package/core/eodash.js +52 -88
- package/core/main.js +1 -3
- package/core/store/Actions.js +0 -28
- package/core/store/States.js +10 -0
- package/core/store/stac.js +3 -1
- package/core/types.d.ts +74 -46
- package/core/utils/eodashSTAC.js +164 -0
- package/core/utils/helpers.js +40 -0
- package/core/utils/index.js +28 -0
- package/core/views/Dashboard.vue +8 -2
- package/core/vite-env.d.ts +12 -10
- package/package.json +8 -3
- package/widgets/EodashDatePicker.vue +51 -0
- package/widgets/EodashItemFilter.vue +60 -0
- package/widgets/EodashMap.vue +72 -0
package/bin/serverConfig.js
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
cachePath, publicPath, userConfig,
|
|
10
10
|
buildTargetPath,
|
|
11
11
|
logger,
|
|
12
|
-
rootPath
|
|
12
|
+
rootPath,
|
|
13
|
+
internalWidgetsPath
|
|
13
14
|
} from "./utils.js";
|
|
14
15
|
import { readFile } from "fs/promises";
|
|
15
16
|
import { defineConfig, searchForWorkspaceRoot } from "vite"
|
|
@@ -61,7 +62,8 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
61
62
|
alias: {
|
|
62
63
|
'@': fileURLToPath(new URL('../core', import.meta.url)),
|
|
63
64
|
'^': fileURLToPath(new URL('../widgets', import.meta.url)),
|
|
64
|
-
"user:config": entryPath
|
|
65
|
+
"user:config": entryPath,
|
|
66
|
+
"user:widgets": internalWidgetsPath
|
|
65
67
|
},
|
|
66
68
|
extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
|
|
67
69
|
},
|
|
@@ -78,7 +80,7 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
78
80
|
},
|
|
79
81
|
root: fileURLToPath(new URL('..', import.meta.url)),
|
|
80
82
|
optimizeDeps: mode === "development" ? {
|
|
81
|
-
include: ["webfontloader", "vuetify", "vue", "pinia"],
|
|
83
|
+
include: ["webfontloader", "vuetify", "vue", "pinia", "stac-js", "urijs"],
|
|
82
84
|
noDiscovery: true,
|
|
83
85
|
} : {},
|
|
84
86
|
/** @type {string|false} */
|
|
@@ -100,7 +102,7 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
100
102
|
* @type {import("vite").ServerHook}
|
|
101
103
|
*/
|
|
102
104
|
async function configureServer(server) {
|
|
103
|
-
server.watcher.add([entryPath, runtimeConfigPath])
|
|
105
|
+
server.watcher.add([entryPath, runtimeConfigPath, path.join(internalWidgetsPath, "**/*.vue")])
|
|
104
106
|
|
|
105
107
|
let updatedPath = ''
|
|
106
108
|
const loggerInfo = logger.info
|
package/bin/utils.js
CHANGED
|
@@ -21,6 +21,7 @@ const pkg = JSON.parse(
|
|
|
21
21
|
* @property {string | false} publicDir
|
|
22
22
|
* @property {string} outDir
|
|
23
23
|
* @property {string} entryPoint
|
|
24
|
+
* @property {string} widgets
|
|
24
25
|
* @property {string} cacheDir
|
|
25
26
|
* @property {string} runtime
|
|
26
27
|
* @property {string} base
|
|
@@ -33,7 +34,8 @@ cli.version(pkg.version, '-v, --version', 'output the current version')
|
|
|
33
34
|
.option('--publicDir <path>', 'path to statically served assets folder')
|
|
34
35
|
.option('--no-publicDir', 'stop serving static assets')
|
|
35
36
|
.option('--outDir <path>', 'minified output folder')
|
|
36
|
-
.option('-e, --entryPoint <path>', 'file exporting `
|
|
37
|
+
.option('-e, --entryPoint <path>', 'file exporting `createEodash`')
|
|
38
|
+
.option('-w, --widgets <path>', 'folder that contains vue components as internal widgets')
|
|
37
39
|
.option('--cacheDir <path>', 'cache folder')
|
|
38
40
|
.option('-r, --runtime <path>', 'file exporting eodash client runtime config')
|
|
39
41
|
.option('-b, --base <path>', 'base public path')
|
|
@@ -52,6 +54,7 @@ export const appPath = fileURLToPath(new URL("..", import.meta.url)),
|
|
|
52
54
|
srcPath = path.join(rootPath, "/src"),
|
|
53
55
|
runtimeConfigPath = userConfig.runtime ? path.resolve(rootPath, userConfig.runtime) : path.join(srcPath, "./runtime.js"),
|
|
54
56
|
entryPath = userConfig.entryPoint ? path.resolve(rootPath, userConfig.entryPoint) : path.join(srcPath, "/main.js"),
|
|
57
|
+
internalWidgetsPath = userConfig.widgets ? path.resolve(rootPath, userConfig.widgets) : path.join(srcPath, "widgets"),
|
|
55
58
|
dotEodashPath = path.join(rootPath, "/.eodash"),
|
|
56
59
|
buildTargetPath = userConfig.outDir ? path.resolve(rootPath, userConfig.outDir) : path.join(dotEodashPath, '/dist'),
|
|
57
60
|
cachePath = userConfig.cacheDir ? path.resolve(rootPath, userConfig.cacheDir) : path.join(dotEodashPath, 'cache');
|
|
@@ -84,6 +87,7 @@ async function getUserConfig(options, command) {
|
|
|
84
87
|
entryPoint: options.entryPoint ?? config?.entryPoint,
|
|
85
88
|
outDir: options.outDir ?? config?.outDir,
|
|
86
89
|
publicDir: options.publicDir ?? config?.publicDir,
|
|
87
|
-
runtime: options.runtime ?? config?.runtime
|
|
90
|
+
runtime: options.runtime ?? config?.runtime,
|
|
91
|
+
widgets: options.widgets ?? config?.widgets
|
|
88
92
|
}
|
|
89
93
|
}
|
package/core/App.vue
CHANGED
|
@@ -8,7 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
<!-- loading state -->
|
|
10
10
|
<template #fallback>
|
|
11
|
-
|
|
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"
|
|
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
|
-
|
|
5
|
+
{{ eodash.brand.footerText ?? "" }}
|
|
6
6
|
</p>
|
|
7
7
|
<div class="footer-text">
|
|
8
|
-
|
|
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-
|
|
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-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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">✕</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 {
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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-
|
|
53
|
+
background: rgb(var(--v-theme-surface));
|
|
73
54
|
}
|
|
74
55
|
|
|
75
56
|
.close-btn {
|
|
76
|
-
|
|
57
|
+
position: relative;
|
|
58
|
+
height: 1rem;
|
|
59
|
+
font-size: 0.8rem;
|
|
77
60
|
}
|
|
78
61
|
</style>
|
|
@@ -2,8 +2,6 @@ import { defineAsyncComponent, reactive, shallowRef, watch } from 'vue'
|
|
|
2
2
|
import { useSTAcStore } from '@/store/stac'
|
|
3
3
|
import { storeToRefs } from 'pinia'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* @typedef {{
|
|
9
7
|
* component:import('vue').Component | null;
|
|
@@ -17,14 +15,24 @@ import { storeToRefs } from 'pinia'
|
|
|
17
15
|
* @typedef {import('vue').ShallowRef<DefinedWidget>} ReactiveDefinedWidget
|
|
18
16
|
*/
|
|
19
17
|
|
|
18
|
+
const internalWidgets = (() => {
|
|
19
|
+
/**
|
|
20
|
+
* @type {Record<string,() => Promise<import('vue').Component>>}
|
|
21
|
+
*/
|
|
22
|
+
const importMap = {
|
|
23
|
+
...import.meta.glob('^/**/*.vue'),
|
|
24
|
+
...import.meta.glob("user:widgets/**/*.vue")
|
|
25
|
+
}
|
|
26
|
+
for (const key in importMap) {
|
|
27
|
+
const newKey = /** @type {string} */(key.split('/').at(-1)).slice(0, -4)
|
|
28
|
+
Object.defineProperty(importMap, newKey,
|
|
29
|
+
/** @type {PropertyDescriptor} */(Object.getOwnPropertyDescriptor(importMap, key)));
|
|
30
|
+
delete importMap[key];
|
|
31
|
+
}
|
|
32
|
+
return importMap
|
|
33
|
+
})();
|
|
20
34
|
|
|
21
35
|
|
|
22
|
-
/**
|
|
23
|
-
* import map to all vue components inside `widgets` directory.
|
|
24
|
-
* @type {Record<string,() => Promise<import('vue').Component>>}
|
|
25
|
-
*/
|
|
26
|
-
const internalWidgets = import.meta.glob('^/**/*.vue')
|
|
27
|
-
|
|
28
36
|
/**
|
|
29
37
|
* Composable that converts widgets Configurations to defined imported widgets
|
|
30
38
|
* @param { (import("@/types").Widget | import("@/types").BackgroundWidget | undefined)[] |
|
|
@@ -46,7 +54,6 @@ export const useDefineWidgets = (widgetConfigs) => {
|
|
|
46
54
|
props: {},
|
|
47
55
|
title: '',
|
|
48
56
|
id: Symbol(),
|
|
49
|
-
no: '4'
|
|
50
57
|
})
|
|
51
58
|
|
|
52
59
|
if ('defineWidget' in (config ?? {})) {
|
|
@@ -84,10 +91,10 @@ const getWidgetDefinition = (config) => {
|
|
|
84
91
|
switch (config?.type) {
|
|
85
92
|
case 'internal':
|
|
86
93
|
importedWidget.component = defineAsyncComponent({
|
|
87
|
-
loader: internalWidgets[
|
|
94
|
+
loader: internalWidgets[/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.name],
|
|
88
95
|
suspensible: true
|
|
89
96
|
})
|
|
90
|
-
importedWidget.props = reactive(/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.
|
|
97
|
+
importedWidget.props = reactive(/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.properties ?? {})
|
|
91
98
|
|
|
92
99
|
break;
|
|
93
100
|
|
|
@@ -1,11 +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 } from "@/store/States"
|
|
6
|
-
import eodashConfig from "@/eodash"
|
|
7
|
-
import { useTheme } from "vuetify/lib/framework.mjs"
|
|
8
|
-
|
|
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";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Creates an absolute URL from a relative link and assignes it to `currentUrl`
|
|
@@ -14,10 +15,10 @@ import { useTheme } from "vuetify/lib/framework.mjs"
|
|
|
14
15
|
* @returns {import('vue').Ref<string>} - returns `currentUrl`
|
|
15
16
|
* @see {@link '@/store/States.js'}
|
|
16
17
|
*/
|
|
17
|
-
export const useAbsoluteUrl = (rel =
|
|
18
|
-
if (!rel || rel.includes(
|
|
19
|
-
currentUrl.value = base
|
|
20
|
-
return currentUrl
|
|
18
|
+
export const useAbsoluteUrl = (rel = "", base = eodashConfig.stacEndpoint) => {
|
|
19
|
+
if (!rel || rel.includes("http")) {
|
|
20
|
+
currentUrl.value = base;
|
|
21
|
+
return currentUrl;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const st = base.split("/");
|
|
@@ -25,17 +26,14 @@ export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
|
|
|
25
26
|
st.pop();
|
|
26
27
|
|
|
27
28
|
for (let i = 0; i < arr.length; i++) {
|
|
28
|
-
if (arr[i] == ".")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
st.pop();
|
|
32
|
-
else
|
|
33
|
-
st.push(arr[i]);
|
|
29
|
+
if (arr[i] == ".") continue;
|
|
30
|
+
if (arr[i] == "..") st.pop();
|
|
31
|
+
else st.push(arr[i]);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
currentUrl.value = st.join("/");
|
|
37
|
-
return currentUrl
|
|
38
|
-
}
|
|
35
|
+
return currentUrl;
|
|
36
|
+
};
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
39
|
* Adds slide in and out functionality to Elements
|
|
@@ -43,84 +41,107 @@ export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
|
|
|
43
41
|
* @param {import("@/types").Widget[]} configs
|
|
44
42
|
*/
|
|
45
43
|
export const useSlidePanels = (elements, configs) => {
|
|
46
|
-
|
|
47
44
|
/**
|
|
48
45
|
* Sliding direction
|
|
49
46
|
*/
|
|
50
|
-
const slideDirs = configs.map(m =>
|
|
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
|
+
);
|
|
51
56
|
|
|
52
57
|
/**
|
|
53
58
|
* Array of sliding button's style and icons
|
|
54
59
|
*/
|
|
55
|
-
const slideBtns = slideDirs.map(
|
|
56
|
-
const btn = reactive({
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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";
|
|
62
77
|
|
|
63
78
|
break;
|
|
64
|
-
case
|
|
65
|
-
btn.style = {
|
|
66
|
-
btn.icon.in =
|
|
67
|
-
btn.icon.out =
|
|
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";
|
|
68
83
|
|
|
69
84
|
break;
|
|
70
|
-
case
|
|
71
|
-
btn.style = {
|
|
72
|
-
btn.icon.in =
|
|
73
|
-
btn.icon.out =
|
|
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";
|
|
74
89
|
|
|
75
90
|
break;
|
|
76
|
-
case
|
|
77
|
-
btn.style = {
|
|
78
|
-
btn.icon.in =
|
|
79
|
-
btn.icon.out =
|
|
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";
|
|
80
95
|
break;
|
|
81
96
|
|
|
82
97
|
default:
|
|
83
|
-
console.error(
|
|
98
|
+
console.error("sliding error");
|
|
84
99
|
break;
|
|
85
100
|
}
|
|
86
|
-
return btn
|
|
87
|
-
})
|
|
101
|
+
return btn;
|
|
102
|
+
});
|
|
88
103
|
|
|
89
104
|
/**
|
|
90
105
|
* Transforms the element's position based on the direction
|
|
91
106
|
* @param {number} idx - index of the pressed element
|
|
92
107
|
*/
|
|
93
108
|
const slideInOut = (idx) => {
|
|
94
|
-
const parentStyle = /** @type {CSSStyleDeclaration} */ (
|
|
109
|
+
const parentStyle = /** @type {CSSStyleDeclaration} */ (
|
|
110
|
+
elements.value?.[idx].style
|
|
111
|
+
);
|
|
95
112
|
if (parentStyle?.transform.length) {
|
|
96
|
-
slideBtns[idx].active = false
|
|
113
|
+
slideBtns[idx].active = false;
|
|
97
114
|
parentStyle.transform = "";
|
|
98
115
|
} else {
|
|
99
|
-
slideBtns[idx].active = true
|
|
100
|
-
parentStyle.transition = "transform 0.3s ease-in-out"
|
|
116
|
+
slideBtns[idx].active = true;
|
|
117
|
+
parentStyle.transition = "transform 0.3s ease-in-out";
|
|
101
118
|
switch (slideDirs[idx]) {
|
|
102
|
-
case
|
|
103
|
-
parentStyle.transform = "translateX(-100%)"
|
|
119
|
+
case "left":
|
|
120
|
+
parentStyle.transform = "translateX(-100%)";
|
|
104
121
|
break;
|
|
105
|
-
case
|
|
106
|
-
parentStyle.transform = "translateX(100%)"
|
|
122
|
+
case "right":
|
|
123
|
+
parentStyle.transform = "translateX(100%)";
|
|
107
124
|
break;
|
|
108
|
-
case
|
|
109
|
-
parentStyle.transform = `translateY(-${(
|
|
125
|
+
case "up":
|
|
126
|
+
parentStyle.transform = `translateY(-${(configs[idx].layout.y / configs[idx].layout.h) * 100 + 100
|
|
127
|
+
}%)`;
|
|
110
128
|
break;
|
|
111
|
-
case
|
|
112
|
-
parentStyle.transform = `translateY(${(
|
|
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
|
+
}%)`;
|
|
113
135
|
break;
|
|
114
136
|
|
|
115
137
|
default:
|
|
116
|
-
console.error(
|
|
138
|
+
console.error("sliding error");
|
|
117
139
|
break;
|
|
118
140
|
}
|
|
119
141
|
}
|
|
120
|
-
}
|
|
121
|
-
return { slideBtns, slideInOut }
|
|
122
|
-
}
|
|
123
|
-
|
|
142
|
+
};
|
|
143
|
+
return { slideBtns, slideInOut };
|
|
144
|
+
};
|
|
124
145
|
|
|
125
146
|
/**
|
|
126
147
|
* Updates an existing Vuetify theme.
|
|
@@ -132,16 +153,82 @@ export const useSlidePanels = (elements, configs) => {
|
|
|
132
153
|
export const useUpdateTheme = (themeName, themeDefinition = {}) => {
|
|
133
154
|
const theme = useTheme();
|
|
134
155
|
|
|
135
|
-
/** @type {Array<keyof import('vuetify').ThemeDefinition>} */(
|
|
136
|
-
|
|
137
|
-
|
|
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
|
+
);
|
|
138
163
|
} else {
|
|
139
164
|
//@ts-expect-error
|
|
140
165
|
theme.themes.value[themeName][key] = {
|
|
141
166
|
...theme.themes.value[themeName][key],
|
|
142
|
-
...themeDefinition[key]
|
|
143
|
-
}
|
|
167
|
+
...themeDefinition[key],
|
|
168
|
+
};
|
|
144
169
|
}
|
|
145
|
-
})
|
|
146
|
-
return theme
|
|
147
|
-
}
|
|
170
|
+
});
|
|
171
|
+
return theme;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Composable that initiates route query params to store
|
|
176
|
+
* STAC related values
|
|
177
|
+
*/
|
|
178
|
+
export const useRouteParams = () => {
|
|
179
|
+
const router = useRouter();
|
|
180
|
+
/**
|
|
181
|
+
* @type {import("openlayers").EventsListenerFunctionType}
|
|
182
|
+
*/
|
|
183
|
+
const handleMoveEnd = (evt) => {
|
|
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;
|
|
190
|
+
router.push({
|
|
191
|
+
query: {
|
|
192
|
+
...currentQuery,
|
|
193
|
+
x: x.toFixed(4),
|
|
194
|
+
y: y.toFixed(4),
|
|
195
|
+
z: z?.toFixed(4),
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
onMounted(() => {
|
|
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
|
+
});
|
|
230
|
+
|
|
231
|
+
onUnmounted(() => {
|
|
232
|
+
mapInstance.value?.un("moveend", handleMoveEnd);
|
|
233
|
+
});
|
|
234
|
+
};
|