@eodash/eodash 5.0.0-alpha → 5.0.0-alpha.1

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 (66) hide show
  1. package/bin/app.js +16 -147
  2. package/bin/cli.js +58 -0
  3. package/bin/serverConfig.js +130 -0
  4. package/bin/update.js +19 -0
  5. package/bin/utils.js +28 -0
  6. package/core/App.vue +21 -0
  7. package/core/components/DashboardLayout.vue +58 -0
  8. package/core/components/DynamicWebComponent.vue +68 -0
  9. package/core/components/Footer.vue +31 -0
  10. package/core/components/Header.vue +38 -0
  11. package/core/components/IframeWrapper.vue +11 -0
  12. package/core/components/MobileLayout.vue +79 -0
  13. package/core/composables/DefineConfig.js +44 -0
  14. package/core/composables/DefineWidgets.js +118 -0
  15. package/core/composables/index.js +147 -0
  16. package/core/eodashConfig.js +136 -0
  17. package/core/main.js +4 -0
  18. package/core/plugins/index.js +27 -0
  19. package/core/plugins/router.js +20 -0
  20. package/core/plugins/vuetify.js +27 -0
  21. package/core/render.js +13 -0
  22. package/core/store/Actions.js +28 -0
  23. package/core/store/Keys.js +6 -0
  24. package/core/store/States.js +12 -0
  25. package/core/store/index.js +23 -0
  26. package/core/store/stac.js +61 -0
  27. package/core/types.d.ts +333 -0
  28. package/core/views/Dashboard.vue +49 -0
  29. package/core/vite-env.d.ts +35 -0
  30. package/package.json +20 -21
  31. package/widgets/WidgetsContainer.vue +46 -0
  32. package/dist/.gitkeep +0 -0
  33. package/dist/assets/Dashboard-4233cc52.css +0 -1
  34. package/dist/assets/Dashboard-d7d438a6.js +0 -1
  35. package/dist/assets/DashboardLayout-5ab6c4a5.js +0 -29
  36. package/dist/assets/DashboardLayout-739135c5.css +0 -1
  37. package/dist/assets/DynamicWebComponent-1b7b527a.js +0 -1
  38. package/dist/assets/Footer-0fe1887a.css +0 -1
  39. package/dist/assets/Footer-7e1ca735.js +0 -1
  40. package/dist/assets/Header-9cac598d.css +0 -1
  41. package/dist/assets/Header-ae17296c.js +0 -1
  42. package/dist/assets/IframeWrapper-b2c05ffd.js +0 -1
  43. package/dist/assets/MobileLayout-1b3cb89b.js +0 -1
  44. package/dist/assets/MobileLayout-ad647682.css +0 -1
  45. package/dist/assets/VMain-d6216866.css +0 -1
  46. package/dist/assets/VMain-f6b3f120.js +0 -1
  47. package/dist/assets/WidgetsContainer-cdad3d50.js +0 -1
  48. package/dist/assets/color-6039ab34.js +0 -1
  49. package/dist/assets/eox-chart-3b122ba4.js +0 -142
  50. package/dist/assets/eox-itemfilter-a63da0da.js +0 -981
  51. package/dist/assets/eox-jsonform-98c2af62.js +0 -239
  52. package/dist/assets/eox-layercontrol-f5e35702.js +0 -1126
  53. package/dist/assets/eox-map-7f82b0d4.js +0 -178
  54. package/dist/assets/eox-stacinfo-65a8d8f3.js +0 -388
  55. package/dist/assets/eox-timecontrol-4be63aa2.js +0 -237
  56. package/dist/assets/index-52c9d989.js +0 -34
  57. package/dist/assets/index-5d2400e5.css +0 -5
  58. package/dist/assets/materialdesignicons-webfont-48d3eec6.woff +0 -0
  59. package/dist/assets/materialdesignicons-webfont-861aea05.eot +0 -0
  60. package/dist/assets/materialdesignicons-webfont-bd725a7a.ttf +0 -0
  61. package/dist/assets/materialdesignicons-webfont-e52d60f6.woff2 +0 -0
  62. package/dist/assets/ssrBoot-0b8754a9.css +0 -1
  63. package/dist/assets/ssrBoot-d383eb61.js +0 -1
  64. package/dist/assets/webfontloader-523643f5.js +0 -1
  65. package/dist/index.html +0 -17
  66. package/dist/types/index.d.ts +0 -124
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <v-main class="overflow-none" style="height: 91dvh;">
3
+
4
+ <component :is="bgWidget.component" v-bind="bgWidget.props"></component>
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" @click="handleSelection(idx)">
10
+ {{ importedWidget.value.title }}
11
+ </span>
12
+ <div v-show="activeIdx === idx" class="overlay align-self-end overflow-auto pa-2">
13
+ <v-btn icon variant="text" class="close-btn" @click="activeIdx = -1">&#x2715;</v-btn>
14
+ <component :key="importedWidget.value.id" :is="importedWidget.value.component" v-show="activeIdx === idx"
15
+ v-bind="importedWidget.value.props" />
16
+ </div>
17
+ </v-col>
18
+ </v-row>
19
+ </v-main>
20
+ </template>
21
+ <script setup>
22
+ import { eodashConfigKey } from '@/store/Keys';
23
+ import { inject } from 'vue';
24
+ import { useDefineWidgets } from '@/composables/DefineWidgets'
25
+ import { ref } from 'vue';
26
+
27
+ const eodashConfig = /** @type {EodashConfig} */(inject(eodashConfigKey));
28
+
29
+ //import widgets
30
+ const widgetsConfig = eodashConfig.template.widgets
31
+ const importedWidgets = useDefineWidgets(widgetsConfig)
32
+ const [bgWidget] = useDefineWidgets([eodashConfig.template?.background])
33
+
34
+
35
+
36
+ /**
37
+ * number of flex columns
38
+ */
39
+ const cols = importedWidgets.length / 12
40
+
41
+ /**
42
+ * index of the active tab
43
+ */
44
+ const activeIdx = ref(-1)
45
+
46
+ /**
47
+ * @param {number} idx
48
+ **/
49
+ const handleSelection = (idx) => {
50
+ activeIdx.value = activeIdx.value === idx ? -1 : idx
51
+ }
52
+ </script>
53
+ <style scoped lang='scss'>
54
+ .panel-header {
55
+ height: auto;
56
+ margin: 0;
57
+ width: 100%;
58
+ position: relative;
59
+ bottom: 64px;
60
+ z-index: 10;
61
+ background: rgb(var(--v-theme-background));
62
+ }
63
+
64
+ .overlay {
65
+ position: absolute;
66
+ width: 100%;
67
+ left: 0;
68
+ top: 64px;
69
+ bottom: 64px;
70
+ z-index: 1;
71
+ background: rgb(var(--v-theme-background));
72
+ }
73
+
74
+ .close-btn {
75
+ justify-self: end;
76
+ }
77
+
78
+ //
79
+ </style>
@@ -0,0 +1,44 @@
1
+ import { eodashConfigKey } from "@/store/Keys"
2
+ import { inject } from "vue"
3
+ import store from '@/store'
4
+
5
+ /**
6
+ * Sets user defined configuration on runtime.
7
+ * Consumes `/config.js` file from the base URL, and assign it to `eodashConfig`
8
+ * @async
9
+ * @returns {Promise<EodashConfig>}
10
+ * @see {@linkplain '@/eodashConfig.js'}
11
+ */
12
+ export const useEodashRuntimeConfig = async () => {
13
+ const eodashConfig = /** @type {EodashConfig} */(inject(eodashConfigKey))
14
+ /**
15
+ * @param {EodashConfig} updatedConfig
16
+ */
17
+ const assignConfig = (updatedConfig) => {
18
+ /** @type {(keyof EodashConfig)[]} */(Object.keys(eodashConfig))
19
+ .forEach((key) => {
20
+ //@ts-expect-error
21
+ eodashConfig[key] = updatedConfig[key]
22
+ })
23
+ }
24
+
25
+ try {
26
+ assignConfig(
27
+ (await import( /* @vite-ignore */new URL('/config.js', import.meta.url).href)).default
28
+ )
29
+ } catch {
30
+ try {
31
+ assignConfig((await import("user:config")).default)
32
+ } catch {
33
+ console.error('no dashboard configuration assigned')
34
+ }
35
+ }
36
+ return eodashConfig
37
+ }
38
+
39
+ /**
40
+ * @param {(store:EodashStore)=>EodashConfig} configCallback
41
+ */
42
+ export const defineCompiletimeConfig = (configCallback) => {
43
+ return configCallback(store)
44
+ }
@@ -0,0 +1,118 @@
1
+ import { defineAsyncComponent, reactive, shallowRef, watch } from 'vue'
2
+ import { useSTAcStore } from '@/store/stac'
3
+ import { storeToRefs } from 'pinia'
4
+
5
+
6
+
7
+ /**
8
+ * @typedef {{
9
+ * component:import('vue').Component | null;
10
+ * props: Record<string, unknown>;
11
+ * title :string;
12
+ * id:string|number|symbol;
13
+ * }} DefinedWidget
14
+ */
15
+
16
+ /**
17
+ * @typedef {import('vue').ShallowRef<DefinedWidget>} ReactiveDefinedWidget
18
+ */
19
+
20
+
21
+
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
+ /**
29
+ * Composable that converts widgets Configurations to defined imported widgets
30
+ * @param { (WidgetConfig | BackgroundWidgetConfig | undefined)[] |
31
+ * WidgetsContainerProps['widgets'] | undefined} widgetConfigs
32
+ * @returns {Array<ReactiveDefinedWidget>}
33
+ **/
34
+ export const useDefineWidgets = (widgetConfigs) => {
35
+ /**
36
+ * @type {Array<ReactiveDefinedWidget>}
37
+ */
38
+ const definedWidgets = []
39
+
40
+ for (const config of (widgetConfigs ?? [])) {
41
+ /**
42
+ * @type {ReactiveDefinedWidget}
43
+ */
44
+ const definedWidget = shallowRef({
45
+ component: null,
46
+ props: {},
47
+ title: '',
48
+ id: Symbol(),
49
+ no: '4'
50
+ })
51
+
52
+ if ('defineWidget' in (config ?? {})) {
53
+ const { selectedStac } = storeToRefs(useSTAcStore())
54
+ watch(selectedStac, (updatedStac) => {
55
+ const definedConfig = reactive(/** @type {FunctionalWidget} */
56
+ (config)?.defineWidget(updatedStac))
57
+ definedWidget.value = definedWidget.value.id === definedConfig.id ?
58
+ definedWidget.value : getWidgetDefinition(definedConfig);
59
+ }, { immediate: true })
60
+ } else {
61
+ definedWidget.value = getWidgetDefinition(/** @type {StaticWidget} */(config))
62
+ }
63
+ definedWidgets.push(definedWidget)
64
+ }
65
+ return definedWidgets
66
+ }
67
+
68
+
69
+ /**
70
+ * Converts a static widget configuration to a defined imported widget
71
+ * @param {StaticWidget| Omit<StaticWidget, "layout">| undefined} config
72
+ * @returns {DefinedWidget}
73
+ **/
74
+ const getWidgetDefinition = (config) => {
75
+ /**
76
+ * @type {DefinedWidget}
77
+ */
78
+ const importedWidget = {
79
+ component: null,
80
+ props: {},
81
+ title: '',
82
+ id: Symbol(),
83
+ }
84
+ switch (config?.type) {
85
+ case 'internal':
86
+ importedWidget.component = defineAsyncComponent({
87
+ loader: internalWidgets[`/widgets/${/** @type {InternalComponentConfig} **/(config)?.widget.name}.vue`],
88
+ suspensible: true
89
+ })
90
+ importedWidget.props = reactive(/** @type {InternalComponentConfig} **/(config)?.widget.props ?? {})
91
+
92
+ break;
93
+
94
+ case 'web-component':
95
+ importedWidget.component = defineAsyncComponent({
96
+ loader: () => import('@/components/DynamicWebComponent.vue'),
97
+ suspensible: true
98
+ })
99
+ importedWidget.props = reactive(config.widget)
100
+
101
+ break;
102
+ case 'iframe':
103
+ importedWidget.component = defineAsyncComponent({
104
+ loader: () => import('@/components/IframeWrapper.vue'),
105
+ suspensible: true
106
+ })
107
+ importedWidget.props = reactive(config.widget)
108
+ break;
109
+
110
+ default:
111
+ console.error('Widget type not found')
112
+ break;
113
+ }
114
+ importedWidget.title = config?.title ?? ''
115
+ importedWidget.id = config?.id ?? importedWidget.id
116
+ return importedWidget
117
+ }
118
+
@@ -0,0 +1,147 @@
1
+ // functions of this folder can only be consumed inside setup stores,
2
+ // setup functions or vue composition api components
3
+
4
+ import { reactive } from "vue"
5
+ import { currentUrl } from "@/store/States"
6
+ import eodashConfig from "@/eodashConfig"
7
+ import { useTheme } from "vuetify/lib/framework.mjs"
8
+
9
+
10
+ /**
11
+ * Creates an absolute URL from a relative link and assignes it to `currentUrl`
12
+ * @param {string} [rel = '']
13
+ * @param {string} [base = eodashConfig.stacEndpoint] - base URL, default value is the root stac catalog
14
+ * @returns {import('vue').Ref<string>} - returns `currentUrl`
15
+ * @see {@link '@/store/States.js'}
16
+ */
17
+ export const useAbsoluteUrl = (rel = '', base = eodashConfig.stacEndpoint) => {
18
+ if (!rel || rel.includes('http')) {
19
+ currentUrl.value = base
20
+ return currentUrl
21
+ }
22
+
23
+ const st = base.split("/");
24
+ const arr = rel.split("/");
25
+ st.pop();
26
+
27
+ for (let i = 0; i < arr.length; i++) {
28
+ if (arr[i] == ".")
29
+ continue;
30
+ if (arr[i] == "..")
31
+ st.pop();
32
+ else
33
+ st.push(arr[i]);
34
+ }
35
+
36
+ currentUrl.value = st.join("/");
37
+ return currentUrl
38
+ }
39
+
40
+ /**
41
+ * Adds slide in and out functionality to Elements
42
+ * @param {import('vue').Ref<HTMLElement[]|null>} elements - elements to add the functionality to
43
+ * @param {WidgetConfig[]} configs
44
+ */
45
+ export const useSlidePanels = (elements, configs) => {
46
+
47
+ /**
48
+ * Sliding direction
49
+ */
50
+ const slideDirs = configs.map(m => m.layout.x == 0 ? 'left' : m.layout.x == 12 - m.layout.w ? 'right' : m.layout.y < 6 ? 'up' : 'down')
51
+
52
+ /**
53
+ * Array of sliding button's style and icons
54
+ */
55
+ const slideBtns = slideDirs.map(d => {
56
+ const btn = reactive({ style: {}, icon: { in: '', out: '' }, active: false })
57
+ switch (d) {
58
+ case 'left':
59
+ btn.style = { 'top': '50%', 'right': '-11%' }
60
+ btn.icon.in = 'mdi-chevron-double-right'
61
+ btn.icon.out = 'mdi-chevron-double-left'
62
+
63
+ break;
64
+ case 'right':
65
+ btn.style = { 'top': '50%', 'left': '-11%' }
66
+ btn.icon.in = 'mdi-chevron-double-left'
67
+ btn.icon.out = 'mdi-chevron-double-right'
68
+
69
+ break;
70
+ case 'up':
71
+ btn.style = { 'right': '50%', 'bottom': '-17%' }
72
+ btn.icon.in = 'mdi-chevron-double-down'
73
+ btn.icon.out = 'mdi-chevron-double-up'
74
+
75
+ break;
76
+ case 'down':
77
+ btn.style = { 'right': '50%', 'top': '-17%' }
78
+ btn.icon.in = 'mdi-chevron-double-up'
79
+ btn.icon.out = 'mdi-chevron-double-down'
80
+ break;
81
+
82
+ default:
83
+ console.error('sliding error')
84
+ break;
85
+ }
86
+ return btn
87
+ })
88
+
89
+ /**
90
+ * Transforms the element's position based on the direction
91
+ * @param {number} idx - index of the pressed element
92
+ */
93
+ const slideInOut = (idx) => {
94
+ const parentStyle = /** @type {CSSStyleDeclaration} */ (elements.value?.[idx].style)
95
+ if (parentStyle?.transform.length) {
96
+ slideBtns[idx].active = false
97
+ parentStyle.transform = "";
98
+ } else {
99
+ slideBtns[idx].active = true
100
+ parentStyle.transition = "transform 0.3s ease-in-out"
101
+ switch (slideDirs[idx]) {
102
+ case 'left':
103
+ parentStyle.transform = "translateX(-100%)"
104
+ break;
105
+ case 'right':
106
+ parentStyle.transform = "translateX(100%)"
107
+ break;
108
+ case 'up':
109
+ parentStyle.transform = `translateY(-${((configs[idx].layout.y / configs[idx].layout.h) * 100) + 100}%)`
110
+ break;
111
+ case 'down':
112
+ parentStyle.transform = `translateY(${((Math.max(0, 12 - configs[idx].layout.y - configs[idx].layout.h) / configs[idx].layout.h) * 100) + 100}%)`;
113
+ break;
114
+
115
+ default:
116
+ console.error('sliding error')
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ return { slideBtns, slideInOut }
122
+ }
123
+
124
+
125
+ /**
126
+ * Updates an existing Vuetify theme.
127
+ * updates only the values provided in the `ThemeDefinition`
128
+ * @param {string} themeName - Name of the theme to be updated
129
+ * @param {import('vuetify').ThemeDefinition} [themeDefinition = {}] - New defintion to be updated to
130
+ * @returns {import('vuetify').ThemeInstance}
131
+ */
132
+ export const useUpdateTheme = (themeName, themeDefinition = {}) => {
133
+ const theme = useTheme();
134
+
135
+ /** @type {Array<keyof import('vuetify').ThemeDefinition>} */(Object.keys(themeDefinition)).forEach((key) => {
136
+ if (key === 'dark') {
137
+ theme.themes.value[themeName][key] = /** @type {Boolean} */ (themeDefinition[key])
138
+ } else {
139
+ //@ts-expect-error
140
+ theme.themes.value[themeName][key] = {
141
+ ...theme.themes.value[themeName][key],
142
+ ...themeDefinition[key]
143
+ }
144
+ }
145
+ })
146
+ return theme
147
+ }
@@ -0,0 +1,136 @@
1
+ import { reactive } from "vue";
2
+ import { currentUrl, mapInstance } from './store/States';
3
+ /**
4
+ * @type {Function | null}
5
+ */
6
+ let handleMoveEnd = null;
7
+
8
+ /**
9
+ * Reactive Edoash Config Object. provided globally in the app,
10
+ * and used as an intermediate object to make user defined configurations reactive.
11
+ * @type {EodashConfig}
12
+ */
13
+ const eodashConfig = reactive({
14
+ id: 'demo',
15
+ stacEndpoint: 'https://eurodatacube.github.io/eodash-catalog/RACE/catalog.json',
16
+ routes: [],
17
+ brand: {
18
+ name: 'Demo',
19
+ font: {
20
+ family: 'Poppins'
21
+ },
22
+ theme: {
23
+ colors: {
24
+ primary: '#004170',
25
+ secondary: '#00417044',
26
+ surface: "#f0f0f0f0",
27
+ }
28
+ }
29
+ },
30
+ template: {
31
+ background: {
32
+ id: Symbol(),
33
+ widget: {
34
+ link: 'https://cdn.skypack.dev/@eox/map',
35
+ properties: {
36
+ class: "fill-height fill-width overflow-none",
37
+ center: [15, 48],
38
+ layers: [{ type: "Tile", source: { type: "OSM" } }],
39
+ },
40
+ tagName: 'eox-map',
41
+ onMounted(el, _, router) {
42
+ /** @type {any} */(el).zoom = router.currentRoute.value.query['z'];
43
+
44
+ mapInstance.value = /** @type {any} */(el).map;
45
+
46
+ mapInstance.value?.on('moveend', handleMoveEnd =
47
+ /** @param {any} evt */(evt) => {
48
+ router.push({
49
+ query: {
50
+ z: `${evt.map.getView().getZoom()}`
51
+ }
52
+ });
53
+ });
54
+ },
55
+ onUnmounted(_el, _store, _router) {
56
+ //@ts-expect-error
57
+ mapInstance.value?.un('moveend', handleMoveEnd);
58
+ }
59
+ },
60
+ type: 'web-component'
61
+ },
62
+ widgets: [
63
+ {
64
+ id: Symbol(),
65
+ title: 'Tools',
66
+ layout: { "x": 0, "y": 0, "w": 3, "h": 12 },
67
+ widget: {
68
+ link: 'https://cdn.skypack.dev/@eox/itemfilter',
69
+ properties: {
70
+ config: {
71
+ titleProperty: "title",
72
+ filterProperties: [
73
+ {
74
+ keys: ["title", "themes"],
75
+ title: "Search",
76
+ type: "text",
77
+ expanded: true,
78
+ },
79
+ {
80
+ key: "themes",
81
+ title: "Theme",
82
+ type: "multiselect",
83
+ featured: true
84
+ },
85
+ ],
86
+ aggregateResults: "themes",
87
+ enableHighlighting: true,
88
+ }
89
+ },
90
+ onMounted: async function (el, store, _) {
91
+ /**
92
+ * @typedef {object} Item
93
+ * @property {string} href
94
+ * */
95
+
96
+ /** @type {any} */(el).apply(store?.stac);
97
+ /** @type {any} */(el).config.onSelect =
98
+ /**
99
+ * @param {Item} item
100
+ * */
101
+ async (item) => {
102
+ console.log(item);
103
+ await store.loadSelectedSTAC(item.href);
104
+ };
105
+ },
106
+ tagName: 'eox-itemfilter'
107
+ },
108
+ type: 'web-component'
109
+ },
110
+ {
111
+ id: Symbol(),
112
+ title: 'Information',
113
+ layout: { "x": 9, "y": 0, "w": 3, "h": 12 },
114
+ widget: {
115
+ link: async () => await import('@eox/stacinfo'),
116
+ properties: {
117
+ for: currentUrl,
118
+ allowHtml: "true",
119
+ styleOverride: "#properties li > .value {font-weight: normal !important;}",
120
+ header: "[]",
121
+
122
+ subheader: "[]",
123
+ properties: '["description"]',
124
+ featured: "[]",
125
+ footer: "[]"
126
+ },
127
+ tagName: 'eox-stacinfo'
128
+ },
129
+ type: 'web-component'
130
+ },
131
+ ]
132
+ }
133
+ });
134
+
135
+
136
+ export default eodashConfig;
package/core/main.js ADDED
@@ -0,0 +1,4 @@
1
+ // Plugins
2
+ import { defineCompiletimeConfig } from '@/composables/DefineConfig';
3
+
4
+ export { defineCompiletimeConfig as defineConfig }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * plugins/index.ts
3
+ *
4
+ * Automatically included in `./src/main.ts`
5
+ */
6
+
7
+ // Plugins
8
+ import vuetify from './vuetify';
9
+ import router from './router';
10
+ import { createPinia } from 'pinia';
11
+ import eodashConfig from '@/eodashConfig';
12
+ import { eodashConfigKey } from '@/store/Keys';
13
+ import store from '../store';
14
+
15
+ export const pinia = createPinia();
16
+
17
+ /**
18
+ * @param {import('vue').App} app
19
+ */
20
+ export function registerPlugins(app) {
21
+ window.eodashStore = store;
22
+
23
+ app.use(vuetify)
24
+ .use(router)
25
+ .use(pinia)
26
+ .provide(eodashConfigKey, eodashConfig);
27
+ }
@@ -0,0 +1,20 @@
1
+ import { createRouter, createWebHistory } from 'vue-router';
2
+
3
+ const routes = [
4
+ {
5
+ path: '/',
6
+ redirect: '/dashboard'
7
+ },
8
+ {
9
+ path: '/dashboard',
10
+ name: 'Dashboard',
11
+ component: () => import('@/views/Dashboard.vue'),
12
+ }
13
+ ];
14
+
15
+ const router = createRouter({
16
+ history: createWebHistory(process.env.BASE_URL),
17
+ routes,
18
+ });
19
+
20
+ export default router;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * plugins/vuetify.ts
3
+ *
4
+ * Framework documentation: https://vuetifyjs.com`
5
+ */
6
+
7
+ // Styles
8
+ import '@mdi/font/css/materialdesignicons.css';
9
+ import 'vuetify/styles';
10
+
11
+
12
+ import { createVuetify } from 'vuetify';
13
+
14
+ // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
15
+ export default createVuetify({
16
+ theme: {
17
+ themes: {
18
+ dashboardTheme: {},
19
+ light: {
20
+ colors: {
21
+ primary: '#1867C0',
22
+ secondary: '#5CBBF6',
23
+ },
24
+ },
25
+ },
26
+ },
27
+ });
package/core/render.js ADDED
@@ -0,0 +1,13 @@
1
+ import { registerPlugins } from '@/plugins';
2
+ // Components
3
+ import App from './App.vue';
4
+
5
+ // Composables
6
+ import { createApp } from 'vue';
7
+
8
+
9
+ const app = createApp(App);
10
+
11
+ registerPlugins(app);
12
+
13
+ app.mount('#app');
@@ -0,0 +1,28 @@
1
+ /**
2
+ * loads font in the app using `webfontloader`
3
+ * @param {string} [family="Roboto"]
4
+ * @param {string} [link]
5
+ * @returns {Promise<string>} - font family name
6
+ * @see {@link "https://github.com/typekit/webfontloader "}
7
+ */
8
+ export const loadFont = async (family = "Roboto", link) => {
9
+ const WebFontLoader = (await import('webfontloader')).default;
10
+ if (link) {
11
+ WebFontLoader.load({
12
+ custom: {
13
+ // Use FVD notation to include families https://github.com/typekit/fvd
14
+ families: [family],
15
+ // Path to stylesheet that defines font-face
16
+ urls: [link],
17
+ },
18
+ });
19
+ }
20
+ else {
21
+ WebFontLoader.load({
22
+ google: {
23
+ families: [family]
24
+ }
25
+ });
26
+ }
27
+ return family;
28
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * `eodashConfig` injection key.
3
+ * @type {Symbol}
4
+ * @see {@link "@/plugins/index.js"}
5
+ */
6
+ export const eodashConfigKey = Symbol("eodashConfig");
@@ -0,0 +1,12 @@
1
+ import { ref } from "vue";
2
+
3
+ /**
4
+ * currently selected STAC endpoint
5
+ */
6
+ export const currentUrl = ref('');
7
+
8
+ /**
9
+ * ol map object. Updated by the config file.
10
+ * @type {import("vue").Ref<import('openlayers').Map | null>}
11
+ */
12
+ export const mapInstance = ref(null);
@@ -0,0 +1,23 @@
1
+ //export all actions, states, and pinia stores
2
+ /**
3
+ * @template {keyof EodashStore} [K = keyof EodashStore]
4
+ * @typedef {Record<K,EodashStore[K]>} EodashStoreImports
5
+ */
6
+
7
+ const storesImport = /**@type {EodashStoreImports} */(import.meta.glob('../store/**.js', { eager: true }))
8
+ /**
9
+ * @type {EodashStore}
10
+ */
11
+ const store = (() => {
12
+ const stores = /** @type {EodashStore}*/({});
13
+ for (const [filePath, importedstore] of Object.entries(storesImport)) {
14
+ const storeType = filePath.split('/').at(-1)?.slice(0, -3).toLowerCase() ?? ''
15
+ if (!['keys'].includes(storeType)) {
16
+ //@ts-expect-error
17
+ stores[storeType] = importedstore;
18
+ }
19
+ }
20
+ return stores;
21
+ })();
22
+
23
+ export default store;