@eodash/eodash 5.0.0-alpha → 5.0.0-alpha.1.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 +57 -0
  3. package/bin/serverConfig.js +134 -0
  4. package/bin/update.js +17 -0
  5. package/bin/utils.js +33 -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
package/bin/app.js CHANGED
@@ -1,153 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { fileURLToPath } from 'url';
4
- import { preview } from 'vite'
5
- import express from "express";
6
- import * as chokidar from "chokidar"
7
- import { copyFile, cp, readFile, writeFile } from "fs/promises";
8
- import { WebSocketServer } from 'ws';
9
-
10
-
11
- // global paths
12
- const __appPath = fileURLToPath(new URL("../", import.meta.url));
13
- const __execPath = fileURLToPath(new URL(process.cwd(), import.meta.url));
14
- const __configPath = __execPath + "/config.js";
15
-
3
+ import { buildApp, createDevServer, previewApp } from './cli.js'
16
4
 
5
+ const command = process.argv?.[2];
17
6
  (async () => {
18
- if (process.argv.includes('dev')) {
19
- await dev();
20
- } else if (process.argv.includes('build')) {
21
- await buildApp();
22
- } else if (process.argv.includes('preview')) {
23
- await previewApp();
7
+ switch (command) {
8
+ case "dev":
9
+ await createDevServer();
10
+ break;
11
+ case "build":
12
+ await buildApp();
13
+ break;
14
+ case "preview":
15
+ await previewApp();
16
+ break;
17
+
18
+ default:
19
+ console.error('command not found')
20
+ break;
24
21
  }
25
22
  })();
26
-
27
- async function update() {
28
- // 1. copy public
29
- const publicPath = __execPath + "/public"
30
- const distPath = __appPath + "dist"
31
- await cp(publicPath, distPath, { recursive: true }).catch(err => {
32
- console.error(err)
33
- })
34
- // 2. copy config
35
- const appConfigPath = __appPath + "dist/config.js";
36
- await copyFile(__configPath, appConfigPath).catch(err => {
37
- console.error(err)
38
- });
39
- }
40
-
41
- const wsClientScript = `<script type="module">
42
- const client = new WebSocket("ws://localhost:3333/");
43
- client.onerror = function (e) {
44
- console.error('WebSocket Client Error', e);
45
- };
46
- client.onopen = function () {
47
- console.info('client connected');
48
- };
49
- client.onclose = function () {
50
- console.info('client closed');
51
- };
52
- client.onmessage = function (evt) {
53
- if (evt.data === 'reload') {
54
- window.location.reload()
55
- }
56
- };
57
- </script>`
58
-
59
- async function dev() {
60
- // copy files to app
61
- await update();
62
- // inject ws client for dev
63
- await injectInHTML(wsClientScript)
64
- // create static server
65
- const server = express();
66
- server.use(express.static(__appPath + "dist"));
67
-
68
- server.listen(3000, () => {
69
- console.info(`server is running on http://localhost:3000`);
70
- })
71
-
72
- server.all("*", (req, res) => {
73
- // handle query
74
- const params = new URLSearchParams(req.query).toString()
75
- // redirect to the app
76
- res.redirect(`${params.length ? '/?' + params : '/'}`)
77
- })
78
-
79
- // create files watcher
80
- const watcher = chokidar.watch(__execPath + '/**/**.js', {
81
- ignored: ["**/node_modules/**", __execPath + "/app/**", __appPath + '**/**.**'],
82
- depth: 2
83
- });
84
-
85
- // create ws server for reloading
86
- const wsServer = new WebSocketServer({ port: 3333 });
87
-
88
- let websocket = null
89
- wsServer.on('connection', (ws) => {
90
- websocket = ws
91
- });
92
-
93
- // reload on change
94
- watcher.on('change', async (path) => {
95
- if (path === __configPath) {
96
- await update()
97
- websocket.send('reload')
98
- console.info(`updated config.js ✨`)
99
- }
100
- })
101
- }
102
-
103
-
104
-
105
- async function buildApp() {
106
- await update()
107
- // remove injected script before copying to exec path
108
- await injectInHTML(wsClientScript, true)
109
- await cp(__appPath + 'dist', __execPath + '/app', { recursive: true }).catch(err => {
110
- console.error(err)
111
- })
112
- console.info(`built successfully`)
113
- }
114
-
115
- async function previewApp() {
116
- const previewServer = await preview({
117
- root: __execPath,
118
- preview: {
119
- port: 8080,
120
- open: true,
121
- },
122
- build: {
123
- outDir: 'app'
124
- }
125
- })
126
- previewServer.printUrls()
127
- }
128
-
129
-
130
- async function injectInHTML(injected, remove) {
131
- const htmlPath = __appPath + 'dist/index.html'
132
- const updatedHtml = await readFile(htmlPath, 'utf8').then(data => {
133
- let html = ''
134
- if (remove) {
135
- html = data.replace(injected, '')
136
- } else {
137
- if (!data.includes(injected)) {
138
- const splitHtml = data.split("\n")
139
- splitHtml.splice(splitHtml.indexOf("</body>"), 0, injected);
140
- html = splitHtml.join("\n")
141
- }
142
- }
143
- return html
144
- }).catch(err => {
145
- throw err
146
- })
147
-
148
- if (updatedHtml.length) {
149
- await writeFile(htmlPath, updatedHtml).catch(err => {
150
- throw err;
151
- });
152
- }
153
- }
package/bin/cli.js ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { build, createServer, preview } from "vite"
4
+ import { rootPath, appPath, buildTargetPath, appPublicPath } from "./utils.js";
5
+ import { writeFile, rm, cp } from "fs/promises";
6
+ import { update } from "./update.js";
7
+ import { indexHtml, serverConfig } from "./serverConfig.js";
8
+ import path from "path";
9
+ import { existsSync } from "fs";
10
+
11
+
12
+
13
+ export const createDevServer = async () => {
14
+ const server = await createServer(await serverConfig({ mode: 'development', command: 'serve' }))
15
+ await server.listen()
16
+ server.printUrls()
17
+ server.bindCLIShortcuts({ print: true })
18
+ }
19
+
20
+ export const buildApp = async () => {
21
+ const htmlPath = path.join(appPath, '/index.html')
22
+ await writeFile(htmlPath, indexHtml).then(async () => {
23
+ await update()
24
+ await build(await serverConfig({ mode: 'production', command: 'build' }))
25
+ await rm(htmlPath).catch(() => {
26
+ console.error('failed to remove index.html')
27
+ })
28
+ if (appPath.includes('node_modules') && existsSync(appPublicPath)) {
29
+ await rm(appPublicPath, { recursive: true }).catch((e) => {
30
+ console.error(e)
31
+ })
32
+ }
33
+ })
34
+
35
+ if (appPath.includes('node_modules')) {
36
+ await cp(path.join(appPath, 'dist'), buildTargetPath, { recursive: true }).then(() => {
37
+ console.info('dashboard built successfully')
38
+ }).catch((e) => {
39
+ console.error(e)
40
+ })
41
+ }
42
+ }
43
+
44
+
45
+ export async function previewApp() {
46
+ const previewServer = await preview({
47
+ root: rootPath,
48
+ preview: {
49
+ port: 8080,
50
+ open: true,
51
+ },
52
+ build: {
53
+ outDir: buildTargetPath
54
+ }
55
+ })
56
+ previewServer.printUrls()
57
+ }
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+
5
+ import vue from '@vitejs/plugin-vue';
6
+ import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify';
7
+ import virtual, { updateVirtualModule } from 'vite-plugin-virtual'
8
+ import { fileURLToPath, URL } from 'url';
9
+ import {
10
+ runtimeConfigPath,
11
+ appPath, compiletimeConfigPath,
12
+ appPublicPath, cachePath, rootPublicPath
13
+ } from "./utils.js";
14
+ import { readFile } from "fs/promises";
15
+ import { defineConfig, searchForWorkspaceRoot } from "vite"
16
+ import { getUserModules } from './utils.js';
17
+ import { existsSync } from 'fs';
18
+ import path from "path";
19
+
20
+ export const indexHtml = `
21
+ <!DOCTYPE html>
22
+ <html lang="en">
23
+
24
+ <head>
25
+ <meta charset="UTF-8" />
26
+ <link rel="icon" href="/favicon.ico" />
27
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
28
+ <title>Welcome to Eodash v5</title>
29
+ </head>
30
+
31
+ <body>
32
+ <div id="app"></div>
33
+ <script type="module" src="${path.resolve(`/@fs/${appPath}/core/render.js`)}"></script>
34
+ </body>
35
+ </html>`
36
+
37
+ /**
38
+ * @type {import('vite').Plugin | null}
39
+ */
40
+ let virtualPlugin = null;
41
+ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(defineConfig(async ({ mode, command }) => {
42
+ return {
43
+ base: '',
44
+ cacheDir: cachePath,
45
+ plugins: [
46
+ vue({
47
+ template: {
48
+ transformAssetUrls,
49
+ compilerOptions: {
50
+ isCustomElement: (tag) => !tag.includes('v-') && tag.includes('-')
51
+ }
52
+ },
53
+ }),
54
+ // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
55
+ vuetify({
56
+ autoImport: true,
57
+ }),
58
+ (mode === "development" && {
59
+ name: "inject-html",
60
+ configureServer
61
+ }),
62
+ virtualPlugin = virtual(await getUserModules())
63
+ ],
64
+ define: { 'process.env': {} },
65
+ resolve: {
66
+ alias: {
67
+ '@': fileURLToPath(new URL('../core', import.meta.url)),
68
+ '^': fileURLToPath(new URL('../widgets', import.meta.url)),
69
+ },
70
+ extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
71
+ },
72
+ server: {
73
+ port: 3000,
74
+ fs: {
75
+ allow: [searchForWorkspaceRoot(process.cwd())]
76
+ },
77
+ open: '/'
78
+ },
79
+ root: fileURLToPath(new URL('..', import.meta.url)),
80
+ optimizeDeps: mode === "development" ? {
81
+ include: ["webfontloader", "vuetify", "vue", "pinia"],
82
+ noDiscovery: true,
83
+ } : {},
84
+ publicDir: command === 'build' ? appPublicPath : rootPublicPath,
85
+ build: {
86
+ outDir: 'dist',
87
+ rollupOptions: {
88
+ input: fileURLToPath(new URL(command === 'build' ? '../index.html' : '../core/main.js', import.meta.url)),
89
+ },
90
+ target: "esnext"
91
+ }
92
+ }
93
+ }));
94
+
95
+
96
+
97
+ /**
98
+ * @type {import("vite").ServerHook}
99
+ */
100
+ async function configureServer(server) {
101
+ server.watcher.add([compiletimeConfigPath, runtimeConfigPath])
102
+
103
+ server.watcher.on('change', async (path) => {
104
+ if (path == runtimeConfigPath) {
105
+ server.hot.send('reload')
106
+ } else if (!path.includes('node_modules') && path.includes('.eodash')) {
107
+ updateVirtualModule(virtualPlugin, 'user:config',
108
+ await getUserModules().then(modules => modules['user:config']))
109
+ }
110
+ })
111
+
112
+ return () => {
113
+ server.middlewares.use(async (req, res, next) => {
114
+ if (req.originalUrl === '/@fs/config.js' && existsSync(runtimeConfigPath)) {
115
+ await readFile(runtimeConfigPath).then(runtimeConfig => {
116
+ res.statusCode = 200
117
+ res.setHeader('Content-Type', 'text/javascript')
118
+ res.write(runtimeConfig)
119
+ res.end()
120
+ })
121
+ return
122
+ }
123
+
124
+ if (req.url?.endsWith('.html')) {
125
+ res.statusCode = 200
126
+ res.setHeader('Content-Type', 'text/html')
127
+ const html = await server.transformIndexHtml(req.url, indexHtml, req.originalUrl)
128
+ res.end(html)
129
+ return
130
+ }
131
+ next()
132
+ })
133
+ }
134
+ }
package/bin/update.js ADDED
@@ -0,0 +1,17 @@
1
+ import { cp } from "fs/promises";
2
+ import { rootPublicPath, appPath, runtimeConfigPath, appPublicPath } from "./utils.js";
3
+ import { existsSync } from "fs";
4
+ import path from "path";
5
+
6
+ export async function update() {
7
+ if (rootPublicPath !== appPublicPath) {
8
+ await cp(rootPublicPath, appPublicPath, { recursive: true }).catch(err => {
9
+ console.error(err)
10
+ })
11
+ if (existsSync(runtimeConfigPath)) {
12
+ await cp(runtimeConfigPath, path.join(appPath, '/public/config.js')).catch((e) => {
13
+ console.error(e)
14
+ })
15
+ }
16
+ }
17
+ }
package/bin/utils.js ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile } from 'fs/promises';
4
+ import { existsSync } from 'fs';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { searchForWorkspaceRoot } from 'vite';
8
+
9
+ // global paths
10
+ export const appPath = fileURLToPath(new URL("..", import.meta.url)),
11
+ appPublicPath = path.join(appPath, './public'),
12
+ rootPath = searchForWorkspaceRoot(process.cwd()),
13
+ rootPublicPath = path.join(rootPath, './public'),
14
+ srcPath = path.join(rootPath, "/src"),
15
+ runtimeConfigPath = path.join(srcPath, "./config.runtime.js"),
16
+ compiletimeConfigPath = path.join(srcPath, "/config.js"),
17
+ dotEodashPath = path.join(rootPath, "/.eodash"),
18
+ buildTargetPath = path.join(dotEodashPath, '/dist'),
19
+ cachePath = path.join(dotEodashPath, 'cache');
20
+
21
+
22
+
23
+ export const getUserModules = async () => {
24
+ /** @type {Record<string,string>} */
25
+ let userModules = {}
26
+ const indexJs = await readFile(compiletimeConfigPath, 'utf-8').catch(() => {
27
+ if (!existsSync(runtimeConfigPath)) {
28
+ console.error(new Error("no eodash configuration found"))
29
+ }
30
+ })
31
+ userModules['user:config'] = typeof indexJs === 'string' ? indexJs : ''
32
+ return userModules
33
+ }
package/core/App.vue ADDED
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <v-app>
3
+ <RouterView v-slot="{ Component }">
4
+ <template v-if="Component">
5
+ <Suspense>
6
+ <!-- main content -->
7
+ <component :is="Component"></component>
8
+
9
+ <!-- loading state -->
10
+ <template #fallback>
11
+ Loading...
12
+ </template>
13
+ </Suspense>
14
+ </template>
15
+ </RouterView>
16
+ </v-app>
17
+ </template>
18
+
19
+ <script setup>
20
+ //
21
+ </script>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <v-main>
3
+ <eox-layout :gap="eodashConfig.template.gap ?? 2">
4
+ <eox-layout-item class="bg-widget" x="0" y="0" h="12" w="12">
5
+ <component :is="bgWidget.component" v-bind="bgWidget.props" />
6
+ </eox-layout-item>
7
+ <eox-layout-item v-for="(config, idx) in widgetsConfig" ref="itemEls" :key="idx" class="custom-widget"
8
+ :x="config.layout.x" :y="config.layout.y" :h="config.layout.h" :w="config.layout.w">
9
+
10
+ <v-btn position="absolute" variant="tonal" :style="slideBtns[idx].style" class="slide-btn"
11
+ @click="slideInOut(idx)">
12
+ <v-icon :icon="slideBtns[idx].active ? slideBtns[idx].icon.in : slideBtns[idx].icon.out" />
13
+ </v-btn>
14
+ <component :key="importedWidgets[idx].value.id" :is="importedWidgets[idx].value.component"
15
+ v-bind="importedWidgets[idx].value.props" />
16
+
17
+ </eox-layout-item>
18
+ </eox-layout>
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 { useSlidePanels } from '@/composables'
26
+ import { ref } from 'vue';
27
+ import '@eox/layout'
28
+
29
+ const eodashConfig = /** @type {EodashConfig} */ (inject(eodashConfigKey))
30
+
31
+ const [bgWidget] = useDefineWidgets([eodashConfig.template?.background])
32
+
33
+ const widgetsConfig = eodashConfig.template?.widgets
34
+
35
+ const importedWidgets = useDefineWidgets(widgetsConfig)
36
+ /**
37
+ * Layout items template ref
38
+ * @type {import('vue').Ref<HTMLElement[]>}
39
+ */
40
+ const itemEls = ref([])
41
+
42
+ const { slideBtns, slideInOut } = useSlidePanels(itemEls, widgetsConfig)
43
+ </script>
44
+ <style scoped>
45
+ eox-layout-item {
46
+ background: rgb(var(--v-theme-surface))
47
+ }
48
+
49
+ .bg-widget {
50
+ z-index: 0;
51
+ }
52
+
53
+ .custom-widget {
54
+ position: relative;
55
+ overflow: visible;
56
+ z-index: 1;
57
+ }
58
+ </style>
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <span class="d-flex flex-column fill-height overflow-auto">
3
+ <component :is="tagName" v-bind="properties" ref="elementRef" />
4
+ </span>
5
+ </template>
6
+
7
+ <script async setup>
8
+ import { useSTAcStore } from '@/store/stac';
9
+ import {
10
+ onUnmounted as whenUnMounted,
11
+ onMounted as whenMounted
12
+ } from 'vue';
13
+ import { ref } from 'vue';
14
+ import { useRouter } from 'vue-router';
15
+
16
+ const props = /** @type {WebComponentProps} */(defineProps({
17
+ link: {
18
+ type: [String, Function],
19
+ required: true
20
+ },
21
+ constructorProp: String,
22
+ tagName: {
23
+ type: String,
24
+ required: true
25
+ },
26
+ properties: {
27
+ type: Object,
28
+ default: () => {
29
+ return {}
30
+ }
31
+ },
32
+ onMounted: Function,
33
+ onUnmounted: Function
34
+ }))
35
+
36
+
37
+ const getWebComponent = async () => typeof props.link === 'string' ?
38
+ await import( /* @vite-ignore */props.link) : await props.link()
39
+
40
+ const imported = await getWebComponent().catch(e => {
41
+ console.error(e)
42
+ })
43
+
44
+ const defined = customElements.get(props.tagName)
45
+
46
+ // if the imported link doesn't define the custom tag provided
47
+ if (!defined && props.constructorProp) {
48
+ const Constructor = imported[props.constructorProp]
49
+ customElements.define(props.tagName, Constructor)
50
+ }
51
+
52
+ const store = useSTAcStore()
53
+
54
+ /**
55
+ * @template {HTMLElement} CE
56
+ * @type {import('vue').Ref<CE|null>}
57
+ */
58
+ const elementRef = ref(null)
59
+ const router = useRouter()
60
+
61
+ whenMounted(() => {
62
+ props.onMounted?.(elementRef.value, store, router)
63
+ })
64
+
65
+ whenUnMounted(() => {
66
+ props.onUnmounted?.(elementRef.value, store, router)
67
+ })
68
+ </script>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <v-footer ref="footer" :height="mdAndDown ? '48px' : 'auto'" color="secondary" app class="d-flex justify-space-between">
3
+ <p class="pt-0 footer-text">
4
+ Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet. Mauris cursus commodo interdum.
5
+ </p>
6
+ <div class="footer-text">
7
+ {{ new Date().getFullYear() }} — <strong>{{ title }}</strong>
8
+ </div>
9
+ </v-footer>
10
+ </template>
11
+ <script setup>
12
+ import { eodashConfigKey } from '@/store/Keys';
13
+ import { ref } from 'vue';
14
+ import { inject } from 'vue';
15
+ import { useDisplay } from 'vuetify/lib/framework.mjs';
16
+
17
+ /**
18
+ * Footer template ref
19
+ * @type {import('vue').Ref<import('vuetify/lib/components/index.mjs').VFooter | null>}
20
+ */
21
+ const footer = ref(null)
22
+ const eodashConfig = /** @type {EodashConfig} */(inject(eodashConfigKey))
23
+
24
+ const title = eodashConfig.brand?.shortName ?? eodashConfig.brand?.name
25
+ const { mdAndDown } = useDisplay()
26
+ </script>
27
+ <style scoped lang='scss'>
28
+ .footer-text {
29
+ font-size: 0.8rem;
30
+ }
31
+ </style>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <v-app-bar color="primary">
3
+ <v-app-bar-title class="cursor-pointer">{{ title }}</v-app-bar-title>
4
+ <v-toolbar-items v-if="eodashConfig.routes">
5
+ <v-btn v-for="route in eodashConfig.routes" :key="route.to" variant="text" @click="navigateTo(route.to)">
6
+ {{ route.title }}
7
+ </v-btn>
8
+ </v-toolbar-items>
9
+ <v-img class="mx-12 logo" :src="eodashConfig.brand?.logo" />
10
+ </v-app-bar>
11
+ </template>
12
+ <script setup>
13
+ import { eodashConfigKey } from '@/store/Keys';
14
+ import { inject } from 'vue';
15
+ import { useRouter } from 'vue-router';
16
+
17
+ const eodashConfig = /** @type {EodashConfig} */(inject(eodashConfigKey))
18
+
19
+ const title = eodashConfig.brand?.name
20
+
21
+ const { push } = useRouter()
22
+
23
+ /**
24
+ * @param {string} to
25
+ */
26
+ const navigateTo = (to) => {
27
+ if (to.toLowerCase().startsWith('http')) {
28
+ window.open(to, '_self')
29
+ } else {
30
+ push(to)
31
+ }
32
+ }
33
+ </script>
34
+ <style scoped lang='scss'>
35
+ .logo {
36
+ max-width: 140px;
37
+ }
38
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <iframe :src="src" style="width: 100%; height: 100%"></iframe>
3
+ </template>
4
+ <script setup>
5
+ defineProps({
6
+ src: {
7
+ type: String,
8
+ required: true
9
+ }
10
+ })
11
+ </script>