Compare commits
No commits in common. "master" and "2806e8d88982979a71bcbd3f9c654910fd4c9af0" have entirely different histories.
master
...
2806e8d889
@ -1,3 +0,0 @@
|
||||
dist
|
||||
node_modules
|
||||
public
|
13
.eslintrc
13
.eslintrc
@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"@antfu"
|
||||
],
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"camelcase": "off"
|
||||
},
|
||||
"plugins": [
|
||||
"snakecasejs"
|
||||
]
|
||||
}
|
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Jesús Pérez Lorenzo based in Anthony Fu developments
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,4 +1,4 @@
|
||||
# Status interface for ZTerton services
|
||||
# Status iterface for ZTerton services
|
||||
|
||||
<img style="margin-top: 1em;width: 500px;border: 0" alt="Fork me on GitHub" src="assets/images/status.svg?sanitize=true">
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
{"profile":{"image":"jesus.jpg"},"checkin":0,"sidebar":{"header":{"title":"Services Status"},"menu_items":[{"title":"app.title","icon_on":"carbon-campsite","name_to":"app.title","show_to":false,"click":"tophome","type":"app_link","pfx":""},{"title":"nav.Tasks","ctx":"home","icon_on":"carbon-services","name_to":"navm.Tasks","show_to":true,"click":"tsksrvcs","type":"app_link","pfx":""},{"title":"nav.Apps","ctx":"home","icon_on":"carbon-application","name_to":"navm.Apps","show_to":true,"click":"appsrvcs","type":"app_link","pfx":""},{"title":"nav.Informations","ctx":"home","icon_on":"carbon-operation","name_to":"navm.Infos","show_to":true,"click":"srvcstatus","type":"app_link","pfx":""}],"footer":{"itm":{"title":"menu.logout","name_to":"Logout","icon_on":"carbon-logout","type":"router_link"}}},"header":{"title":"Status","name_to":"Home","logo":"","navbar":{"menuright":{"notify":true,"search":true,"title":"menu.user","items":[{"title":"menu.your-profile","type":"app_link","click":"profile"},{"title":"menu.settings","type":"app_link","click":"user_settings"},{"title":"menu.sign-out","type":"router_link","name_to":"Logout"}]}}},"footer":{"left_items":[{"title":"LibreCloud © 2021","icon_on":"","href":"https://librecloud.online","type":"app_link"}],"right_items":[{"title":"LibreCloud","img":"app_w","href":"https://librecloud.online","type":"app_link"}],"central_items":[{"title":"button.home","mode":"icon","icon_on":"carbon-campsite","click":"tophome","type":"app_link","pfx":""},{"title":"button.toggle_dark","mode":"icon","icon_on":"carbon-moon","icon-off":"carbon-sun","vif":"isDark","click":"toggleDark","type":"app_link"},{"title":"button.toggle_langs","mode":"icon","icon_on":"carbon-language","click":"toggleLocales","type":"app_link"},{"title":"GitHub","mode":"icon","icon_on":"carbon-logo-github","href":"https://rlung.librecloud.online","type":"a_blank"},{"title":"button.about","mode":"icon","icon_on":"carbon-dicom-overlay","to":"/about","type":"router_link"},{"title":"button.login","mode":"icon","icon_on":"carbon-login","vif":"notValidUser","to":"/login","type":"router_link"}]}}
|
111
assets/defs.yaml
111
assets/defs.yaml
@ -1,111 +0,0 @@
|
||||
profile:
|
||||
image: jesus.jpg
|
||||
# checkin time in millisecond or 0 for not checkin
|
||||
checkin: 0
|
||||
# checkin: 60000
|
||||
sidebar:
|
||||
header:
|
||||
title: Services Status
|
||||
menu_items:
|
||||
- title: app.title
|
||||
icon_on: carbon-campsite
|
||||
name_to: app.title
|
||||
show_to: false
|
||||
click: tophome
|
||||
type: app_link
|
||||
pfx: ''
|
||||
- title: nav.Tasks
|
||||
ctx: home
|
||||
icon_on: carbon-services
|
||||
name_to: navm.Tasks
|
||||
show_to: true
|
||||
click: tsksrvcs
|
||||
type: app_link
|
||||
pfx: ''
|
||||
- title: nav.Apps
|
||||
ctx: home
|
||||
icon_on: carbon-application
|
||||
name_to: navm.Apps
|
||||
show_to: true
|
||||
click: appsrvcs
|
||||
type: app_link
|
||||
pfx: ''
|
||||
- title: nav.Informations
|
||||
ctx: home
|
||||
icon_on: carbon-operation
|
||||
name_to: navm.Infos
|
||||
show_to: true
|
||||
click: srvcstatus
|
||||
type: app_link
|
||||
pfx: ''
|
||||
footer:
|
||||
itm:
|
||||
title: menu.logout
|
||||
name_to: Logout
|
||||
icon_on: carbon-logout
|
||||
type: router_link
|
||||
header:
|
||||
title: Status
|
||||
name_to: Home
|
||||
logo: ""
|
||||
navbar:
|
||||
menuright:
|
||||
notify: true
|
||||
search: true
|
||||
title: menu.user
|
||||
items:
|
||||
- title: menu.your-profile
|
||||
type: app_link
|
||||
click: profile
|
||||
- title: menu.settings
|
||||
type: app_link
|
||||
click: user_settings
|
||||
- title: menu.sign-out
|
||||
type: router_link
|
||||
name_to: Logout
|
||||
footer:
|
||||
left_items:
|
||||
- title: 'LibreCloud © 2021'
|
||||
icon_on: ''
|
||||
href: https://librecloud.online
|
||||
type: app_link
|
||||
right_items:
|
||||
- title: 'LibreCloud'
|
||||
img: 'app_w'
|
||||
href: https://librecloud.online
|
||||
type: app_link
|
||||
central_items:
|
||||
- title: button.home
|
||||
mode: icon
|
||||
icon_on: carbon-campsite
|
||||
click: tophome
|
||||
type: app_link
|
||||
pfx: ''
|
||||
- title: button.toggle_dark
|
||||
mode: icon
|
||||
icon_on: carbon-moon
|
||||
icon-off: carbon-sun
|
||||
vif: isDark
|
||||
click: toggleDark
|
||||
type: app_link
|
||||
- title: button.toggle_langs
|
||||
mode: icon
|
||||
icon_on: carbon-language
|
||||
click: toggleLocales
|
||||
type: app_link
|
||||
- title: GitHub
|
||||
mode: icon
|
||||
icon_on: carbon-logo-github
|
||||
href: https://rlung.librecloud.online
|
||||
type: a_blank
|
||||
- title: button.about
|
||||
mode: icon
|
||||
icon_on: carbon-dicom-overlay
|
||||
to: /about
|
||||
type: router_link
|
||||
- title: button.login
|
||||
mode: icon
|
||||
icon_on: carbon-login
|
||||
vif: notValidUser
|
||||
to: /login
|
||||
type: router_link
|
@ -1,12 +0,0 @@
|
||||
<svg id="icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path d="M25.8218,10.124a9.9991,9.9991,0,0,0-19.6435,0A7.4964,7.4964,0,0,0,7.5,25H8V23H7.5a5.4961,5.4961,0,0,1-.3769-10.9795l.8364-.0571.09-.8335a7.9979,7.9979,0,0,1,15.9013,0l.09.8335.8364.0571A5.4961,5.4961,0,0,1,24.5,23H24v2h.5a7.4964,7.4964,0,0,0,1.3218-14.876Z" transform="translate(0 0)"/>
|
||||
<path d="M23,22V20H20.8989a4.9678,4.9678,0,0,0-.7319-1.7529l1.49-1.49-1.414-1.414-1.49,1.49A4.9678,4.9678,0,0,0,17,16.1011V14H15v2.1011a4.9678,4.9678,0,0,0-1.7529.7319l-1.49-1.49-1.414,1.414,1.49,1.49A4.9678,4.9678,0,0,0,11.1011,20H9v2h2.1011a4.9678,4.9678,0,0,0,.7319,1.7529l-1.49,1.49,1.414,1.414,1.49-1.49A4.9678,4.9678,0,0,0,15,25.8989V28h2V25.8989a4.9678,4.9678,0,0,0,1.7529-.7319l1.49,1.49,1.414-1.414-1.49-1.49A4.9678,4.9678,0,0,0,20.8989,22Zm-7,2a3,3,0,1,1,3-3A3.0033,3.0033,0,0,1,16,24Z" transform="translate(0 0)"/>
|
||||
<rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.0 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.7 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
@ -1 +0,0 @@
|
||||
cat defs.yaml | yq e -o=json | jq -cr > defs.json
|
172
auto-imports.d.ts
vendored
172
auto-imports.d.ts
vendored
@ -1,172 +0,0 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
// We suggest you to commit this file into source control
|
||||
declare global {
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||
const biSyncRef: typeof import('@vueuse/core')['biSyncRef']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const computedInject: typeof import('@vueuse/core')['computedInject']
|
||||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
|
||||
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const h: typeof import('vue')['h']
|
||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactify: typeof import('@vueuse/core')['reactify']
|
||||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const syncRef: typeof import('@vueuse/core')['syncRef']
|
||||
const templateRef: typeof import('@vueuse/core')['templateRef']
|
||||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toReactive: typeof import('@vueuse/core')['toReactive']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
|
||||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
|
||||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
|
||||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
||||
const until: typeof import('@vueuse/core')['until']
|
||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
|
||||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
||||
const useClipboard: typeof import('@vueuse/core')['useClipboard']
|
||||
const useCounter: typeof import('@vueuse/core')['useCounter']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVar: typeof import('@vueuse/core')['useCssVar']
|
||||
const useDark: typeof import('@vueuse/core')['useDark']
|
||||
const useDebounce: typeof import('@vueuse/core')['useDebounce']
|
||||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
|
||||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
|
||||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
|
||||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
|
||||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
|
||||
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
|
||||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
|
||||
const useDraggable: typeof import('@vueuse/core')['useDraggable']
|
||||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
|
||||
const useElementSize: typeof import('@vueuse/core')['useElementSize']
|
||||
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
|
||||
const useEventBus: typeof import('@vueuse/core')['useEventBus']
|
||||
const useEventListener: typeof import('@vueuse/core')['useEventListener']
|
||||
const useEventSource: typeof import('@vueuse/core')['useEventSource']
|
||||
const useFavicon: typeof import('@vueuse/core')['useFavicon']
|
||||
const useFetch: typeof import('@vueuse/core')['useFetch']
|
||||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
||||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
||||
const useHead: typeof import('@vueuse/head')['useHead']
|
||||
const useI18n: typeof import('vue-i18n')['useI18n']
|
||||
const useIdle: typeof import('@vueuse/core')['useIdle']
|
||||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
|
||||
const useInterval: typeof import('@vueuse/core')['useInterval']
|
||||
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
|
||||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
|
||||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
|
||||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
|
||||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
|
||||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
|
||||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
|
||||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
||||
const useMouse: typeof import('@vueuse/core')['useMouse']
|
||||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
|
||||
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
|
||||
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
|
||||
const useNetwork: typeof import('@vueuse/core')['useNetwork']
|
||||
const useNow: typeof import('@vueuse/core')['useNow']
|
||||
const useOnline: typeof import('@vueuse/core')['useOnline']
|
||||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
|
||||
const useParallax: typeof import('@vueuse/core')['useParallax']
|
||||
const usePermission: typeof import('@vueuse/core')['usePermission']
|
||||
const usePointer: typeof import('@vueuse/core')['usePointer']
|
||||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
|
||||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
|
||||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
|
||||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
|
||||
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
||||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
||||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
||||
const useRoute: typeof import('vue-router')['useRoute']
|
||||
const useRouter: typeof import('vue-router')['useRouter']
|
||||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
||||
const useScroll: typeof import('@vueuse/core')['useScroll']
|
||||
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
|
||||
const useShare: typeof import('@vueuse/core')['useShare']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
|
||||
const useStorage: typeof import('@vueuse/core')['useStorage']
|
||||
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
||||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
||||
const useThrottle: typeof import('@vueuse/core')['useThrottle']
|
||||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
||||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
||||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
||||
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
||||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
||||
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
|
||||
const useTitle: typeof import('@vueuse/core')['useTitle']
|
||||
const useToggle: typeof import('@vueuse/core')['useToggle']
|
||||
const useTransition: typeof import('@vueuse/core')['useTransition']
|
||||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
|
||||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
|
||||
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
|
||||
const useVModel: typeof import('@vueuse/core')['useVModel']
|
||||
const useVModels: typeof import('@vueuse/core')['useVModels']
|
||||
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
|
||||
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
|
||||
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
|
||||
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
|
||||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
|
||||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
|
||||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchOnce: typeof import('@vueuse/core')['watchOnce']
|
||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||
const whenever: typeof import('@vueuse/core')['whenever']
|
||||
}
|
||||
export {}
|
34
components.d.ts
vendored
34
components.d.ts
vendored
@ -1,34 +0,0 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/vue-next/pull/3399
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AccordionView: typeof import('./src/components/AccordionView.vue')['default']
|
||||
AppImg: typeof import('./src/components/icons/AppImg.vue')['default']
|
||||
AppLogoText: typeof import('./src/components/icons/AppLogoText.vue')['default']
|
||||
AppLogoV: typeof import('./src/components/icons/AppLogoV.vue')['default']
|
||||
CarbonCampsite: typeof import('~icons/carbon/campsite')['default']
|
||||
CarbonCheck: typeof import('~icons/carbon/check')['default']
|
||||
CarbonCheckmark: typeof import('~icons/carbon/checkmark')['default']
|
||||
CarbonLanguage: typeof import('~icons/carbon/language')['default']
|
||||
CarbonLogin: typeof import('~icons/carbon/login')['default']
|
||||
CarbonLogoGithub: typeof import('~icons/carbon/logo-github')['default']
|
||||
CarbonLogout: typeof import('~icons/carbon/logout')['default']
|
||||
CarbonMoon: typeof import('~icons/carbon/moon')['default']
|
||||
CarbonPedestrian: typeof import('~icons/carbon/pedestrian')['default']
|
||||
CarbonScript: typeof import('~icons/carbon/script')['default']
|
||||
CarbonSearch: typeof import('~icons/carbon/search')['default']
|
||||
CarbonSun: typeof import('~icons/carbon/sun')['default']
|
||||
CarbonWarning: typeof import('~icons/carbon/warning')['default']
|
||||
CloudGroups: typeof import('./src/components/CloudGroups.vue')['default']
|
||||
CloudServices: typeof import('./src/components/CloudServices.vue')['default']
|
||||
CloudSrvc: typeof import('./src/components/CloudSrvc.vue')['default']
|
||||
Footer: typeof import('./src/components/Footer.vue')['default']
|
||||
MenuLocales: typeof import('./src/components/menus/MenuLocales.vue')['default']
|
||||
NavMenu: typeof import('./src/components/NavMenu.vue')['default']
|
||||
ProfileView: typeof import('./src/components/ProfileView.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
export { }
|
26
index.html
26
index.html
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||
<title>Vitesse Lite</title>
|
||||
<meta name="description" content="Opinionated Vite Starter Template">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
(function() {
|
||||
// window.ROOT_LOCATION='https://10.11.5.1'
|
||||
// window.ROOT_LOCATION='https://status.librecloud.online'
|
||||
// window.ROOT_LOCATION='https://localhost:8302'
|
||||
window.ROOT_LOCATION='https://localhost:8302'
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
const setting = localStorage.getItem('color-schema') || 'auto'
|
||||
if (setting === 'dark' || (prefersDark && setting !== 'light'))
|
||||
document.documentElement.classList.toggle('dark', true)
|
||||
})()
|
||||
</script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +0,0 @@
|
||||
## i18n
|
||||
|
||||
This directory is to serve your locale translation files. YAML under this folder would be loaded automatically and register with their filenames as locale code.
|
||||
|
||||
Check out [`vue-i18n`](https://github.com/intlify/vue-i18n-next) for more details.
|
||||
|
||||
If you are using VS Code, [`i18n Ally`](https://github.com/lokalise/i18n-ally) is recommended to make the i18n experience better.
|
151
locales/en.yml
151
locales/en.yml
@ -1,151 +0,0 @@
|
||||
All: All
|
||||
auth:
|
||||
invalidcredentials: Invalid credentials
|
||||
loginForm: ''
|
||||
newaccount: new account
|
||||
password: password
|
||||
register: Register
|
||||
signin: Sign in
|
||||
subHeading: Login info
|
||||
subTitle: ''
|
||||
wellcome: Wellcome !
|
||||
bc:
|
||||
home: librecloud
|
||||
topographic_anatomy: klouds
|
||||
bm:
|
||||
topographic-anatomy: Topographic Anatomy
|
||||
button:
|
||||
about: About
|
||||
back: Back
|
||||
cancel: Cancel
|
||||
close-panel: Close panel
|
||||
delete: Delete
|
||||
go: Go
|
||||
home: Home
|
||||
new: Nuevo
|
||||
reset: Reset
|
||||
save: Save
|
||||
toggle_dark: Toggle dark mode
|
||||
toggle_langs: Change language
|
||||
login: Login
|
||||
logout: Logout
|
||||
connection:
|
||||
error: Error conexión
|
||||
dashboard: Dashboard
|
||||
en: English
|
||||
entry:
|
||||
Apps: Apps
|
||||
Code: Code
|
||||
DB: DB
|
||||
Data: Data
|
||||
DataCode: Data / Code
|
||||
Document: Document
|
||||
Documents: Documents
|
||||
Macro: Macro
|
||||
Profiles: Profiles/roles
|
||||
Schema: Schema
|
||||
Services: Services
|
||||
Shortcut: Shortcut
|
||||
Template: Template
|
||||
Trans: Translations
|
||||
es: Español
|
||||
form:
|
||||
delete_done: Delete done
|
||||
delete_error: Delete Error
|
||||
save_done: Data saved
|
||||
save_error: Data save Error
|
||||
intro:
|
||||
desc: Opinionated Vite Starter Template
|
||||
dynamic-route: Demo of dynamic route
|
||||
hi: Hi, {name}!
|
||||
whats-your-name: What's your name?
|
||||
login:
|
||||
end_session: End session
|
||||
form: Credentials
|
||||
invalidcredentials: Incorrect data
|
||||
newuser: New user
|
||||
nodata: No data
|
||||
password: Password
|
||||
register: Register
|
||||
reset: Reset
|
||||
see_you_soon: See You soon !
|
||||
signin: Signin
|
||||
subHeading: Access
|
||||
subtitle: LibreCloud online
|
||||
user_email: User / email
|
||||
wellcome: Wellcome
|
||||
menu:
|
||||
copy: Copy
|
||||
data-grid: Data Grid
|
||||
edit: Edit
|
||||
edit-items: Edit items
|
||||
home: Home
|
||||
login: Init session
|
||||
logout: Close session
|
||||
new: New
|
||||
open-recent: Open recent
|
||||
paste: Paste
|
||||
save: Save
|
||||
settings: Configuration
|
||||
sign-in: Signin
|
||||
sign-out: Signout
|
||||
your-profile: Your profile
|
||||
message:
|
||||
loadding: Loading
|
||||
not-found: Not found
|
||||
notes: Notes
|
||||
notifications:
|
||||
content: content
|
||||
notifications: Notifications
|
||||
search:
|
||||
search: Search
|
||||
settings:
|
||||
above-noedit: ALL above options in "off" configure mode for
|
||||
aside: Aside
|
||||
col: Col
|
||||
columns-settings: Columns
|
||||
filter: Filter
|
||||
grid: Grid
|
||||
grid-options: Grid options
|
||||
hidden: Hide
|
||||
id: Id
|
||||
list: List
|
||||
main: Main
|
||||
no-edition: no edition
|
||||
pagination: Pagination
|
||||
panels: Panels
|
||||
pos: Pos
|
||||
position: position
|
||||
select: Select
|
||||
select-config: Select configuration
|
||||
select-grid-type: Select grid type
|
||||
setting-id: Identificator
|
||||
settings: Configuration
|
||||
slide: Modal
|
||||
sort: Sort
|
||||
table: Table
|
||||
undefined: Undefined
|
||||
srvc:
|
||||
mailserver::smtp::imap: mail imap
|
||||
mailserver::smtp::pop: mail pop
|
||||
mailserver::smtp::tls: mail tls
|
||||
mailserver::smtp: mail smtp
|
||||
pending: Pendiente
|
||||
nav:
|
||||
Services Status: Services Status Servicios
|
||||
Tasks: Services
|
||||
Search: Search
|
||||
Apps: Applications
|
||||
Informations: Informations
|
||||
navm:
|
||||
Infos: Infos
|
||||
Status: Status
|
||||
Tasks: Serv.
|
||||
Apps: Aplic.
|
||||
app:
|
||||
title: Status
|
||||
profile:
|
||||
Close: Close
|
||||
Settings: Settings
|
||||
backgroud_color: Background color
|
||||
Logout: Logout
|
155
locales/es.yml
155
locales/es.yml
@ -1,155 +0,0 @@
|
||||
All: All
|
||||
auth:
|
||||
invalidcredentials: Invalid credentials
|
||||
loginForm: ''
|
||||
newaccount: new account
|
||||
password: password
|
||||
register: Register
|
||||
signin: Sign in
|
||||
subHeading: Login info
|
||||
subTitle: ''
|
||||
wellcome: Wellcome !
|
||||
bc:
|
||||
home: librecloud
|
||||
topographic_anatomy: klouds
|
||||
bm:
|
||||
topographic-anatomy: Anatomía topográfica
|
||||
button:
|
||||
about: Acerca de
|
||||
back: Atrás
|
||||
cancel: Cancelar
|
||||
close-panel: Cerarr panel
|
||||
delete: Borrar
|
||||
go: Ir
|
||||
home: Inicio
|
||||
new: Nuevo
|
||||
reset: Reset
|
||||
save: Guardar
|
||||
toggle_dark: Alternar modo oscuro
|
||||
toggle_langs: Cambiar idiomas
|
||||
login: Login
|
||||
logout: Desconectar
|
||||
connection:
|
||||
error: Error conexión
|
||||
dashboard: Panel de control
|
||||
en: English
|
||||
entry:
|
||||
Apps: Apps
|
||||
Code: Code
|
||||
DB: DB
|
||||
Data: Data
|
||||
DataCode: Data / Code
|
||||
Document: Document
|
||||
Documents: Documents
|
||||
Macro: Macro
|
||||
Profiles: Profiles/roles
|
||||
Schema: Schema
|
||||
Services: Services
|
||||
Shortcut: Shortcut
|
||||
Template: Template
|
||||
Trans: Translations
|
||||
es: Español
|
||||
form:
|
||||
delete_done: Borrado realizado
|
||||
delete_error: Error al borrar datos
|
||||
save_done: Datos guardados
|
||||
save_error: Error al guardar datos
|
||||
intro:
|
||||
desc: Plantilla de Inicio de Vite Dogmática
|
||||
dynamic-route: Demo de ruta dinámica
|
||||
hi: ¡Hola, {name}!
|
||||
whats-your-name: ¿Cómo te llamas?
|
||||
login:
|
||||
end_session: Sesión finalizada
|
||||
form: Credenciales
|
||||
invalidcredentials: Datos incorrectos
|
||||
newuser: Nuevo usuario
|
||||
nodata: No hay datos
|
||||
password: Password
|
||||
register: Registrarse
|
||||
reset: Reset
|
||||
see_you_soon: ¡ Nos vemos pronto !
|
||||
signin: Iniciar sesión
|
||||
subHeading: Acceso
|
||||
subtitle: LibreCloud online
|
||||
user_email: Usuario / email
|
||||
wellcome: Bienvenido/a
|
||||
menu:
|
||||
copy: Copiar
|
||||
data-grid: Cuadrícula de datos
|
||||
edit: Editar
|
||||
edit-items: Editar items
|
||||
home: Inicio
|
||||
login: Inicio sesión
|
||||
logout: Cerrar sesión
|
||||
new: Nuevo
|
||||
open-recent: Abrir reciente
|
||||
paste: Pegar
|
||||
save: Guardar
|
||||
settings: Configuración
|
||||
sign-in: Registrarse
|
||||
sign-out: Desconectar
|
||||
your-profile: Tu perfil
|
||||
message:
|
||||
loadding: Cargando
|
||||
not-found: No se ha encontrado
|
||||
notes: Notas
|
||||
notifications:
|
||||
content: contenido
|
||||
notifications: Notificiaciones
|
||||
search:
|
||||
search: Buscar
|
||||
settings:
|
||||
above-noedit: TODAS las opciones de arriba en "off" configuran el modo
|
||||
aside: Al lado
|
||||
col: Col
|
||||
columns-settings: Columnas
|
||||
filter: Filtrar
|
||||
grid: Cuadrícula
|
||||
grid-options: Opciones cuadrícula
|
||||
hidden: Ocultar
|
||||
id: Id
|
||||
list: Lista
|
||||
main: Principal
|
||||
no-edition: no edición
|
||||
pagination: Paginación
|
||||
panels: Paneles
|
||||
pos: Pos
|
||||
position: posición
|
||||
select: Seleccionar
|
||||
select-config: Seleccionar configuración
|
||||
select-grid-type: Seleccionar tipo cuadrícula
|
||||
setting-id: Identificador
|
||||
settings: Configuración
|
||||
slide: Modal
|
||||
sort: Ordenar
|
||||
table: Tabla
|
||||
undefined: No definido
|
||||
graphsettings:
|
||||
clouds: Clouds
|
||||
groups: Grupos
|
||||
srvc:
|
||||
mailserver::smtp::imap: correo imap
|
||||
mailserver::smtp::pop: correo pop
|
||||
mailserver::smtp::tls: correo tls
|
||||
mailserver::smtp: correo smtp
|
||||
pending: Pending
|
||||
nav:
|
||||
Informations: Informaciones
|
||||
Services Status: Status Servicios
|
||||
Tasks: Servicios
|
||||
Applications: Aplicaciones
|
||||
Apps: Aplicaciones
|
||||
Search: Buscar
|
||||
navm:
|
||||
Infos: Infos
|
||||
Status: Status
|
||||
Tasks: Serv.
|
||||
Apps: Aplic.
|
||||
app:
|
||||
title: Status
|
||||
profile:
|
||||
Close: Cerrar
|
||||
Settings: Configuración
|
||||
backgroud_color: Color de fondo
|
||||
Logout: Desconectar
|
17
netlify.toml
17
netlify.toml
@ -1,17 +0,0 @@
|
||||
[build.environment]
|
||||
NPM_FLAGS = "--prefix=/dev/null"
|
||||
NODE_VERSION = "14"
|
||||
|
||||
[build]
|
||||
publish = "dist"
|
||||
command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build"
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
|
||||
[[headers]]
|
||||
for = "/manifest.webmanifest"
|
||||
[headers.values]
|
||||
Content-Type = "application/manifest+json"
|
50
package.json
50
package.json
@ -1,50 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --port 3333 --open",
|
||||
"build": "cross-env NODE_ENV=production vite build --debug",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@animxyz/vue": "^0.6.4",
|
||||
"@headlessui/vue": "^1.4.1",
|
||||
"@intlify/vite-plugin-vue-i18n": "^2.4.0",
|
||||
"@vueuse/core": "^6.6.2",
|
||||
"@vueuse/head": "^0.6.0",
|
||||
"a17t": "^0.5.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"toastify-js": "^1.11.2",
|
||||
"vite-imagetools": "^3.8.0",
|
||||
"vite-plugin-inspect": "^0.3.9",
|
||||
"vue": "^3.2.20",
|
||||
"vue-demi": "^0.11.4",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue-router": "^4.0.12",
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.9.0",
|
||||
"@iconify-json/carbon": "^1.0.7",
|
||||
"@types/node": "^16.11.1",
|
||||
"@vitejs/plugin-vue": "^1.9.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^7.32.0",
|
||||
"pnpm": "^6.18.0",
|
||||
"typescript": "^4.4.4",
|
||||
"unplugin-auto-import": "^0.4.12",
|
||||
"unplugin-icons": "^0.12.16",
|
||||
"unplugin-vue-components": "^0.15.6",
|
||||
"vite": "^2.6.10",
|
||||
"vite-plugin-md": "^0.11.2",
|
||||
"vite-plugin-pages": "^0.18.1",
|
||||
"vite-plugin-vue-layouts": "^0.5.0",
|
||||
"vite-plugin-windicss": "^1.4.12"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "@antfu/eslint-config",
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<style>
|
||||
path { fill: #222; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #ffffff; }
|
||||
}
|
||||
</style>
|
||||
<path d="M27.562 26L17.17 8.928l2.366-3.888L17.828 4L16 7.005L14.17 4l-1.708 1.04l2.366 3.888L4.438 26H2v2h28v-2zM16 10.85L25.22 26H17v-8h-2v8H6.78z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 347 B |
@ -1,2 +0,0 @@
|
||||
User-agent: *
|
||||
Allow: /
|
37
src/App.vue
37
src/App.vue
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<component :is="layout" class="text-gray-700 dark:text-gray-200">
|
||||
<router-view />
|
||||
</component>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
// <Footer />
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
import { AppDefsAction } from '~/store/types'
|
||||
// import AppLayout from '~/layouts/AppLayout.vue'
|
||||
import { useHead } from '@vueuse/head'
|
||||
// https://github.com/vueuse/head
|
||||
// you can use this to manipulate the document head in any components,
|
||||
// they will be rendered correctly in the html results with vite-ssg
|
||||
|
||||
import defs from '../assets/defs.json'
|
||||
|
||||
const store = useStore()
|
||||
useHead({
|
||||
title: 'Status',
|
||||
meta: [
|
||||
{ name: 'description', content: 'Opinionated Vite Starter Template' },
|
||||
],
|
||||
})
|
||||
const { currentRoute } = useRouter()
|
||||
const appLayout = 'AppLayout'
|
||||
const layout = computed(() => {
|
||||
return `${currentRoute.value.meta.layout || appLayout}`
|
||||
})
|
||||
onBeforeMount(() => {
|
||||
if (defs) {
|
||||
store.dispatch(AppDefsAction.addDefs, { key: 'ui', defs })
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,46 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { StatusItemType } from '~/typs/clouds'
|
||||
const props = defineProps<{
|
||||
items: Array<StatusItemType>
|
||||
title: string
|
||||
}>()
|
||||
const items = ref(props.items as Array<StatusItemType>)
|
||||
const on_item = (it: any) => {
|
||||
items.value = items.value.map((i: StatusItemType) => ({ ...i, isOpen: i.title !== it.title ? false : !i.isOpen }))
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="container mx-auto px-2 py-2">
|
||||
<div id="srvcstatus" class="text-3xl bg-light-500 p-3 rounded-xl">
|
||||
{{ props.title }}
|
||||
</div>
|
||||
<div class="leading-loose text-lg mt-6">
|
||||
<div v-for="item in items" :key="item.title">
|
||||
<div>
|
||||
<button
|
||||
class="w-full font-bold border-b border-gray-400 py-3 flex justify-between items-center mt-4"
|
||||
@click="on_item(item)"
|
||||
>
|
||||
<!-- Specs has it that only one component can be open at a time and also you should be able to toggle the open state of the active component too -->
|
||||
<div>{{ item.title }}</div>
|
||||
<svg v-show="!item.isOpen" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path
|
||||
class="heroicon-ui"
|
||||
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm1-9h2a1 1 0 010 2h-2v2a1 1 0 01-2 0v-2H9a1 1 0 010-2h2V9a1 1 0 012 0v2z"
|
||||
/>
|
||||
</svg>
|
||||
<svg v-show="item.isOpen" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path
|
||||
class="heroicon-ui"
|
||||
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm4-8a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div v-show="item.isOpen" class="text-gray-700 text-sm mt-2">
|
||||
{{ item.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,115 +0,0 @@
|
||||
<template>
|
||||
<div class="breadcrump-box transition duration-300 ease-in-out py-3 ">
|
||||
<div class="card-body">
|
||||
<nav aria-label="breadcrumb" class="flex flex-wrap">
|
||||
<ul v-for="(itm,i) in arrBcPath" :key="`bread-${i}`" class="breadcrumb">
|
||||
<li v-if="i == 0 && itm[0] == '#'" class="breadcrumb-item flex-1 cursor-pointer" @click="bookselec(itm[i])">
|
||||
<span class="shield">
|
||||
<span class="icon">
|
||||
<svg
|
||||
v-if="itm === '#fa-cloud'"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fas"
|
||||
data-icon="cloud"
|
||||
class="svg-inline--fa fa-cloud fa-w-16 dark:text-white text-blue-400"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 640 512"
|
||||
><path fill="currentColor" d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"></path></svg>
|
||||
<svg
|
||||
v-if="itm === '#fa-book'"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fad"
|
||||
data-icon="book-reader"
|
||||
class="svg-inline--fa fa-book-reader fa-w-16 dark:text-white"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
><g class="fa-group"><path class="fa-secondary" fill="currentColor" d="M256 192a96 96 0 1 1 96-96 96 96 0 0 1-96 96z" opacity="0.4" /><path class="fa-primary" fill="currentColor" d="M233.59 241.1c-59.33-36.32-155.43-46.3-203.79-49C13.55 191.13 0 203.51 0 219.14v222.8c0 14.33 11.59 26.28 26.49 27.06 43.66 2.29 132 10.68 193 41.43 9.37 4.72 20.48-1.71 20.48-11.87v-246a13.31 13.31 0 0 0-6.38-11.46zm248.61-49c-48.35 2.74-144.46 12.73-203.78 49a13.56 13.56 0 0 0-6.42 11.63v245.79c0 10.19 11.14 16.63 20.54 11.9 61-30.72 149.32-39.11 193-41.4C500.42 468.24 512 456.29 512 442V219.14c0-15.63-13.55-28.01-29.8-27.09z" /></g></svg>
|
||||
<span v-else class="iconify" :data-icon="itm.replace('#','').replace('fa-','fa:')" />
|
||||
</span>
|
||||
</span>
|
||||
<span class="slash text-xs">/</span>
|
||||
</li>
|
||||
<li v-else-if="arrBcPath[i+1]" class="breadcrumb-item flex-1 cursor-pointer">
|
||||
<a href="#{itm}" class="mx-1 leading-tight text-xs" @click="(e) => { e.preventDefault(); $router.push(`/${itm}`)}">
|
||||
{{ translate(itm) }}</a>
|
||||
<span class="slash text-xs">/</span>
|
||||
</li>
|
||||
<li v-else class="breadcrumb-item active flex-1 mx-1 ml-1 leading-tight text-xs cursor-pointer" aria-current="page">
|
||||
<span style="line-height: 2.2em" @click="bookselec(itm)"> {{ translate(itm) }} </span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({
|
||||
bcPath: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['onBookSelec'])
|
||||
// const currAppTab = ref('')
|
||||
const arrBcPath = computed(() => props.bcPath.split('/'))
|
||||
const bookselec = (book: any) => {
|
||||
emit('onBookSelec', book)
|
||||
}
|
||||
const { t, locale } = useI18n()
|
||||
const translate = (txt: any) => {
|
||||
const tr_txt = t(`bc.${txt}`)
|
||||
return tr_txt === `bc.${txt}` ? txt : tr_txt
|
||||
}
|
||||
// $: arrBcPath=bcPath.split("/");
|
||||
// const bookselec = (e) => {
|
||||
// dispatch("bookselec","main");
|
||||
// // console.log(`mode: ${mode} id: ${id} target: ${target}`);
|
||||
// const parent=".tabs-menu";
|
||||
// document.querySelectorAll(`${parent} span`).forEach(it => it.classList.remove('active') )
|
||||
// // e.target.parentElement.childNodes.forEach(it => it.classList.remove('active') )
|
||||
// // e.target.classList.add('active')
|
||||
// document.querySelectorAll(`${parent} span`).forEach(it => it.classList.remove('active') )
|
||||
// document.querySelectorAll(`${parent} span.itm-${id}`).forEach(it => it.classList.add('active') )
|
||||
// dispatch("choosetab",id);
|
||||
// //const tab=document.querySelector(`#${currTab}`);
|
||||
// //if (tab) { }
|
||||
// }
|
||||
</script>
|
||||
<style scoped>
|
||||
.breadcrumb-item .shield {
|
||||
padding: 0em 0.5em;
|
||||
/* margin-top: -0.4em; */
|
||||
}
|
||||
.breadcrumb-item .icon {
|
||||
padding: 0em;
|
||||
margin: 0;
|
||||
}
|
||||
.breadcrumb-item .icon svg {
|
||||
width: 100%;
|
||||
}
|
||||
.breadcrumb .breadcrumb-item {
|
||||
position: relative;
|
||||
}
|
||||
.breadcrumb-item a:hover {
|
||||
padding-bottom: 0.2em;
|
||||
border-bottom: 1px solid rgb(154, 154, 154);
|
||||
border-bottom-width: thin;
|
||||
border-bottom-style: dashed;
|
||||
}
|
||||
/*
|
||||
.breadcrumb .breadcrumb-item:first-child {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
*/
|
||||
.breadcrumb .breadcrumb-item:not(:last-child):after {
|
||||
content: '/';
|
||||
color: rgb(154, 154, 154);
|
||||
}
|
||||
</style>
|
@ -1,61 +0,0 @@
|
||||
<template>
|
||||
<div :id="props.target" class="border-t-gray-800 border-opacity-90 bg-light-600 dark:bg-gray-600 w-full p-4 mt-4 md:mt-2 rounded-l">
|
||||
<div class="flex flex justify-between text-2xl bg-light-800 dark:bg-gray-400 p-3 rounded-xl" @click="on_group_item(props.target,$event)">
|
||||
<div class="dark:text-white"> {{ props.title }} </div>
|
||||
<svg v-show="props.hide" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path
|
||||
class="heroicon-ui"
|
||||
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm1-9h2a1 1 0 010 2h-2v2a1 1 0 01-2 0v-2H9a1 1 0 010-2h2V9a1 1 0 012 0v2z"
|
||||
/>
|
||||
</svg>
|
||||
<svg v-show="!props.hide" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path
|
||||
class="heroicon-ui"
|
||||
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm4-8a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div v-for="[grp_key, grp_value] in props.groups" :key="grp_key" class="mt-3" :class="{ 'hidden' : props.hide }">
|
||||
<div
|
||||
v-for="[subgrp_key,subgrp_value] in grp_value"
|
||||
:key="subgrp_key"
|
||||
>
|
||||
<div
|
||||
v-for="(srvr,srvrindex) in subgrp_value"
|
||||
:key="srvrindex"
|
||||
class="flex flex-wrap -mx-2 pb-8"
|
||||
>
|
||||
<CloudServices
|
||||
:source="props.target === 'tsksrvcs' ? srvr.tsksrvcs : srvr.appsrvcs"
|
||||
:target="props.target"
|
||||
:filter="props.search"
|
||||
:hostname="srvr.hostname"
|
||||
@on-cloud-server-item="onCloudServiceItem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { CloudGroupServcType,SrvcInfoType } from '~/typs/clouds'
|
||||
const props = defineProps<{
|
||||
groups: Map<string, Map<string, CloudGroupServcType>>
|
||||
search: string
|
||||
target: string
|
||||
title: string
|
||||
hide: boolean
|
||||
}>()
|
||||
const emit = defineEmits(['onCloudGroup'])
|
||||
const on_group_item = (target: string, event: Event) => {
|
||||
event.preventDefault()
|
||||
event.stopImmediatePropagation()
|
||||
event.stopPropagation()
|
||||
emit('onCloudGroup', target)
|
||||
}
|
||||
const onCloudServiceItem = (item: SrvcInfoType) => {
|
||||
if (item) {
|
||||
// console.log(item)
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,134 +0,0 @@
|
||||
<template>
|
||||
<div class="shape-wrapper flex flex-wrap xyz-in" xyz="fade flip-up flip-left" v-if="props.source && props.source.length > 0">
|
||||
<div
|
||||
v-for="(item ,srvcindex) in props.source"
|
||||
:key="`grp_${srvcindex}`"
|
||||
class="shape w-1/2 md:w-1/4 lg:w-1/6 xl:w-1/7 font-light dark:bg-gray-200 bg-gray-300"
|
||||
:class="{hidden: !filter_item(item)}"
|
||||
@click="on_item(item,$event)"
|
||||
>
|
||||
<div
|
||||
class="flex bg-white dark:bg-gray-300 rounded-lg shadow-md m-2 border-l-4 border-gray-500 dark:border-gray-500 hover:shadow-2xl hover:border-pink-500 cursor-pointer relative"
|
||||
>
|
||||
<div class=" p-4 pr-6 leading-normal">
|
||||
<div class="font-medium text-xl truncate">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div
|
||||
class="truncate text-xs text-gray-500 font-semibold pt-1 pb-2 tracking-widest"
|
||||
v-html="map_srvc_target(item.srvc.target)"
|
||||
>
|
||||
</div>
|
||||
<div class="flex font-medium">
|
||||
<div v-if="authData.auth !== ''" class="flex-grow text-gray-400">
|
||||
{{ item.srvc.req || 'tcp' }}
|
||||
</div>
|
||||
<div
|
||||
class="flex-grow-0"
|
||||
:class="{ 'text-indigo-500' : item.info === 'ok' , 'text-red-600' : item.info !== 'ok' && item.srvc.critical === CriticalType.yes, 'text-green-500': item.info !== 'ok' && item.srvc.critical !== CriticalType.yes}"
|
||||
>
|
||||
<span v-if="item.info === 'ok'" class="text-2xl">
|
||||
<carbon-checkmark class="align-bottom" />
|
||||
</span>
|
||||
<span v-else class="ml-3">
|
||||
<span v-if="authData.auth === '' && (item.srvc.critical === CriticalType.ifresized || item.srvc.critical === CriticalType.cloud) ">
|
||||
{{ item.info }} <span class="ml-3">{{ t('srvc.pending','pending')}}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ item.info }} <span v-if="item.srvc.critical !== CriticalType.yes" class="ml-3">{{ item.srvc.critical }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="authData.auth !== ''" class="flex mt-2 font-medium">
|
||||
<div v-if="item.srvc.path" class="flex-grow-0 text-1xl text-blue-600 hover:text-blue-700 mr-2 block" :data="item.srvc.path">
|
||||
<carbon-script class="inline-block" />
|
||||
</div>
|
||||
<div v-if="item.srvc.liveness" class="flex-grow text-xs text-blue-600 hover:text-blue-700 block" :data="item.srvc.liveness">
|
||||
{{ item.srvc.liveness }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
SrvcInfoType,
|
||||
CriticalType,
|
||||
} from '~/typs/clouds'
|
||||
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
const { t } = useI18n()
|
||||
|
||||
let shapWrapper = document.querySelector(".shape-wrapper");
|
||||
const props = defineProps<{
|
||||
source: SrvcInfoType[]
|
||||
hostname: string
|
||||
target: string
|
||||
filter: string
|
||||
}>()
|
||||
const emit = defineEmits(['onCloudServiceItem'])
|
||||
const on_item = (item: SrvcInfoType, event: Event) => {
|
||||
event.preventDefault()
|
||||
event.stopImmediatePropagation()
|
||||
event.stopPropagation()
|
||||
emit('onCloudServiceItem', item)
|
||||
}
|
||||
const authData = auth_data()
|
||||
// TODO review https://medium.com/@KevinBGreene/typescript-enums-and-polymorphism-with-type-matching-fc3dc74b031c
|
||||
const critical_matches = (val: CriticalType, match: string): boolean => {
|
||||
switch (match) {
|
||||
case 'yes':
|
||||
return val === CriticalType.yes
|
||||
case 'no':
|
||||
return val === CriticalType.no
|
||||
case 'cloud':
|
||||
return val === CriticalType.cloud
|
||||
case 'group':
|
||||
return val === CriticalType.group
|
||||
case 'ifresized':
|
||||
return val === CriticalType.ifresized
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
const map_srvc_target = (srvc_target: string): string => {
|
||||
return srvc_target ? srvc_target.replace('::','<br>') : (authData.auth !== '' && props.hostname || '')
|
||||
}
|
||||
const filter_item = (item: SrvcInfoType): boolean => {
|
||||
if (authData.auth !== '')
|
||||
return props.filter === '' || item.name.includes(props.filter) || item.srvc.target.includes(props.filter)
|
||||
|| item.srvc.liveness.includes(props.filter) || item.info.includes(props.filter)
|
||||
|| props.hostname.includes(props.filter) || critical_matches(item.srvc.critical,props.filter)
|
||||
else
|
||||
return props.filter === '' || item.name.includes(props.filter) || item.srvc.target.includes(props.filter)
|
||||
|| item.info.includes(props.filter)
|
||||
}
|
||||
onMounted(() => {
|
||||
shapWrapper = document.querySelector(".shape-wrapper");
|
||||
function animate(selector: Element|null) {
|
||||
if (selector && selector.classList.contains("xyz-in")) {
|
||||
selector.classList.remove("xyz-in");
|
||||
selector.classList.add("xyz-out");
|
||||
} else if (selector) {
|
||||
selector.classList.remove("xyz-out");
|
||||
selector.classList.add("xyz-in");
|
||||
}
|
||||
}
|
||||
|
||||
animate(shapWrapper);
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.shape-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
.shape {
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 1rem;
|
||||
border-radius: 20px;
|
||||
}
|
||||
</style>
|
@ -1,146 +0,0 @@
|
||||
<template>
|
||||
<nav class="text-xl mt-6 dark:bg-cool-gray-800 dark:text-white">
|
||||
<span
|
||||
v-for="(itm,index) in footerMenuCentral"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
class="icon-btn mx-2"
|
||||
>
|
||||
<router-link v-if="itm.type === NavItemType.router_link && itemIf(itm)" :to="itm.to">
|
||||
<span v-if="itm.to === '/'"> <carbon-campsite /> </span>
|
||||
<span v-if="itm.to === '/login'"> <carbon-login /> </span>
|
||||
<span v-if="itm.to === '/about'"> <carbon-dicom-overlay /> </span>
|
||||
</router-link>
|
||||
<a v-if="itm.type == NavItemType.app_link" :title="t(itm.title)" @click="itemClick(itm || '')">
|
||||
<span v-if="itm.vif && itm.vif === 'isDark'" class="icon">
|
||||
<svg
|
||||
v-if="isDark"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fal"
|
||||
data-icon="cloud-sun"
|
||||
class="svg-inline--fa fa-cloud-sun fa-w-20 dark:text-white text-blue-400 w-7"
|
||||
style="margin-top: -0.8em"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 640 512"
|
||||
><path fill="currentColor" d="M543.7 304.3C539.8 259.4 502 224 456 224c-17.8 0-34.8 5.3-49.2 15.2-22.5-29.5-57.3-47.2-94.8-47.2-66.2 0-120 53.8-120 120v.4c-38.3 16-64 53.5-64 95.6 0 57.3 46.7 104 104 104h304c57.3 0 104-46.7 104-104 0-54.8-42.6-99.8-96.3-103.7zM536 480H232c-39.7 0-72-32.3-72-72 0-32.3 21.9-60.7 53.3-69.2l13.3-3.6-2-17.2c-.3-2-.6-4-.6-6 0-48.5 39.5-88 88-88 32.2 0 61.8 17.9 77.2 46.8l10.6 19.8 15.2-16.5c10.8-11.7 25.4-18.1 41-18.1 30.9 0 56 25.1 56 56 0 1.6-.3 3.1-.8 6.9l-2.5 20 23.5-2.4c1.2-.2 2.5-.4 3.8-.4 39.7 0 72 32.3 72 72S575.7 480 536 480zM92.6 323l12.5-63.2c1.2-6.3-1.4-12.8-6.8-16.4l-53.5-35.8 53.5-35.8c5.4-3.6 8-10.1 6.8-16.4L92.6 92.1l63.2 12.5c6.4 1.3 12.8-1.5 16.4-6.8L208 44.3l35.8 53.5c3.6 5.3 9.9 8.1 16.4 6.8l63.2-12.5-12.5 63.2c-.3 1.6-.1 3.2 0 4.8.4 0 .7-.1 1.1-.1 10.1 0 20 1.1 29.6 3 .2-.5.5-.9.6-1.5l17.2-86.7c1-5.2-.6-10.6-4.4-14.4s-9.2-5.5-14.4-4.4l-76.2 15.1-43.1-64.4c-6-8.9-20.6-8.9-26.6 0l-43.2 64.5-76.1-15.1c-5.3-1.1-10.7.6-14.4 4.4-3.8 3.8-5.4 9.2-4.4 14.4l15.1 76.2-64.6 43.1c-4.4 3-7.1 8-7.1 13.3s2.7 10.3 7.1 13.3L71.6 264l-15.1 76.2c-1 5.2.6 10.6 4.4 14.4 3 3 7.1 4.7 11.3 4.7 1 0 2.1-.1 3.1-.3l32.8-6.5c6.2-13.8 14.6-26.5 25.1-37.6L92.6 323zM208 149.7c18.5 0 34.8 8.9 45.4 22.4 10.2-4.3 20.8-7.6 31.9-9.6-15.6-26.6-44.2-44.8-77.3-44.8-49.5 0-89.8 40.3-89.8 89.8 0 33 18.1 61.7 44.8 77.3 2-11.1 5.3-21.7 9.6-31.9-13.6-10.6-22.4-26.9-22.4-45.4 0-31.8 25.9-57.8 57.8-57.8z"></path></svg>
|
||||
<svg
|
||||
v-else
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
data-prefix="fal"
|
||||
data-icon="cloud-moon"
|
||||
class="svg-inline--fa fa-cloud-moon fa-w-20 dark:text-white text-blue-400 w-7"
|
||||
style="margin-top: -0.8em"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 640 512"
|
||||
><path fill="currentColor" d="M351.5 313.6c-4.5-41.3-39.6-73.6-82.1-73.6-13.9 0-27.3 3.5-39.5 10.3-18.3-16.8-41.9-26.3-66.8-26.3-53.7 0-97.5 42.8-99.2 96.2-38.3 14.3-64 50.7-64 92.7C0 467.5 44.5 512 99.2 512h249.6c54.7 0 99.2-44.5 99.2-99.2 0-53.8-43-97.7-96.5-99.2zM348.8 480H99.2C62.1 480 32 449.9 32 412.8c0-31.6 21.5-58.5 52.4-65.4l14-5.9-2-14.6c-.2-1.2-.4-2.5-.4-3.8 0-37.1 30.1-67.2 67.2-67.2 20.1 0 39 9.2 52 25.2l10.1 12.5 12.4-10.1C247 276 258 272 269.4 272c27.9 0 50.6 22.7 50.6 50.6 0 1.5-.2 2.8-.7 6.4l-2.6 21.3 21.2-3.6c3.6-.6 7.2-1.2 11-1.2 37.1 0 67.2 30.2 67.2 67.2S385.9 480 348.8 480zm288.8-192.8c-4.1-8.6-12.4-13.9-21.8-13.9-1.5 0-3 .1-4.6.4-7.7 1.5-15.5 2.2-23.2 2.2-67 0-121.5-54.7-121.5-121.9 0-43.7 23.6-84.3 61.6-106 8.9-5.1 13.6-15 11.9-25.1-1.7-10.2-9.4-17.9-19.5-19.8-11.5-2-23.2-3.1-35-3.1-105.7 0-191.8 86.1-191.8 192 0 6.5.4 12.8 1.1 19.2 12.7 2.9 24.6 7.8 35.4 14.6-2.6-10.9-4.5-22-4.5-33.7 0-88.2 71.7-160 159.8-160 3 0 5.9.1 8.9.2-37.4 28.9-59.9 73.9-59.9 121.9C434.5 239 503.4 308 588 308c2.6 0 5.2-.1 7.8-.2C566.2 336.1 527 352 485.5 352c-7.5 0-14.8-.7-21.9-1.9 5.7 10.3 9.7 21.5 12.5 33.1 3.1.2 6.2.7 9.4.7 58.1 0 112.4-25.9 149-71.1 6-7.2 7.2-17.1 3.1-25.6z"></path></svg>
|
||||
</span>
|
||||
<IconLink v-else :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="false" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
|
||||
</a>
|
||||
<a
|
||||
v-if="itm.type == NavItemType.a_blank"
|
||||
rel="noreferrer"
|
||||
:href="itm.href || '#'"
|
||||
target="_blank"
|
||||
:title="t(itm.title)"
|
||||
>
|
||||
<span v-if="itm.icon_on === 'carbon-logo-github'">
|
||||
<carbon-logo-github />
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</nav>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { isDark, toggleDark } from '~/logics'
|
||||
import { NavItemType } from '~/typs'
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import useState from '~/hooks/useState'
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
|
||||
// https://vitejs.dev/guide/features.html#static-assets
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const { t, availableLocales, locale } = useI18n()
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const footerMenuCentral = computed(() => {
|
||||
return defs.value && defs.value.footer && defs.value.footer.central_items ? defs.value.footer.central_items : []
|
||||
})
|
||||
const toggleLocales = () => {
|
||||
// change to some real logic
|
||||
const locales = availableLocales
|
||||
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length]
|
||||
}
|
||||
const itemIf = (itm: SideMenuItemType) => {
|
||||
switch (itm.vif) {
|
||||
case 'notValidUser':
|
||||
return auth_data().auth === '' ? true : false
|
||||
;;
|
||||
case 'validUser':
|
||||
return auth_data().auth !== '' ? true : false
|
||||
;;
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
const itemClick = (itm: SideMenuItemType) => {
|
||||
switch (itm.click) {
|
||||
case 'toggleDark':
|
||||
toggleDark()
|
||||
break
|
||||
case 'toggleLocales':
|
||||
toggleLocales()
|
||||
break
|
||||
case 'tophome':
|
||||
if (useState().app_home_click.value) {
|
||||
useState().app_home_click.value()
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
break
|
||||
default:
|
||||
if (useState().side_menu_click.value) {
|
||||
try {
|
||||
useState().side_menu_click.value(itm)
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
<router-link class="icon-btn mx-2" to="/" :title="t('button.home')">
|
||||
<carbon-campsite />
|
||||
</router-link>
|
||||
|
||||
<a class="icon-btn mx-2" :title="t('button.toggle_dark')" @click="toggleDark">
|
||||
<carbon-moon v-if="isDark" />
|
||||
<carbon-sun v-else />
|
||||
</a>
|
||||
|
||||
<a class="icon-btn mx-2" :title="t('button.toggle_langs')" @click="toggleLocales">
|
||||
<carbon-language />
|
||||
</a>
|
||||
|
||||
<router-link class="icon-btn mx-2" to="/about" :title="t('button.about')">
|
||||
<carbon-dicom-overlay />
|
||||
</router-link>
|
||||
|
||||
<a class="icon-btn mx-2" rel="noreferrer" href="https://github.com/antfu/vitesse" target="_blank" title="GitHub">
|
||||
<carbon-logo-github />
|
||||
</a>
|
||||
<router-link class="icon-btn mx-2" to="/login" :title="t('button.login')">
|
||||
<carbon-login />
|
||||
</router-link>
|
||||
*/
|
||||
</script>
|
@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<span class="flex" :class="{'justify-start': open}">
|
||||
<span v-if="pfx" class="-ml-5 mr-2 text-xs" :class="{ 'lg:hidden': open }">
|
||||
<small class="text-gray-400">{{ pfx }}</small>
|
||||
</span>
|
||||
<span v-if="icon === 'carbon-home'" class="mt-1"> <carbon-home /> </span>
|
||||
<span v-if="icon === 'carbon-campsite'" class="mt-1"> <carbon-campsite /> </span>
|
||||
<span v-if="icon === 'carbon-login'" class="mt-1"> <carbon-login /> </span>
|
||||
<span v-if="icon === 'carbon-dicom-overlay'" class="mt-1"> <carbon-dicom-overlay /> </span>
|
||||
<span v-if="icon === 'carbon-table'" class="mt-1"> <carbon-table class="dark:text-white" /> </span>
|
||||
<span v-if="icon === 'carbon-image'" class="mt-1"> <carbon-image /> </span>
|
||||
<span v-if="icon === 'carbon-storage-pool'" class="mt-1"> <carbon-storage-pool /> </span>
|
||||
<span v-if="icon === 'carbon-application'"> <carbon-application /> </span>
|
||||
<span v-if="icon === 'carbon-services'" class="mt-1"> <carbon-cloud-services /> </span>
|
||||
<span v-if="icon === 'carbon-event'"> <carbon-event /> </span>
|
||||
<span v-if="icon === 'carbon-operation'"> <carbon-operation /> </span>
|
||||
<span v-if="icon === 'carbon-api'"> <carbon-api /> </span>
|
||||
<span v-if="icon === 'carbon-cloud'" class="flex justify-center items-center"> <carbon-cloud /> </span>
|
||||
<span v-if="icon === 'carbon-flow'"> <carbon-flow /> </span>
|
||||
<span v-if="icon === 'carbon-nominal'"> <carbon-nominal /> </span>
|
||||
<span v-if="icon === 'carbon-language'"> <carbon-language /> </span>
|
||||
<span v-if="show_to && name && name !== 'items'" class="mt-1 ml-2 text-xs" :class="{ 'hidden': open }"> {{ t(`${name}`,name||'') || '' }}</span>
|
||||
<span v-if="mode !== 'icon'" class="ml-2" :class="{ 'lg:hidden': !open }"> {{ t(`${title}`,title||'') }}</span>
|
||||
<span v-if="show_to" :class="{ 'lg:hidden': !open }" class="ml-2 text-xs flex justify-center items-center "> {{ t(`${name}`,name || '') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { NavItemType } from '~/typs'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
typ: NavItemType
|
||||
icon: string | undefined
|
||||
pfx: string | undefined
|
||||
name: string | undefined
|
||||
show_to: boolean | false
|
||||
title: string | undefined
|
||||
mode: sring | undefined
|
||||
open: boolean | false
|
||||
}>()
|
||||
|
||||
</script>
|
@ -1,110 +0,0 @@
|
||||
|
||||
<template>
|
||||
<nav
|
||||
class="flex items-center justify-between flex-wrap p-1 fixed w-full z-10 top-0 left-0"
|
||||
:class="{ 'shadow-lg bg-indigo-900' : isOpen , 'bg-blue-900' : !isOpen}"
|
||||
@keydown.escape="isOpen = false"
|
||||
>
|
||||
<!--Logo etc-->
|
||||
<div class="flex items-center flex-shrink-0 text-white ml-2 mr-6">
|
||||
<a
|
||||
aria-current="page"
|
||||
href="/"
|
||||
class="router-link-active router-link-exact-active flex items-center text-white no-underline hover:text-white hover:no-underline"
|
||||
title="LibreCloud"
|
||||
>
|
||||
<span class="w-11 h-11 rounded-full mr-2">
|
||||
<img class="max-w-7xl w-32 h-rounded" src="/assets/images/logo.svg" alt="App">
|
||||
</span>
|
||||
<span class="hidden text-sm md:block mr-2">{{props.navtitle}}</span>
|
||||
<span
|
||||
v-if="usetitle"
|
||||
class="text-xl pl-2"
|
||||
><i class="em em-grinning"></i> {{ t(`nav.${props.title}`,props.title) }} </span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--Toggle button (hidden on large screens)-->
|
||||
<button
|
||||
type="button"
|
||||
class="block lg:hidden px-2 text-gray-300 hover:text-white focus:outline-none focus:text-white"
|
||||
:class="{ 'transition transform-180': isOpen }"
|
||||
@click.prevent="isOpen = !isOpen"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
v-show="isOpen"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z"
|
||||
/>
|
||||
<path
|
||||
v-show="!isOpen"
|
||||
fill-rule="evenodd"
|
||||
d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!--Menu-->
|
||||
<div
|
||||
class="w-full flex-grow lg:flex lg:items-center lg:w-auto"
|
||||
:class="{ 'block shadow-3xl': isOpen, 'hidden': !isOpen }"
|
||||
>
|
||||
<ul
|
||||
class="pt-4 lg:pt-0 list-reset lg:flex justify-end flex-1 items-center"
|
||||
>
|
||||
<li v-for="item in items" :key="item.name_to" class="mr-3">
|
||||
<a
|
||||
class="inline-block py-2 px-4 text-white no-underline"
|
||||
:class="item.active ? '' : 'text-gray-400 no-underline hover:text-gray-200 hover:text-underline'"
|
||||
:href="item.href"
|
||||
@click.prevent="on_item(item)"
|
||||
> {{ t(`nav.${item.title}`,item.title) }}
|
||||
</a>
|
||||
</li>
|
||||
<slot name="opslist" />
|
||||
<li class="p-1">
|
||||
<div class="bg-white flex items-center rounded-full shadow-xl">
|
||||
<slot name="search" />
|
||||
</div>
|
||||
</li>
|
||||
<slot name="lastitems" />
|
||||
<li class="p-1" v-if="authData.auth !== ''">
|
||||
<router-link class="icon-btn text-2xl text-white no-underline" to="/logout" :title="t('button.logout')">
|
||||
<carbon-logout />
|
||||
</router-link>
|
||||
</li>
|
||||
<li class="p-1" v-else>
|
||||
<router-link class="icon-btn text-2xl text-white no-underline" to="/login" :title="t('button.login')">
|
||||
<carbon-login />
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
navtitle: string
|
||||
usetitle: boolean
|
||||
title: string
|
||||
items: Array<SideMenuItemType>
|
||||
}>()
|
||||
const authData = auth_data()
|
||||
|
||||
const emit = defineEmits(['onNavMenu'])
|
||||
const isOpen = ref(false)
|
||||
const on_item = (item: SideMenuItemType) => {
|
||||
emit('onNavMenu', item)
|
||||
}
|
||||
</script>
|
@ -1,137 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import useState from '~/hooks/useState'
|
||||
const { t } = useI18n()
|
||||
|
||||
const profile = ref({
|
||||
username: 'jesusperez',
|
||||
fullname: 'Jesús Pérez Lorenzo',
|
||||
bgcolors: ['bg-emerald-500', 'bg-purple-500', 'bg-yellow-500', 'bg-gray-800', 'bg-pink-500'],
|
||||
bgcolor: 'bg-dark-800',
|
||||
photourl: 'https://avatars.githubusercontent.com/u/59666?v=4',
|
||||
})
|
||||
const profile_showsettings= ref(false)
|
||||
const profile_editing= ref('')
|
||||
const profile_saveedit = (name: string) => {
|
||||
profile_editing.value = ''
|
||||
}
|
||||
const profile_edit = (name: string) => {
|
||||
profile_editing.value = name
|
||||
// this.$nextTick(() => {
|
||||
// this.$refs[`${name}input`].focus()
|
||||
// })
|
||||
}
|
||||
const profile_discard = (name: string) => {
|
||||
// this.$refs[`${name}input`].value = this[name]
|
||||
profile_editing.value = ''
|
||||
}
|
||||
const profile_selectcolor = (color: string) => {
|
||||
profile.value.bgcolor = color
|
||||
}
|
||||
const onSettings = () => {
|
||||
profile_showsettings.value= true
|
||||
}
|
||||
const onCloseSettings = () => {
|
||||
profile_showsettings.value=false
|
||||
}
|
||||
const onLogout = () => {
|
||||
useState().show_profile.value = false
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="block flex flex-col w-full h-screen justify-center items-center bg-white">
|
||||
<div class="flex flex-col w-75 shadow-md max-w-full h-70 rounded-lg transition-colors ease-in" :class="profile.bgcolor">
|
||||
<div v-show="profile_showsettings" class="fixed z-10 flex flex-col w-75 max-w-full h-70 text-center text-white p-5 origin-top-left transform scale-0 transition-all" :class="{'scale-100': profile_showsettings}">
|
||||
<span class="text-2xl font-bold">{{ t('profile.Settings','Settings') }}</span>
|
||||
<div class="flex flex-col space-y-2 mt-5 flex-grow">
|
||||
<span class="text-md font-bold">{{ t('profile.backgroud_color','Background color') }}:</span>
|
||||
<div class="w-full flex justify-center space-x-2">
|
||||
<span v-for="c in profile.bgcolors" :key="c">
|
||||
<button class="flex border-4 border-white inline cursor-pointer w-8 h-8 rounded-full" :class="c" :disabled="profile.bgcolor == c" @click="profile_selectcolor(c)"></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center flex-shrink align-end">
|
||||
<button class="rounded bg-transparent font-bold text-lg fill-current text-white" @click="onCloseSettings">
|
||||
{{ t(`profile.Close`,'Close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!profile_showsettings">
|
||||
<div class="flex w-full justify-between p-2 mt-1">
|
||||
<button @click="onSettings" class="flex space-x-1 group font-semibold items-center bg-transparent cursor-pointer text-white fill-current">
|
||||
<svg class="w-7 h-7" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
<span class="origin-left transform scale-x-0 group-focus:scale-x-100 group-hover:scale-x-100 transition-transform ease-in select-none text-lg">{{ t('profile.Settings','Settings') }}</span>
|
||||
</button>
|
||||
<button @click="onLogout" class="flex space-x-1 group font-semibold items-center bg-transparent cursor-pointer text-white fill-current">
|
||||
<span class="origin-right transform scale-x-0 group-focus:scale-x-100 group-hover:scale-x-100 transition-transform ease-in select-none text-lg">{{ t('profile.Logout','Logout') }}</span>
|
||||
<svg class="w-7 h-7" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col w-full h-full text-center">
|
||||
<div class="flex flex-col space-y-2 items-center mb-3">
|
||||
<img :src="profile.photourl" alt="Profile Picture" class="rounded-full select-none w-22">
|
||||
<div class="text-center relative group">
|
||||
<span v-show="profile_editing !== 'fullname'" class="text-xl break-words font-semibold text-white font-sans m-0 p-0 px-2 select-none" title="Double click to edit" @dblclick="profile_edit('fullname')">{{ profile.fullname }}</span>
|
||||
<svg v-show="profile_editing != 'fullname'" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-50 inline absolute right-2 -top-3 transform scale-0 group-hover:scale-100 transition-transform" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
|
||||
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
<input
|
||||
v-show="profile_editing == 'fullname'"
|
||||
id=""
|
||||
type="text"
|
||||
name=""
|
||||
class="bg-transparent text-xl font-sans w-full p-0 px-2 m-0 text-center text-white font-semibold focus:outline-none focus:animate-pulse"
|
||||
:value="profile.fullname"
|
||||
spellcheck="false"
|
||||
x-ref="fullnameinput"
|
||||
title="Enter to save, click outside to discard."
|
||||
maxlength="20"
|
||||
@keydown.enter="profile_saveedit('fullname')"
|
||||
@click="profile_discard('fullname')"
|
||||
@keydown.escape="profile_discard('fullname')"
|
||||
>
|
||||
</div>
|
||||
<div class="text-center relative group">
|
||||
<span v-show="profile_editing != 'username'" class="text-sm text-wrap font-semibold font-sans m-0 p-0 text-green-100 select-none" title="Double click to edit" @dblclick="profile_edit('username')">{{ profile.username }}</span>
|
||||
<svg v-show="profile_editing != 'username'" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-50 inline absolute ml-1 -top-1 transform scale-0 group-hover:scale-100 transition-transform" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
|
||||
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
<input
|
||||
v-show="profile_editing == 'username'"
|
||||
id=""
|
||||
type="text"
|
||||
name=""
|
||||
class="inline-block bg-transparent text-sm font-sans p-0 m-0 w-auto text-center font-semibold text-green-100 focus:outline-none focus:animate-pulse"
|
||||
:value="profile.username"
|
||||
spellcheck="false"
|
||||
x-ref="usernameinput"
|
||||
title="Enter to save, click outside to discard."
|
||||
maxlength="15"
|
||||
@keydown.enter="profile_saveedit('username')"
|
||||
@click="profile_discard('username')"
|
||||
@keydown.escape="profile_discard('username')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden flex flex-row justify-evenly">
|
||||
<div class="flex flex-col cursor-pointer hover:opacity-80">
|
||||
<span class="text-lg font-bold text-white">11</span>
|
||||
<span class="text-green-100 text-sm">Followers</span>
|
||||
</div>
|
||||
<div class="flex flex-col cursor-pointer hover:opacity-80">
|
||||
<span class="text-lg font-bold text-white">52</span>
|
||||
<span class="text-green-100 text-sm">Following</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,9 +0,0 @@
|
||||
## Components
|
||||
|
||||
Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components).
|
||||
|
||||
### Icons
|
||||
|
||||
You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/).
|
||||
|
||||
It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details.
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<button class="icon-btn mx-2" @click="toggleShowLocales">
|
||||
<carbon-language class="inline-block text-gray-900 dark:text-white" />
|
||||
</button>
|
||||
<div v-if="showLocalesSelector" :class="`select !normal max-w-xs ${selWidth} float-right`">
|
||||
<select v-model="currentLocale" class="dark:text-white">
|
||||
<option
|
||||
v-for="itm in listLocales"
|
||||
:key="itm"
|
||||
:selected="itm === currentLocale"
|
||||
:value="itm"
|
||||
>
|
||||
{{ localeLabel(itm) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// import {
|
||||
// PropType,
|
||||
// } from 'vue'
|
||||
</script>
|
||||
<script setup lang="ts">
|
||||
// <vue:window on:keydown={cleanOverlay} />
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
enum LocalesLabelModes {
|
||||
value = 'val',
|
||||
translation = 'trans',
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
labelMode: {
|
||||
type: Object as PropType<LocalesLabelModes>,
|
||||
//default: LocalesLabelModes.translation,
|
||||
required: false,
|
||||
},
|
||||
includeCurrent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
const i18n = useI18n()
|
||||
|
||||
const showLocalesSelector = ref(false)
|
||||
|
||||
const currentLocale = computed({
|
||||
get: (): string => i18n.locale.value,
|
||||
set: (val: string) => {
|
||||
if (i18n.availableLocales.includes(val)) {
|
||||
// console.log(`change to ${val} from ${i18n.locale.value}`)
|
||||
i18n.locale.value = val
|
||||
showLocalesSelector.value = false
|
||||
}
|
||||
},
|
||||
})
|
||||
const locales = computed(() => i18n.availableLocales)
|
||||
const listLocales = computed(() =>
|
||||
props.includeCurrent ? locales.value : locales.value.filter(lcl => lcl !== currentLocale.value))
|
||||
const toggleShowLocales = () => {
|
||||
showLocalesSelector.value = !showLocalesSelector.value
|
||||
// change to some real logic
|
||||
// i18n.locale.value = i18n.availableLocales[(i18n.availableLocales.indexOf(i18n.locale.value) + 1) % i18n.availableLocales.length]
|
||||
}
|
||||
const localeLabel = (value: string): string => {
|
||||
let label = ''
|
||||
switch (props.labelMode) {
|
||||
case LocalesLabelModes.translation:
|
||||
label = i18n.t(value, value)
|
||||
break
|
||||
case LocalesLabelModes.value:
|
||||
label = value
|
||||
break
|
||||
}
|
||||
return label
|
||||
}
|
||||
const selWidth = computed(() => {
|
||||
let width = ''
|
||||
switch (props.labelMode) {
|
||||
case LocalesLabelModes.translation:
|
||||
width = 'w-28'
|
||||
break
|
||||
case LocalesLabelModes.value:
|
||||
width = 'w-24'
|
||||
break
|
||||
}
|
||||
return width
|
||||
})
|
||||
onMounted(() => {
|
||||
})
|
||||
</script>
|
@ -1,251 +0,0 @@
|
||||
<template>
|
||||
<nav class="flex items-center justify-between pt-1 dark:bg-cool-gray-800 dark:text-white">
|
||||
<!-- Navbar left -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase lg:hidden" @click="on_logo_app">
|
||||
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/app_w.svg" alt="App">
|
||||
</span>
|
||||
<!-- Toggle sidebar button -->
|
||||
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="toggleSidebar">
|
||||
<span class="sr-only">Toggle sidebar</span>
|
||||
<ChevronDoubleRight
|
||||
aria-hidden="true"
|
||||
class="w-4 h-4 text-gray-600 dark:text-white"
|
||||
:class="{ 'transform transition-transform -rotate-180': isSidebarOpen }"
|
||||
/>
|
||||
</button>
|
||||
<Breadcrump :bc-path="bcPath" @on-book-selec="bookSelec" />
|
||||
<span class="lg:ml-3 flex">
|
||||
<span
|
||||
class="hidden lg:flex flex-grow"
|
||||
:class="`${navTitle && navTitle.cmpnt === 'boxmenu' ? 'mt-2': ''} ${navTitle.textclick ? 'cursor-pointer': ''}`"
|
||||
@click="onNavTitleClick"
|
||||
>{{ navTitle && navTitle.text || '' }}
|
||||
</span>
|
||||
<BoxMenu
|
||||
v-if="navTitle && navTitle.text !== '' && navTitle.cmpnt === 'boxmenu'"
|
||||
class="-ml-4 lg:ml-0 flex-grow-0"
|
||||
:menu-options="navTitle.ops"
|
||||
:title="navTitle.title"
|
||||
:btn-type="navTitle.btntype"
|
||||
@on-menu-option="onNavTitleMenuOption"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Navbar right -->
|
||||
<nav aria-label="Secondary" class="flex items-center space-x-3">
|
||||
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase" @click="on_logo_app">
|
||||
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
|
||||
</span>
|
||||
<NavbarIconButton
|
||||
v-show="authData.auth === ''"
|
||||
label="Login"
|
||||
@click="router.push('/login')"
|
||||
>
|
||||
<carbon-login /> {{ t('button.login','Login') }}
|
||||
</NavbarIconButton>
|
||||
<NavbarIconButton
|
||||
v-show="useSettings"
|
||||
label="Open setting panel"
|
||||
@click="isSettingsPanelOpen = !isSettingsPanelOpen"
|
||||
>
|
||||
<carbon-settings />
|
||||
</NavbarIconButton>
|
||||
<!-- Search button -->
|
||||
<NavbarIconButton v-if="navbar_right.search" label="Open search panel" @click="isSearchPanelOpen = true">
|
||||
<!-- SearchIcon aria-hidden="true" class="w-6 h-6" -->
|
||||
<carbon-search />
|
||||
</NavbarIconButton>
|
||||
|
||||
<!-- Notification Button -->
|
||||
<NavbarIconButton v-if="navbar_right.notify" label="Open notifications panel" @click="isNotificationsPanelOpen = true">
|
||||
<!--BellIcon aria-hidden="true" class="w-6 h-6" /-->
|
||||
<carbon-notification />
|
||||
</NavbarIconButton>
|
||||
<!-- User menu -->
|
||||
<Menu v-slot="{ open }" as="div" class="relative pr-2">
|
||||
<MenuButton
|
||||
id="user-menu"
|
||||
aria-haspopup="true"
|
||||
:aria-expanded="open ? 'true' : 'false'"
|
||||
class="relative flex items-center overflow-hidden rounded-full group focus:outline-none focus:ring"
|
||||
v-if="authData.auth !== ''"
|
||||
>
|
||||
<span class="sr-only">{{ `${navbar_right.title || 'Open menu'}` }}</span>
|
||||
<img
|
||||
class="object-cover w-8 h-8 rounded-full group-hover:opacity-90"
|
||||
src="/assets/images/jesus.jpg"
|
||||
alt="User image"
|
||||
>
|
||||
<!-- <div class="absolute right-0 p-1 bg-green-400 rounded-full top-1 animate-ping"></div>
|
||||
<div class="absolute right-0 p-1 bg-green-400 border border-white rounded-full top-1"></div> -->
|
||||
</MenuButton>
|
||||
<transition
|
||||
enter-active-class="transition duration-100 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0"
|
||||
enter-to-class="transform scale-100 opacity-100"
|
||||
leave-active-class="transition duration-75 ease-out"
|
||||
leave-from-class="transform scale-100 opacity-100"
|
||||
leave-to-class="transform scale-95 opacity-0"
|
||||
>
|
||||
<MenuItems
|
||||
class="absolute right-0 z-999 w-48 py-1 mt-2 origin-top-righti dark:bg-gray-600 bg-white rounded-md shadow-lg focus:outline-none"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
aria-labelledby="user-menu"
|
||||
>
|
||||
<MenuItem
|
||||
v-for="(itm,index) in navbar_right.items"
|
||||
v-slot="{ active }"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
>
|
||||
<span class="block text-sm dark:text-gray-300 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-500">
|
||||
<a
|
||||
v-if="itm && itm.type === 'app_link'"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
class="px-4 py-2 flex items-center"
|
||||
role="menuitem"
|
||||
@click.prevent="onMenuItemClick(itm)"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="itm && itm.type === 'router_link'"
|
||||
:title="t(itm.title)"
|
||||
:to="{ name: itm.name_to }"
|
||||
class="px-4 py-2 flex items-center"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</router-link>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</nav>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
// https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.your-profile') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.settings') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.sign-out') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
*/
|
||||
import {
|
||||
computed,
|
||||
} from 'vue'
|
||||
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
|
||||
import ChevronDoubleRight from '@/icons/ChevronDoubleRight.vue'
|
||||
// import SearchIcon from '@/icons/SearchIcon.vue'
|
||||
// import BellIcon from '@/icons/BellIcon.vue'
|
||||
import Breadcrump from '@/Breadcrump.vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import NavbarIconButton from './NavbarIconButton.vue'
|
||||
import BoxMenu from '~/views/BoxMenu.vue'
|
||||
import useState from '~/hooks/useState'
|
||||
import useComponent from '~/hooks/useComponent'
|
||||
// import { NavItemType } from '~/typs'
|
||||
// import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
|
||||
const open_menu = ref(false)
|
||||
const { isSidebarOpen, isSearchPanelOpen, isSettingsPanelOpen, toggleSidebar, isNotificationsPanelOpen, bcPath, navTitle } = useState()
|
||||
const { t } = useI18n()
|
||||
|
||||
const authData = computed(() => auth_data())
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const user_image = computed(() => {
|
||||
const image = defs.value.profile && defs.value.profile.image ? defs.value.profile.image : ''
|
||||
if (image === '') {
|
||||
return '/assets/images/user.jpg'
|
||||
}
|
||||
if (image.charAt(0) === '/' || image.includes('http')) {
|
||||
return image
|
||||
} else {
|
||||
return `/assets/images/${image}`
|
||||
}
|
||||
})
|
||||
|
||||
const useSettings = computed(() => Object.entries(useComponent().settingsComponent.value).length !== 0)
|
||||
|
||||
const navbar_right = computed(() => {
|
||||
return defs.value && defs.value.header && defs.value.header.navbar && defs.value.header.navbar.menuright
|
||||
? defs.value.header.navbar.menuright
|
||||
: { title: '', notify: false, search: false, items: [] }
|
||||
})
|
||||
|
||||
const bookSelec = (target: string) => {
|
||||
switch (target) {
|
||||
case 'home':
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
router.push('/')
|
||||
break
|
||||
default:
|
||||
useState().bookSelec(target)
|
||||
}
|
||||
}
|
||||
const on_logo_app = () => {
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
useState().isSidebarOpen.value = false
|
||||
if (useState().app_home_click.value) {
|
||||
useState().app_home_click.value()
|
||||
}
|
||||
router.push('/')
|
||||
}
|
||||
const onMenuItemClick = (itm: SideMenuItemType ) => {
|
||||
const ustate: any = useState()
|
||||
const ky=`show_${itm.click}`
|
||||
if (ustate[ky])
|
||||
ustate[ky].value = !ustate[ky].value
|
||||
}
|
||||
const onNavTitleMenuOption = (data: any) => {
|
||||
if (navTitle.value.cllbck)
|
||||
navTitle.value.cllbck(data)
|
||||
}
|
||||
const onNavTitleClick = () => {
|
||||
if (navTitle.value.textclick)
|
||||
navTitle.value.textclick()
|
||||
}
|
||||
</script>
|
@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center p-2 text-gray-400 transition-colors bg-gray-100 rounded-full focus:outline-none focus:ring hover:bg-gray-200 hover:text-gray-500 dark:bg-cool-gray-600 dark:text-white"
|
||||
>
|
||||
<span class="sr-only">{{ label }}</span>
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
</script>
|
@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<nav class="flex items-center justify-between pt-1 dark:bg-cool-gray-800 dark:text-white">
|
||||
<!-- Navbar left -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase lg:hidden" @click="on_logo_app">
|
||||
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/app_w.svg" alt="App">
|
||||
</span>
|
||||
<!-- Toggle sidebar button -->
|
||||
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="toggleSidebar">
|
||||
<span class="sr-only">Toggle sidebar</span>
|
||||
<ChevronDoubleRight
|
||||
aria-hidden="true"
|
||||
class="w-4 h-4 text-gray-600 dark:text-white"
|
||||
:class="{ 'transform transition-transform -rotate-180': isSidebarOpen }"
|
||||
/>
|
||||
</button>
|
||||
<Breadcrump :bc-path="bcPath" @on-book-selec="bookSelec" />
|
||||
<span class="lg:ml-3 flex">
|
||||
<span
|
||||
class="hidden lg:flex flex-grow"
|
||||
:class="`${navTitle && navTitle.cmpnt === 'boxmenu' ? 'mt-2': ''} ${navTitle.textclick ? 'cursor-pointer': ''}`"
|
||||
@click="onNavTitleClick"
|
||||
>{{ navTitle && navTitle.text || '' }}
|
||||
</span>
|
||||
<BoxMenu
|
||||
v-if="navTitle && navTitle.text !== '' && navTitle.cmpnt === 'boxmenu'"
|
||||
class="-ml-4 lg:ml-0 flex-grow-0"
|
||||
:menu-options="navTitle.ops"
|
||||
:title="navTitle.title"
|
||||
:btn-type="navTitle.btntype"
|
||||
@on-menu-option="onNavTitleMenuOption"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Navbar right -->
|
||||
<nav aria-label="Secondary" class="flex items-center space-x-3">
|
||||
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase" @click="on_logo_app">
|
||||
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
|
||||
</span>
|
||||
<NavbarIconButton
|
||||
v-show="useSettings"
|
||||
label="Open setting panel"
|
||||
@click="isSettingsPanelOpen = !isSettingsPanelOpen"
|
||||
>
|
||||
<carbon-settings />
|
||||
</NavbarIconButton>
|
||||
<!-- Search button -->
|
||||
<NavbarIconButton v-if="navbar_right.search" label="Open search panel" @click="isSearchPanelOpen = true">
|
||||
<!-- SearchIcon aria-hidden="true" class="w-6 h-6" -->
|
||||
<carbon-search />
|
||||
</NavbarIconButton>
|
||||
|
||||
<!-- Notification Button -->
|
||||
<NavbarIconButton v-if="navbar_right.notify" label="Open notifications panel" @click="isNotificationsPanelOpen = true">
|
||||
<!--BellIcon aria-hidden="true" class="w-6 h-6" /-->
|
||||
<carbon-notification />
|
||||
</NavbarIconButton>
|
||||
<!-- User menu -->
|
||||
<Menu v-slot="{ open }" as="div" class="relative pr-2">
|
||||
<span> {{ navbar_right.items}} </span>
|
||||
<MenuButton
|
||||
id="user-menu"
|
||||
aria-haspopup="true"
|
||||
:aria-expanded="open ? 'true' : 'false'"
|
||||
class="relative flex items-center overflow-hidden rounded-full group focus:outline-none focus:ring"
|
||||
>
|
||||
<span class="sr-only">{{ `${navbar_right.title || 'Open menu'}` }}</span>
|
||||
<img
|
||||
class="object-cover w-8 h-8 rounded-full group-hover:opacity-90"
|
||||
src="/assets/images/jesus.jpg"
|
||||
alt="User image"
|
||||
>
|
||||
<!-- <div class="absolute right-0 p-1 bg-green-400 rounded-full top-1 animate-ping"></div>
|
||||
<div class="absolute right-0 p-1 bg-green-400 border border-white rounded-full top-1"></div> -->
|
||||
</MenuButton>
|
||||
<transition
|
||||
enter-active-class="transition duration-100 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0"
|
||||
enter-to-class="transform scale-100 opacity-100"
|
||||
leave-active-class="transition duration-75 ease-out"
|
||||
leave-from-class="transform scale-100 opacity-100"
|
||||
leave-to-class="transform scale-95 opacity-0"
|
||||
>
|
||||
<MenuItems
|
||||
class="absolute right-0 z-999 w-48 py-1 mt-2 origin-top-righti dark:bg-gray-600 bg-white rounded-md shadow-lg focus:outline-none"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
aria-labelledby="user-menu"
|
||||
>
|
||||
<MenuItem
|
||||
v-for="(itm,index) in navbar_right.items"
|
||||
v-slot="{ active }"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
>
|
||||
<span class="block text-sm dark:text-gray-300 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-500">
|
||||
<a
|
||||
v-if="itm && itm.type === 'app_link'"
|
||||
:href="itm.link"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
class="px-4 py-2"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="itm && itm.type === 'router_link'"
|
||||
:title="t(itm.title)"
|
||||
:to="{ name: itm.name_to }"
|
||||
class="px-4 py-2 flex items-center"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</router-link>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</nav>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
// https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.your-profile') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.settings') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
:class="{ 'bg-gray-100': active }"
|
||||
role="menuitem"
|
||||
>
|
||||
{{ t('menu.sign-out') }}
|
||||
</a>
|
||||
</MenuItem>
|
||||
*/
|
||||
import {
|
||||
computed,
|
||||
} from 'vue'
|
||||
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
|
||||
import ChevronDoubleRight from '@/icons/ChevronDoubleRight.vue'
|
||||
// import SearchIcon from '@/icons/SearchIcon.vue'
|
||||
// import BellIcon from '@/icons/BellIcon.vue'
|
||||
import Breadcrump from '@/Breadcrump.vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import NavbarIconButton from './NavbarIconButton.vue'
|
||||
import BoxMenu from '~/views/BoxMenu.vue'
|
||||
import useState from '~/hooks/useState'
|
||||
import useComponent from '~/hooks/useComponent'
|
||||
// import { NavItemType } from '~/typs'
|
||||
// import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
|
||||
const { isSidebarOpen, isSearchPanelOpen, isSettingsPanelOpen, toggleSidebar, isNotificationsPanelOpen, bcPath, navTitle } = useState()
|
||||
const { t } = useI18n()
|
||||
|
||||
const authData = computed(() => auth_data())
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const user_image = computed(() => {
|
||||
const image = defs.value.profile && defs.value.profile.image ? defs.value.profile.image : ''
|
||||
if (image === '') {
|
||||
return '/assets/images/user.jpg'
|
||||
}
|
||||
if (image.charAt(0) === '/' || image.includes('http')) {
|
||||
return image
|
||||
} else {
|
||||
return `/assets/images/${image}`
|
||||
}
|
||||
})
|
||||
|
||||
const useSettings = computed(() => Object.entries(useComponent().settingsComponent.value).length !== 0)
|
||||
|
||||
const navbar_right = computed(() => {
|
||||
return defs.value && defs.value.header && defs.value.header.navbar && defs.value.header.navbar.menuright
|
||||
? defs.value.header.navbar.menuright
|
||||
: { title: '', notify: false, search: false, items: [] }
|
||||
})
|
||||
|
||||
const bookSelec = (target: string) => {
|
||||
switch (target) {
|
||||
case 'home':
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
router.push('/')
|
||||
break
|
||||
default:
|
||||
useState().bookSelec(target)
|
||||
}
|
||||
}
|
||||
const on_logo_app = () => {
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
useState().isSidebarOpen.value = false
|
||||
if (useState().app_home_click.value) {
|
||||
useState().app_home_click.value()
|
||||
}
|
||||
router.push('/')
|
||||
}
|
||||
const onNavTitleMenuOption = (data: any) => {
|
||||
if (navTitle.value.cllbck)
|
||||
navTitle.value.cllbck(data)
|
||||
}
|
||||
const onNavTitleClick = () => {
|
||||
if (navTitle.value.textclick)
|
||||
navTitle.value.textclick()
|
||||
}
|
||||
</script>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<Panel :show="show" :title="title" id="aside" @close="close">
|
||||
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
|
||||
<keep-alive>
|
||||
<component :is="asideComponent" />
|
||||
</keep-alive>
|
||||
<slot />
|
||||
</div>
|
||||
</Panel>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Panel from './Panel.vue'
|
||||
import useComponent, { DynComponent } from '~/hooks/useComponent'
|
||||
|
||||
defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const cmpnt = useComponent()
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
emit('close')
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
const { t, locale } = useI18n()
|
||||
const asideComponent = computed(() => cmpnt.asideComponent.value)
|
||||
</script>
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<Panel :show="show" :title="t(title || 'notifications.notifications')" id="notifycation" @close="close">
|
||||
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
|
||||
<span>{{ t('notifications.content') }}</span>
|
||||
<!-- Notifications Panel Content ... -->
|
||||
</div>
|
||||
</Panel>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Panel from './Panel.vue'
|
||||
|
||||
defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
const { t, locale } = useI18n()
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
emit('close')
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<!-- Backdrop -->
|
||||
<Backdrop :show="show" :blur="backdrop_blur" @close="close" />
|
||||
|
||||
<!-- Panel -->
|
||||
<transition
|
||||
enter-active-class="transition duration-300 ease-in-out transform"
|
||||
:enter-from-class="left ? '-translate-x-full' : 'translate-x-full'"
|
||||
:enter-to-class="left ? '-translate-x-0' : 'translate-x-0'"
|
||||
leave-active-class="transition duration-300 ease-in-out transform"
|
||||
:leave-from-class="left ? '-translate-x-0' : 'translate-x-0'"
|
||||
:leave-to-class="left ? '-translate-x-full' : 'translate-x-full'"
|
||||
>
|
||||
<section
|
||||
v-if="show"
|
||||
:aria-labelledby="title"
|
||||
class="fixed z-999 border-left-2 border-gray-400 max-w-xs bg-white sm:max-w-md ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-cool-gray-800 dark:text-white"
|
||||
:class="`${left ? 'left-0' : 'right-0'} bg-opacity-${back_opacity} ${panel_style}`"
|
||||
>
|
||||
<div class="flex items-center justify-between flex-shrink-0 p-2">
|
||||
<h6 class="p-2 text-lg">
|
||||
{{ title }}
|
||||
</h6>
|
||||
<!-- Close button -->
|
||||
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="close">
|
||||
<CloseIcon class="w-6 h-6 text-gray-600 dark:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
<!-- Panel content -->
|
||||
<slot />
|
||||
</section>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Backdrop from '../global/Backdrop.vue'
|
||||
import CloseIcon from '../icons/CloseIcon.vue'
|
||||
import useState from '~/hooks/useState'
|
||||
|
||||
const props = defineProps<{
|
||||
show: {
|
||||
type: boolean,
|
||||
required: true,
|
||||
},
|
||||
left: {
|
||||
type: boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: string,
|
||||
required: true,
|
||||
},
|
||||
id: {
|
||||
type: string,
|
||||
required: true,
|
||||
},
|
||||
}>()
|
||||
|
||||
const backdrop_blur = useState().backdrop_blur
|
||||
const back_opacity = useState().back_opacity
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const panel_style = computed(() => {
|
||||
const key: any = props.id || ''
|
||||
return useState().panels.value[key] && useState().panels.value[key].style ? useState().panels.value[key].style : 'inset-y-0 w-full'
|
||||
})
|
||||
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
@ -1,51 +0,0 @@
|
||||
<template>
|
||||
<Panel :show="show" :title="t(title || 'search.search')" id="search" @close="close">
|
||||
<div class="flex-1 max-h-full p-4 space-y-4 overflow-hidden hover:overflow-y-auto dark:text-gray-600 dark:text-white">
|
||||
<form @submit.prevent="close" >
|
||||
<input
|
||||
type="text"
|
||||
v-model="search"
|
||||
:placeholder="`${t('search.search')}...`"
|
||||
class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring dark:text-gray-600 dark:text-white"
|
||||
>
|
||||
</form>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Panel from './Panel.vue'
|
||||
import useState from '~/hooks/useState'
|
||||
|
||||
const search = useState().search
|
||||
|
||||
defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
const { t, locale } = useI18n()
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
emit('close')
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<Panel :show="show" :title="title || t('settings.settings')" id="setting" @close="close">
|
||||
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
|
||||
<keep-alive>
|
||||
<component :is="currentComponent" />
|
||||
</keep-alive>
|
||||
<slot />
|
||||
<!-- Settings Panel Content ... -->
|
||||
</div>
|
||||
</Panel>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Panel from './Panel.vue'
|
||||
import useComponent, { DynComponent } from '~/hooks/useComponent'
|
||||
|
||||
defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
const cmpnt = useComponent()
|
||||
const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
const { t, locale } = useI18n()
|
||||
const currentComponent = computed(() => cmpnt.settingsComponent.value)
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
emit('close')
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
@ -1,170 +0,0 @@
|
||||
<template>
|
||||
<Backdrop :show="isSidebarOpen" :blur="backdrop_blur" class="lg:hidden" @close="isSidebarOpen = false" />
|
||||
<aside
|
||||
class="fixed inset-y-0 z-999 flex flex-col flex-shrink-0 w-64 max-h-screen transition-all transform border-r dark:border-gray-700 border-gray-200 bg-white shadow-lg lg:z-auto lg:static lg:shadow-none"
|
||||
:class="{ '-translate-x-full lg:translate-x-0 lg:w-20': !isSidebarOpen }"
|
||||
>
|
||||
<!-- sidebar header -->
|
||||
<SidebarHeader />
|
||||
<!-- Sidebar links -->
|
||||
<nav aria-label="Main" class="dark:bg-cool-gray-800 dark:text-white bg-white flex-1 overflow-hidden hover:overflow-y-auto">
|
||||
<!-- Sidebar Links... -->
|
||||
<ul class="p-2">
|
||||
<li
|
||||
v-for="(itm,index) in sidebarMenuItems"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
dark:border-gray-700
|
||||
border-gray-200
|
||||
>
|
||||
<hr v-if="itm.type === NavItemType.separator" class=" dark:border-gray-600 border-gray-300">
|
||||
<router-link
|
||||
v-if="itm.type === NavItemType.router_link"
|
||||
:title="t(itm.title)"
|
||||
:to="{ name: itm.name_to }"
|
||||
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
|
||||
:class="{ 'justify-center': !isSidebarOpen }"
|
||||
>
|
||||
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode||''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
|
||||
</router-link>
|
||||
<span
|
||||
v-if="itm.type === NavItemType.module_label"
|
||||
class="border-bottom-1 dark:border-gray-700 border-gray-200 flex text-xs color-gray-100"
|
||||
:class="isSidebarOpen ? 'justify-end' : 'justify-start'"
|
||||
>
|
||||
<span class="float-right text-gray-400" :class="{ 'lg:hidden': !isSidebarOpen }"> {{ t(`menu.${itm.label}`,'') }}</span>
|
||||
</span>
|
||||
<a
|
||||
v-if="itm.type == NavItemType.a_blank"
|
||||
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
|
||||
:class="{ 'justify-center': !isSidebarOpen }"
|
||||
@click="itemClick(itm.click || '')"
|
||||
>
|
||||
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
|
||||
</a>
|
||||
<a
|
||||
v-if="itm.type == NavItemType.a_link"
|
||||
rel="noreferrer"
|
||||
:href="itm.href || '#'"
|
||||
target="_blank"
|
||||
:title="t(itm.title)"
|
||||
>
|
||||
<span v-if="itm.icon_on === 'carbon-launch'"> <carbon-launch /> </span>
|
||||
<span class="ml-2" :class="{ 'lg:hidden': !isSidebarOpen }"> {{ t(itm.title) }}</span>
|
||||
</a>
|
||||
<a
|
||||
v-if="itm.type == NavItemType.app_link"
|
||||
:title="t(itm.title)"
|
||||
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
|
||||
:class="{ 'justify-center': !isSidebarOpen, 'ml-5': itm.name_to && itm.name_to === 'items' }"
|
||||
@click.prevent="appItemClick(itm)"
|
||||
>
|
||||
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
|
||||
</a>
|
||||
<a
|
||||
v-if="itm.type == NavItemType.cloud_link && !isSidebarOpen && itm.name_to && itm.name_to !== 'items'"
|
||||
:title="t(itm.title)"
|
||||
class="flex items-center justify-center p-2 overflow-hidden rounded-md hover:bg-gray-300 dark:hover:text-gray-100 dark:hover:bg-gray-500"
|
||||
@click.prevent="appItemClick(itm)"
|
||||
>
|
||||
<span v-if="itm.name_to && itm.name_to !== 'cloud'" class="flex -ml-2 text-gray-500 dark:text-gray-500 dark:hover:text-gray-100 dark:hover:bg-gray-500">
|
||||
<span v-if="isSidebarOpen && itm.pfx" class="-ml-2 mr-2 font-light">
|
||||
<small class="text-gray-400">{{ itm.pfx }}</small>
|
||||
</span>
|
||||
<span class="ml-2 text-xs font-light"> {{ itm.name || '' }}</span>
|
||||
</span>
|
||||
<span v-else class="pt-1 pb-1 border-b border-t border-gray-200 dark:border-gray-500">
|
||||
<span v-if="itm.icon_on === 'carbon-cloud'" class="flex justify-center items-center"> <carbon-cloud /> </span>
|
||||
<span class="text-xs flex justify-center items-center "> {{ itm.name || '' }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<span @click="on_logo_app" class="cursor-pointer text-xl font-semibold tracking-wider uppercase dark:bg-cool-gray-800 dark:text-white bg-white">
|
||||
<div class="flex">
|
||||
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
|
||||
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-4 mt-2 text-gray-400">{{ t('app.title','') }}</span>
|
||||
</div>
|
||||
</span>
|
||||
<SidebarFooter />
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import { computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Backdrop from '@/global/Backdrop.vue'
|
||||
import IconLink from '@/IconLink.vue'
|
||||
import SidebarFooter from './SidebarFooter.vue'
|
||||
import SidebarHeader from './SidebarHeader.vue'
|
||||
import useState from '~/hooks/useState'
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import { NavItemType } from '~/typs'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const { isSidebarOpen } = useState()
|
||||
const { t } = useI18n()
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const backdrop_blur = useState().backdrop_blur
|
||||
|
||||
const sidebarMenuItems = computed((): SideMenuItemType[] => {
|
||||
const ctx = router.currentRoute.value.meta.ctx || ''
|
||||
const defsMenuItems = defs.value && defs.value.sidebar && defs.value.sidebar.menu_items ? defs.value.sidebar.menu_items : [] as SideMenuItemType[]
|
||||
const all_items = [].concat(defsMenuItems || []) // .concat(useState().sidebarMenuItems.value as SideMenuItemType[] | any)
|
||||
useState().sidebarMenuItems.value = all_items.filter((itm: SideMenuItemType) => {
|
||||
if (itm.ctx && itm.ctx === ctx) {
|
||||
return true
|
||||
} else if (itm.ctx && itm.ctx !== ctx) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
return useState().sidebarMenuItems.value
|
||||
})
|
||||
|
||||
const itemClick = (target: string) => {
|
||||
switch (target) {
|
||||
case 'home':
|
||||
useState().bcPath.value = ''
|
||||
// useState().navTitle.value = ''
|
||||
router.push('/')
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
const appItemClick = (itm: SideMenuItemType) => {
|
||||
if (itm.cllbck) {
|
||||
itm.cllbck(itm)
|
||||
isSidebarOpen.value = false
|
||||
} else {
|
||||
if (useState().side_menu_click.value) {
|
||||
try {
|
||||
useState().side_menu_click.value(itm)
|
||||
isSidebarOpen.value.value = false
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
}
|
||||
} else if (itm.click === 'tophome') {
|
||||
router.push('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
const on_logo_app = () => {
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
useState().isSidebarOpen.value = false
|
||||
if (useState().app_home_click.value) {
|
||||
useState().app_home_click.value()
|
||||
}
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div class="flex-shrink-0 p-4 border-t dark:border-gray-700 border-gray-200 max-h-14 dark:bg-cool-gray-800 dark:text-white">
|
||||
<Button
|
||||
v-if="sidebarFooter.itm.type === NavItemType.a_link"
|
||||
class="flex w-full text-gray-700 bg-gray-100 hover:bg-gray-700 dark:bg-cool-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
|
||||
:class="{'justify-start': isSidebarOpen}"
|
||||
@click="itemClick(sidebarFooter.itm.click || '')"
|
||||
>
|
||||
<!-- LogoutIcon aria-hidden="true" class="w-6 h-6" -->
|
||||
<span v-if="sidebarFooter.itm.icon_on === 'carbon-logout'"> <carbon-logout /> </span>
|
||||
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-2"> {{ t(sidebarFooter.itm.title) }} </span>
|
||||
</Button>
|
||||
<router-link
|
||||
v-if="sidebarFooter.itm.type === NavItemType.router_link"
|
||||
:to="{ name: `${sidebarFooter.itm.name_to === 'Logout' && authData.auth === '' ? 'Login' : 'Logout'}` }"
|
||||
class="flex w-full text-gray-700 bg-gray-100 dark:bg-cool-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
|
||||
:class="{'justify-start': isSidebarOpen}"
|
||||
>
|
||||
<span v-if="sidebarFooter.itm.icon_on === 'carbon-logout' && authData.auth !== ''" class="mt-1"> <carbon-logout /> </span>
|
||||
<span v-else class="mt-1"> <carbon-login /> </span>
|
||||
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-2"> {{ t(sidebarFooter.itm.title) }} </span>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Button from '@/global/Button.vue'
|
||||
// import LogoutIcon from '@/icons/LogoutIcon.vue'
|
||||
import { computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useState from '~/hooks/useState'
|
||||
import { NavItemType } from '~/typs'
|
||||
import { auth_data } from '~/hooks/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const { isSidebarOpen } = useState()
|
||||
const { t } = useI18n()
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const authData = computed(() => auth_data())
|
||||
|
||||
const sidebarFooter = computed(() => {
|
||||
return defs.value && defs.value.sidebar && defs.value.sidebar.footer ? defs.value.sidebar.footer : { itm: {} }
|
||||
})
|
||||
|
||||
const itemClick = (target: string) => {
|
||||
switch (target) {
|
||||
case 'home':
|
||||
useState().bcPath.value = ''
|
||||
useState().navTitle.value = {} as any
|
||||
router.push('/')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between flex-shrink-0 p-2 dark:bg-cool-gray-800 dark:text-white" :class="{ 'lg:justify-center': !isSidebarOpen }">
|
||||
<span
|
||||
class="cursor-pointer text-lg lg:text-xl font-semibold leading-8 tracking-wider uppercase whitespace-nowrap dark:bg-cool-gray-800 dark:text-white"
|
||||
@click="on_logo_app"
|
||||
>
|
||||
<div class="flex">
|
||||
<img class="h-11 w-auto rounded" :src="`${header.logo && header.logo !== '' ? header.logo : '/assets/images/app_w.svg'}`" alt="App">
|
||||
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-4 mt-2 text-gray-400">{{ header.title || '' }}</span>
|
||||
</div>
|
||||
</span>
|
||||
<button class="rounded-md lg:hidden" @click="isSidebarOpen = false">
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-600"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useState from '~/hooks/useState'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
|
||||
const { isSidebarOpen } = useState()
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const header = computed(() => {
|
||||
return defs.value && defs.value.header ? defs.value.header : {}
|
||||
})
|
||||
|
||||
const on_logo_app = () => {
|
||||
useState().bcPath.value = ''
|
||||
useState().dfltNavTitle()
|
||||
useState().isSidebarOpen.value = false
|
||||
if (useState().app_home_click.value) {
|
||||
useState().app_home_click.value()
|
||||
}
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
</script>
|
@ -1,97 +0,0 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
// import WysiwygEditor from '@/WysiwygEditor.vue'
|
||||
// // import CodeEditor from '@/CodeEditor.vue'
|
||||
// import GridSettings from '~/views/GridSettings.vue'
|
||||
// import GridView from '~/views/GridView.vue'
|
||||
// import TableView from '~/views/TableView.vue'
|
||||
// import ListView from '~/views/ListView.vue'
|
||||
// import FormView from '~/views/FormView.vue'
|
||||
|
||||
// import TaFormView from '/app_modules/bm/ta/views/ta_form.vue'
|
||||
// import TaTableView from '/app_modules/bm/ta/views/ta_table.vue'
|
||||
// import TaListView from '/app_modules/bm/ta/views/ta_list.vue'
|
||||
|
||||
export enum DynComponent {
|
||||
// GridSettings,
|
||||
// GridJs,
|
||||
// TableView,
|
||||
// ListView,
|
||||
// FormView,
|
||||
// WysiwygEditor,
|
||||
// CodeEditor,
|
||||
}
|
||||
|
||||
const asideComponent = ref({})
|
||||
|
||||
const settingsComponent = ref({})
|
||||
|
||||
const fullSliderComponent = ref({})
|
||||
|
||||
const formViewComponent = ref({})
|
||||
|
||||
const dataViewComponent = ref({})
|
||||
|
||||
const topPaneComponent = ref({})
|
||||
|
||||
const bottomPaneComponent = ref({})
|
||||
|
||||
const moduleComponent = ref({})
|
||||
|
||||
const getModuleComponent = (key: string, target: string): any => {
|
||||
// switch (key) {
|
||||
// case 'ta':
|
||||
// switch (target) {
|
||||
// case 'form':
|
||||
// return TaFormView
|
||||
// break
|
||||
// case 'table':
|
||||
// return TaTableView
|
||||
// break
|
||||
// case 'list':
|
||||
// return TaListView
|
||||
// break
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
}
|
||||
const getComponent = (cmpnt: DynComponent): any => {
|
||||
// switch (cmpnt) {
|
||||
// case DynComponent.WysiwygEditor:
|
||||
// return WysiwygEditor
|
||||
// break
|
||||
// // case DynComponent.CodeEditor:
|
||||
// // return CodeEditor
|
||||
// // break
|
||||
// case DynComponent.GridSettings:
|
||||
// return GridSettings
|
||||
// break
|
||||
// case DynComponent.GridJs:
|
||||
// return GridView
|
||||
// break
|
||||
// case DynComponent.TableView:
|
||||
// return TableView
|
||||
// break
|
||||
// case DynComponent.ListView:
|
||||
// return ListView
|
||||
// break
|
||||
// case DynComponent.FormView:
|
||||
// return FormView
|
||||
// break
|
||||
// }
|
||||
}
|
||||
|
||||
export default function useComponent() {
|
||||
return {
|
||||
getModuleComponent,
|
||||
asideComponent,
|
||||
settingsComponent,
|
||||
fullSliderComponent,
|
||||
dataViewComponent,
|
||||
formViewComponent,
|
||||
getComponent,
|
||||
topPaneComponent,
|
||||
bottomPaneComponent,
|
||||
moduleComponent,
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
const roles = ['Admin', 'Editor', 'User']
|
||||
|
||||
const users = [
|
||||
{
|
||||
id: 'c27eb2bd-13d3-4231-aa60-e392b5f60d2e',
|
||||
name: 'Agnes Bogisich',
|
||||
email: 'Drake61@hotmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 'baca6dbf-4efe-4135-b584-5123dc6e1efa',
|
||||
name: 'Damaris Huels',
|
||||
email: 'Alayna.Rohan@yahoo.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 'ac991968-7f22-41e4-84ba-e62a335607c7',
|
||||
name: 'Monique Kozey',
|
||||
email: 'Louisa_Emard@gmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
id: '2b353eda-d96a-47b0-aaed-1871b257abd1',
|
||||
name: 'Kayden Collier',
|
||||
email: 'Rosina71@yahoo.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: '697fbe33-fe86-45fc-93e3-bd4335fe4063',
|
||||
name: 'Kiera Baumbach',
|
||||
email: 'Ashleigh10@hotmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: '0dffdd8d-84f4-4b87-8832-c6f560ebe850',
|
||||
name: 'Sage Dietrich',
|
||||
email: 'Ramona70@gmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
id: '46d0a8b6-b2c2-468e-b6d9-89c8520dccfe',
|
||||
name: 'Jodie Jones',
|
||||
email: 'Lempi89@gmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 'c8d54e36-f6e8-4c8f-b43a-4228ab11d7a9',
|
||||
name: 'Blaze Reilly',
|
||||
email: 'Dakota_Casper@yahoo.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: '47e143af-9e03-4c7c-9fe1-99f3374841cb',
|
||||
name: 'Margie Douglas',
|
||||
email: 'Jadyn.Ernser@yahoo.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 'd40ff313-4a69-4a70-9fc3-398d51e53114',
|
||||
name: 'Arianna Kilback',
|
||||
email: 'Fritz.Tremblay@gmail.com',
|
||||
role: roles[Math.round(Math.random() * (roles.length - 1))],
|
||||
active: false,
|
||||
},
|
||||
]
|
||||
|
||||
export default function useData() {
|
||||
return {
|
||||
users,
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import type { SideMenuItemType, UiPanelsType } from '~/typs/cmpnts'
|
||||
|
||||
const reqError = ref({ defs: '', lang: '', data: '', gql: '', api: '' })
|
||||
|
||||
const currentMapKey = ref('')
|
||||
const isSidebarOpen = ref(false)
|
||||
const toggleSidebar = () => {
|
||||
isSidebarOpen.value = !isSidebarOpen.value
|
||||
}
|
||||
const showModal = ref(false)
|
||||
|
||||
const isAsidePanelOpen = ref(false)
|
||||
|
||||
const sideSettingButton = ref(false)
|
||||
|
||||
const isSettingsPanelOpen = ref(false)
|
||||
|
||||
const isSearchPanelOpen = ref(false)
|
||||
const usideSettingButton = ref(false)
|
||||
|
||||
const isNotificationsPanelOpen = ref(false)
|
||||
|
||||
const useSettings = ref(false)
|
||||
|
||||
const useSearch = ref(false)
|
||||
|
||||
const search = ref('')
|
||||
|
||||
const bcPath = ref('')
|
||||
|
||||
const navTitle = ref({
|
||||
text: '',
|
||||
textclick: null as null | Function,
|
||||
title: '',
|
||||
cmpnt: '',
|
||||
ops: [] as any[],
|
||||
btntype: '',
|
||||
cllbck: null as null | Function,
|
||||
})
|
||||
const dfltNavTitle = () => {
|
||||
navTitle.value = {
|
||||
text: '',
|
||||
textclick: null as null | Function,
|
||||
title: '',
|
||||
cmpnt: '',
|
||||
ops: [] as any[],
|
||||
btntype: '',
|
||||
cllbck: null as null | Function,
|
||||
}
|
||||
}
|
||||
// '#fa-book/biomagnetismo/microorganismos/virus'
|
||||
|
||||
const bookCllbck = ref()
|
||||
const bookSelec = (data: string) => {
|
||||
if (data === '#') {
|
||||
bcPath.value = ''
|
||||
dfltNavTitle()
|
||||
}
|
||||
else {
|
||||
if (bookCllbck.value)
|
||||
bookCllbck.value(data)
|
||||
// else ...
|
||||
}
|
||||
}
|
||||
const sidebarMenuItems = ref([] as SideMenuItemType[])
|
||||
|
||||
const checkin = ref(false)
|
||||
const connection = ref({
|
||||
state: '',
|
||||
})
|
||||
|
||||
const tsksrvcs = 'tsksrvcs'
|
||||
const appsrvcs = 'appsrvcs'
|
||||
const srvcstatus = 'srvcstatus'
|
||||
|
||||
// const menu_items = ref([
|
||||
// { id: tsksrvcs, title: 'Tasks', active: false, link: '#' },
|
||||
// { id: appsrvcs, title: 'Applications', active: false, link: '#' },
|
||||
// { id: srvcstatus, title: 'Informations', active: false, link: '#' },
|
||||
// ])
|
||||
|
||||
const side_menu_click = ref()
|
||||
const app_home_click = ref()
|
||||
|
||||
const backdrop_blur = ref(14)
|
||||
const back_opacity = ref(60)
|
||||
const panels = ref({} as UiPanelsType)
|
||||
|
||||
const show_profile = ref(false)
|
||||
|
||||
export default function useState() {
|
||||
return {
|
||||
reqError,
|
||||
currentMapKey,
|
||||
isSidebarOpen,
|
||||
toggleSidebar,
|
||||
isAsidePanelOpen,
|
||||
isSettingsPanelOpen,
|
||||
isSearchPanelOpen,
|
||||
isNotificationsPanelOpen,
|
||||
useSettings,
|
||||
usideSettingButton,
|
||||
sideSettingButton,
|
||||
bcPath,
|
||||
bookSelec,
|
||||
bookCllbck,
|
||||
navTitle,
|
||||
dfltNavTitle,
|
||||
checkin,
|
||||
connection,
|
||||
sidebarMenuItems,
|
||||
showModal,
|
||||
tsksrvcs,
|
||||
appsrvcs,
|
||||
srvcstatus,
|
||||
// menu_items,
|
||||
side_menu_click,
|
||||
app_home_click,
|
||||
useSearch,
|
||||
search,
|
||||
back_opacity,
|
||||
backdrop_blur,
|
||||
panels,
|
||||
show_profile,
|
||||
}
|
||||
}
|
@ -1,339 +0,0 @@
|
||||
// import {
|
||||
// FixedAdjust,
|
||||
// DenseFixedAdjust,
|
||||
// ProminentFixedAdjust,
|
||||
// ShortFixedAdjust,
|
||||
// } from "@smui/top-app-bar";
|
||||
|
||||
import Toastify from 'toastify-js'
|
||||
import store from '~/store'
|
||||
import useState from '~/hooks/useState'
|
||||
import { AppDefsAction } from '~/store/types'
|
||||
import { MessageType } from '~/typs'
|
||||
import 'toastify-js/src/toastify.css'
|
||||
const { connection } = useState()
|
||||
|
||||
// import { postData, sendData } from './api.js'
|
||||
|
||||
// https://www.carlrippon.com/fetch-with-async-await-and-typescript/
|
||||
|
||||
/*
|
||||
const headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Request-Id': uuidv4(),
|
||||
'Authorization': `Bearer <API_TOKEN>`
|
||||
}
|
||||
*/
|
||||
// https://github.com/Maronato/vue-toastification#installation
|
||||
|
||||
export const show_message = (typ: MessageType, msg: string, timeout?: number): void => {
|
||||
// switch (typ) {
|
||||
// case MessageType.Show:
|
||||
// toast.show(msg)
|
||||
// break
|
||||
// case MessageType.Success:
|
||||
// toast.success(msg)
|
||||
// break
|
||||
// case MessageType.Error:
|
||||
// toast.error(msg)
|
||||
// break
|
||||
// case MessageType.Warning:
|
||||
// toast.warning(msg)
|
||||
// break
|
||||
// case MessageType.Info:
|
||||
// toast.info(msg)
|
||||
// break
|
||||
// }
|
||||
// if (timeout && timeout > 0)
|
||||
// setTimeout(toast.clear, timeout)
|
||||
// https://github.com/apvarun/toastify-js
|
||||
Toastify({
|
||||
text: msg,
|
||||
duration: timeout || 3000,
|
||||
destination: 'https://github.com/apvarun/toastify-js',
|
||||
newWindow: true,
|
||||
className: '',
|
||||
offset: {
|
||||
x: 10, // horizontal axis - can be a number or a string indicating unity. eg: '2em'
|
||||
y: 50, // vertical axis - can be a number or a string indicating unity. eg: '2em
|
||||
},
|
||||
close: true,
|
||||
gravity: 'top', // `top` or `bottom`
|
||||
position: 'left', // `left`, `center` or `right`
|
||||
backgroundColor: 'linear-gradient(to right, #00b09b, #96c93d)',
|
||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
||||
onClick() {}, // Callback after click
|
||||
}).showToast()
|
||||
}
|
||||
|
||||
export const translate = (store: any, map: string, ky: string, ctx: string, dflt?: string): string => {
|
||||
const val = dflt || ky
|
||||
const lang = store.state.app_lang.lang.get(map)
|
||||
// switch (ctx) {
|
||||
// case 'main':
|
||||
// val = lang.value.main && lang.value.main[ky] ? lang.value.main[ky] : val
|
||||
// break
|
||||
// case 'data':
|
||||
// val = lang.value.main && lang.value.main[ky] ? lang.value.main[ky] : val
|
||||
// val = lang.value.data[ky] || val
|
||||
// break
|
||||
// case 'forms':
|
||||
// val = lang.value.forms && lang.value.forms[ky] ? lang.value.forms[ky] : val
|
||||
// break
|
||||
// }
|
||||
if (lang && lang.value)
|
||||
return lang.value[ctx] && lang.value[ctx][ky] ? lang.value[ctx][ky] : val
|
||||
else if (lang && lang[ctx])
|
||||
return lang[ctx][ky] ? lang[ctx][ky] : val
|
||||
else
|
||||
return val
|
||||
}
|
||||
|
||||
export const senddata = async<T>(url: RequestInfo, data: BlobPart, file_name?: string, cllbck?: any): Promise<any> => {
|
||||
const formData = new FormData()
|
||||
// formData.append('blob', new Blob([JSON.stringify(rowData)]), 'test')
|
||||
// let response: Ref < T | undefined > = ref()
|
||||
|
||||
formData.append('blob', new Blob([data]), file_name)
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
mode: 'no-cors', // 'cors' by default
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
return response
|
||||
}
|
||||
catch (err) {
|
||||
if (cllbck)
|
||||
cllbck(err)
|
||||
else
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
export const postdata = (url: string, data: any, file_name: string, cllbck?: any): void => {
|
||||
if (data && file_name) {
|
||||
senddata(url, data, file_name, cllbck).then((result: any) => {
|
||||
if (result.status !== 0) {
|
||||
console.log(
|
||||
// throw Error(
|
||||
`Data sent to ${url} (${file_name}) - Network response NOT OK`,
|
||||
)
|
||||
}
|
||||
else {
|
||||
console.log(
|
||||
`Save data to ${url} (${file_name}) status: ${result.status}`,
|
||||
)
|
||||
}
|
||||
if (cllbck)
|
||||
cllbck(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
export const fetch_text = async(path: RequestInfo): Promise<any> => {
|
||||
try {
|
||||
const response = await fetch(path)
|
||||
return !response.ok ? response.text() : new Error('No items found')
|
||||
}
|
||||
catch (err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
export const fetch_json = async(path: RequestInfo, timeout = 2000): Promise<any> => {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async(resolve, reject) => {
|
||||
try {
|
||||
const response = await self.fetch(path)
|
||||
setTimeout(async() => {
|
||||
resolve(await response.json())
|
||||
}, timeout)
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const load_data = async(data_path: RequestInfo, ato: number, timeout = 2000, cllbck?: any) => {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
// return await new Promise(async(resolve, reject) => {
|
||||
useState().connection.value.state = ''
|
||||
const token = localStorage.getItem('auth') || ''
|
||||
// if (token === '')
|
||||
// return `error no auth for ${data_path}`
|
||||
|
||||
try {
|
||||
const headers = token !== "" ? { Authorization: `Bearer ${token}`} : {}
|
||||
// 'content-type': 'application/json',
|
||||
const res = await self.fetch(data_path, {
|
||||
headers
|
||||
})
|
||||
// setTimeout(async() => {
|
||||
let dataloaded = {}
|
||||
try {
|
||||
let strData = await res.text()
|
||||
for (let i = 0; i < ato; i++)
|
||||
strData = atob(strData)
|
||||
dataloaded = JSON.parse(strData)
|
||||
}
|
||||
catch (e) {
|
||||
return `error ${e} with ${data_path}`
|
||||
}
|
||||
if (Object.keys(dataloaded).length) {
|
||||
if (cllbck)
|
||||
cllbck(dataloaded)
|
||||
return ''
|
||||
}
|
||||
else {
|
||||
return new Error('No definitions found')
|
||||
}
|
||||
// }, timeout)
|
||||
}
|
||||
catch (err) {
|
||||
show_message(MessageType.Error, `'Data Load' -> ${err}`)
|
||||
useState().connection.value.state = 'connection.error'
|
||||
return err
|
||||
}
|
||||
// })
|
||||
}
|
||||
export const post_data = async(url: string, formData: any, with_auth = true) => {
|
||||
connection.value.state = ''
|
||||
let headers = {}
|
||||
if (with_auth) {
|
||||
const token = localStorage.getItem('auth') || ''
|
||||
if (token === '')
|
||||
return `error no auth for ${url}`
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`,
|
||||
// 'Access-Control-Allow-Origin': '*',
|
||||
// 'Accept': 'application/json',
|
||||
}
|
||||
}
|
||||
else {
|
||||
headers = { 'content-type': 'application/json' }
|
||||
}
|
||||
let formDataJsonString = ''
|
||||
try {
|
||||
formDataJsonString = JSON.stringify(formData)
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
return
|
||||
}
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: formDataJsonString,
|
||||
})
|
||||
if (!response.ok && response.status !== 200) {
|
||||
const errorMessage = await response.text()
|
||||
console.log(errorMessage)
|
||||
// throw new Error(errorMessage)
|
||||
}
|
||||
if (response.ok && response.status === 200)
|
||||
return response.json()
|
||||
}
|
||||
catch (e) {
|
||||
connection.value.state = 'connection.error'
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
export const check_credentials = async(url: string, data: any): Promise<any> => {
|
||||
let dataJsonString = ''
|
||||
try {
|
||||
dataJsonString = JSON.stringify(data)
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
return
|
||||
}
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: dataJsonString,
|
||||
})
|
||||
if (!response.ok) {
|
||||
const errorMessage = await response.text()
|
||||
// throw new Error(errorMessage)
|
||||
console.log(errorMessage)
|
||||
return
|
||||
}
|
||||
if (response.ok && response.status === 200)
|
||||
return response.json()
|
||||
}
|
||||
catch (e) {
|
||||
useState().connection.value.state = 'connection.error'
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
export const run_task = (val: number, task: Function) => {
|
||||
const now = new Date().getTime()
|
||||
const timePassed = now % val
|
||||
const run_at = val - timePassed
|
||||
setTimeout(task, run_at)
|
||||
}
|
||||
|
||||
export const verify_auth = async(mapkey: string, check_url: string, login_url: string) => {
|
||||
const auth = localStorage.getItem('auth') || ''
|
||||
const res = await check_credentials(check_url, { data: auth, mapkey })
|
||||
if (res && res.token === auth) {
|
||||
if (res.defs)
|
||||
store.dispatch(AppDefsAction.addDefs, { key: mapkey, defs: res.defs })
|
||||
if (res.defs.checkin && res.defs.checkin > 0) {
|
||||
run_task(res.defs.checkin, async() => {
|
||||
// console.log('run_task')
|
||||
const res_task = await verify_auth(mapkey, check_url, login_url)
|
||||
if (res_task)
|
||||
return
|
||||
if (useState().connection.value.state === '')
|
||||
location.href = login_url
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export const auth_data = () => {
|
||||
const auth = localStorage.getItem('auth') || ''
|
||||
let uidefs = {}
|
||||
if (store && store.state && store.state.app_defs && store.state.app_defs.main) {
|
||||
uidefs = store.state.app_defs.main.get('ui')
|
||||
}
|
||||
return {auth, uidefs}
|
||||
}
|
||||
|
||||
export const parse_str_json_data = (src: string, dflt: object|any) => {
|
||||
let data = dflt
|
||||
try {
|
||||
data = JSON.parse(src)
|
||||
}
|
||||
catch (e) {
|
||||
data = dflt
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export default {
|
||||
fetch_text,
|
||||
fetch_json,
|
||||
postdata,
|
||||
senddata,
|
||||
load_data,
|
||||
post_data,
|
||||
// store_data,
|
||||
show_message,
|
||||
translate,
|
||||
check_credentials,
|
||||
run_task,
|
||||
verify_auth,
|
||||
auth_data,
|
||||
parse_str_json_data,
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
<template>
|
||||
<div v-if="isCheckin">
|
||||
<div class="spinner" style="margin: 100px auto; width: 80px; height: 80px;">
|
||||
<div class="dot1" />
|
||||
<div class="dot2" />
|
||||
</div>
|
||||
<div class="flex justify-center text-2xl">
|
||||
{{ t('message.loadding') }} ...
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<div class="antialiased text-gray-900 bg-white dark:bg-gray-800 dark:text-white">
|
||||
<div class="flex h-screen overflow-y-hidden bg-white">
|
||||
<!-- Sidebar -->
|
||||
<Sidebar />
|
||||
|
||||
<div class="flex flex-col flex-1 h-full overflow-hidden">
|
||||
<!-- Navbar -->
|
||||
<header class="flex-shrink-0 border-b dark:border-gray-700 border-gray-200">
|
||||
<Navbar @on-nav-menu="onNavMenu" />
|
||||
</header>
|
||||
<!-- Main content -->
|
||||
<main class="flex-1 max-h-full overflow-hidden overflow-y-scroll dark:bg-cool-gray-800 dark:text-white">
|
||||
<slot />
|
||||
</main>
|
||||
<!-- Main footer -->
|
||||
<footer class="flex items-center justify-between flex-shrink-0 p-4 border-t dark:border-gray-700 border-gray-200 max-h-14 dark:bg-cool-gray-800 dark:text-white">
|
||||
<div class="flex">
|
||||
<span
|
||||
v-for="(itm,index) in left_items"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
>
|
||||
<a
|
||||
v-if="itm && itm.type === NavItemType.app_link"
|
||||
:href="itm.href"
|
||||
class="text-xs"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="itm && itm.type === 'router_link'"
|
||||
:title="t(itm.title)"
|
||||
:to="{ name: itm.name_to }"
|
||||
class="small-text flex items-center text-shadow-xs"
|
||||
>
|
||||
{{ t(itm.title) }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<Footer />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<span
|
||||
v-for="(itm,index) in right_items"
|
||||
:key="`${String(index)}-${itm.title}`"
|
||||
>
|
||||
<a
|
||||
v-if="itm && itm.type === NavItemType.app_link"
|
||||
:href="itm.href"
|
||||
class="flex items-center"
|
||||
>
|
||||
<span class="hidden text-sm md:block mr-2"> {{ t(itm.title) }} </span>
|
||||
<span v-if="itm.img" class="w-11 h-11 mr-2">
|
||||
<app-img v-if="itm.img === 'librecloudd'" />
|
||||
<img v-else class="h-11 w-auto rounded" :src="`/assets/images/${itm.img}.svg`" alt="App">
|
||||
</span>
|
||||
</a>
|
||||
<router-link
|
||||
v-if="itm && itm.type === 'router_link'"
|
||||
:title="t(itm.title)"
|
||||
:to="{ name: itm.name_to }"
|
||||
class="flex items-center"
|
||||
>
|
||||
<span class="hidden text-sm md:block mr-2"> {{ t(itm.title) }} </span>
|
||||
<span v-if="itm.img" class="w-11 h-11 mr-2">
|
||||
<app-img v-if="itm.img === 'librecloudd'" />
|
||||
<img v-else class="h-11 w-auto" :src="`/assets/images/${itm.img}.svg`" alt="App">
|
||||
</span>
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<!-- Setting panel button -->
|
||||
<div v-if="sideSettingButton" v-show="useSettings" class="fixed right-0 transform rotate-90 translate-x-8 top-1/2">
|
||||
<Button class="text-sm font-medium z-999 text-white uppercase bg-gray-600" @click="isSettingsPanelOpen = true">
|
||||
Settings
|
||||
</Button>
|
||||
</div>
|
||||
<SettingsPanel :show="isSettingsPanelOpen" @close="isSettingsPanelOpen = false" />
|
||||
<SearchPanel left :show="isSearchPanelOpen" @close="isSearchPanelOpen = false" />
|
||||
<NotificationsPanel left :show="isNotificationsPanelOpen" @close="isNotificationsPanelOpen = false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
<suspense v-else>
|
||||
<template #default>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<div class="space-up">
|
||||
<div class="spinner" style="margin: 100px auto; width: 80px; height: 80px;">
|
||||
<div class="dot1" />
|
||||
<div class="dot2" />
|
||||
</div>
|
||||
<div class="flex justify-center text-2xl">
|
||||
Check-in ...
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</suspense>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="https://karyo.dev"
|
||||
target="_blank"
|
||||
class="flex items-center space-x-1"
|
||||
>
|
||||
|
||||
<span class="w-11 h-11 dark:bg-gray-200 rounded-full mr-2">
|
||||
<dsc-logo />
|
||||
</span>
|
||||
<span class="hidden text-sm md:block">Z-Terton</span>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
*/
|
||||
import { onMounted, onUnmounted, ref, computed } from 'vue'
|
||||
|
||||
import { useRouter } from 'vue-router'
|
||||
import Sidebar from '@/sidebar/Sidebar.vue'
|
||||
import Navbar from '@/navbar/Navbar.vue'
|
||||
import SettingsPanel from '@/panels/SettingsPanel.vue'
|
||||
import SearchPanel from '@/panels/SearchPanel.vue'
|
||||
import NotificationsPanel from '@/panels/NotificationsPanel.vue'
|
||||
import Button from '@/global/Button.vue'
|
||||
import Footer from '@/Footer.vue'
|
||||
import AppImg from '@/icons/AppImg.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from 'vuex'
|
||||
import useState from '~/hooks/useState'
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import { NavItemType } from '~/typs'
|
||||
|
||||
// import { AppDefsAction } from '~/store/types'
|
||||
// import useComponent, { DynComponent } from '~/hooks/useComponent'
|
||||
// import { check_credentials } from '~/hooks/utils'
|
||||
|
||||
//const { reqError, isSidebarOpen, isAsidePanelOpen, isSettingsPanelOpen, isSearchPanelOpen, isNotificationsPanelOpen, sideSettingButton } = useState()
|
||||
const { isSidebarOpen, isSettingsPanelOpen, isSearchPanelOpen, isNotificationsPanelOpen, sideSettingButton, useSettings } = useState()
|
||||
|
||||
const checkScreen = () => {
|
||||
if (window.innerWidth <= 1024)
|
||||
isSidebarOpen.value = false
|
||||
}
|
||||
|
||||
// const props = defineProps<{
|
||||
// appdefs: any
|
||||
// }>()
|
||||
// const { appdefs } = toRefs(props)
|
||||
|
||||
// const use_panels = true
|
||||
// const show_top_pane = ref(false)
|
||||
// const show_bottom_pane = ref(false)
|
||||
|
||||
const isCheckin = ref(true)
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const left_items = computed((): SideMenuItemType[] => {
|
||||
return defs.value && defs.value.footer && defs.value.footer.left_items ? defs.value.footer.left_items : [] as SideMenuItemType[]
|
||||
})
|
||||
const right_items = computed((): SideMenuItemType[] => {
|
||||
return defs.value && defs.value.footer && defs.value.footer.right_items ? defs.value.footer.right_items : [] as SideMenuItemType[]
|
||||
})
|
||||
|
||||
const onNavMenu = (itm: SideMenuItemType) => {
|
||||
useState().show_profile.value = true
|
||||
}
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', checkScreen)
|
||||
isCheckin.value = false
|
||||
})
|
||||
|
||||
// const topPaneComponent = computed(() => useComponent().topPaneComponent.value)
|
||||
// const bottomPaneComponent = computed(() => useComponent().bottomPaneComponent.value)
|
||||
// const root_url = router.currentRoute.value.meta.rooturl || ''
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', checkScreen)
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.small-text {
|
||||
font-size: 75%;
|
||||
}
|
||||
.expandable {
|
||||
background: #dadada;
|
||||
overflow: hidden;
|
||||
|
||||
transition: all .5s ease-in-out;
|
||||
line-height: 0;
|
||||
padding: 0 1em;
|
||||
color: transparent;
|
||||
}
|
||||
.expandable:target {
|
||||
line-height: 1.5;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center min-h-screen p-4 space-y-4 antialiased text-gray-900 bg-white">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
@ -1,27 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="px-4 py-10 text-center text-teal-700 dark:text-gray-200">
|
||||
<div>
|
||||
<p class="text-4xl">
|
||||
<carbon-warning class="inline-block" />
|
||||
</p>
|
||||
</div>
|
||||
<router-view />
|
||||
<slot />
|
||||
<div>
|
||||
<button
|
||||
class="btn m-3 text-sm mt-8"
|
||||
@click="router.back()"
|
||||
>
|
||||
{{ t('button.back') }}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<div class="antialiased text-gray-900 bg-white">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200">
|
||||
<router-view />
|
||||
<Footer />
|
||||
<div class="mt-5 mx-auto text-center opacity-25 text-sm">
|
||||
[Default Layout]
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200">
|
||||
<router-view />
|
||||
<Footer />
|
||||
<div class="mt-5 mx-auto text-center opacity-25 text-sm">
|
||||
[Home Layout]
|
||||
</div>
|
||||
<router-link to="/datalist">
|
||||
Data List
|
||||
</router-link>
|
||||
</main>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
onBeforeRouteUpdate((to: any, from: any) => {
|
||||
})
|
||||
onBeforeRouteLeave((to, from) => {
|
||||
// console.log(to);
|
||||
// const answer = window.confirm(
|
||||
// 'Do you really want to leave? you have unsaved changes!'
|
||||
// )
|
||||
// // cancel the navigation and stay on the same page
|
||||
// if (!answer) return false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,2 +0,0 @@
|
||||
export const isDark = useDark()
|
||||
export const toggleDark = useToggle(isDark)
|
@ -1 +0,0 @@
|
||||
export * from './dark'
|
59
src/main.ts
59
src/main.ts
@ -1,59 +0,0 @@
|
||||
// windicss layers
|
||||
import 'virtual:windi-base.css'
|
||||
import 'virtual:windi-components.css'
|
||||
// your custom styles here
|
||||
import './styles/main.css'
|
||||
// windicss utilities should be the last style import
|
||||
import 'virtual:windi-utilities.css'
|
||||
// windicss devtools support (dev only)
|
||||
import 'virtual:windi-devtools'
|
||||
|
||||
import VueAnimXYZ from '@animxyz/vue' // import AnimXZY vue package
|
||||
import '@animxyz/core'
|
||||
|
||||
// register vue composition api globally
|
||||
import { createApp } from 'vue'
|
||||
// import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { createHead, useHead } from '@vueuse/head'
|
||||
|
||||
import App from './App.vue'
|
||||
|
||||
import routes from './router'
|
||||
import store from './store'
|
||||
|
||||
import 'a17t'
|
||||
|
||||
import { messages } from './modules/i18n'
|
||||
// import GuestLayout from '~/layouts/GuestLayout.vue'
|
||||
import AppLayout from '~/layouts/AppLayout.vue'
|
||||
import SimpleLayout from '~/layouts/SimpleLayout.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: 'es',
|
||||
legacy: false,
|
||||
fallbackLocale: ['es'],
|
||||
fallbackWarn: false,
|
||||
missing: (locale, key, instance) => {
|
||||
console.warn(`detect '${key}' key missing in '${locale}'`)
|
||||
},
|
||||
messages,
|
||||
})
|
||||
|
||||
const head = createHead()
|
||||
// const router = createRouter({
|
||||
// history: createWebHistory(),
|
||||
// routes,
|
||||
// })
|
||||
app.use(VueAnimXYZ)
|
||||
app.use(store)
|
||||
app.use(i18n)
|
||||
app.use(routes)
|
||||
// app.use(router)
|
||||
app.use(head)
|
||||
app.component('AppLayout', AppLayout)
|
||||
app.component('SimpleLayout', SimpleLayout)
|
||||
// app.component('GuestLayout', GuestLayout)
|
||||
app.mount('#app')
|
@ -1,11 +0,0 @@
|
||||
## Modules
|
||||
|
||||
A custom user module system. Place a `.ts` file with the following template, it will be installed automatically.
|
||||
|
||||
```ts
|
||||
import { UserModule } from '~/types'
|
||||
|
||||
export const install: UserModule = ({ app, router, isClient }) => {
|
||||
// do something
|
||||
}
|
||||
```
|
@ -1,25 +0,0 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
// import { UserModule } from '~/types'
|
||||
|
||||
// import i18n resources
|
||||
// https://vitejs.dev/guide/features.html#glob-import
|
||||
export const messages = Object.fromEntries(
|
||||
Object.entries(
|
||||
import.meta.globEager('../../locales/*.y(a)?ml'))
|
||||
.map(([key, value]) => {
|
||||
const yaml = key.endsWith('.yaml')
|
||||
return [key.slice(14, yaml ? -5 : -4), value.default]
|
||||
}),
|
||||
)
|
||||
/*
|
||||
export const install: UserModule = ({ app }) => {
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
messages,
|
||||
})
|
||||
|
||||
app.use(i18n)
|
||||
}
|
||||
|
||||
*/
|
@ -1,9 +0,0 @@
|
||||
import NProgress from 'nprogress'
|
||||
import { UserModule } from '~/types'
|
||||
|
||||
export const install: UserModule = ({ isClient, router }) => {
|
||||
if (isClient) {
|
||||
router.beforeEach(() => { NProgress.start() })
|
||||
router.afterEach(() => { NProgress.done() })
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { UserModule } from '~/types'
|
||||
|
||||
export const install: UserModule = ({ isClient, router }) => {
|
||||
if (isClient) {
|
||||
router.isReady().then(async() => {
|
||||
if (isClient) {
|
||||
const { registerSW } = await import('virtual:pwa-register')
|
||||
registerSW({ immediate: true })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
## File-based Routing
|
||||
|
||||
Routes will be auto-generated for Vue files in this dir with the same file structure.
|
||||
Check out [`vite-plugin-pages`](https://github.com/hannoeru/vite-plugin-pages) for more details.
|
||||
|
||||
### Path Aliasing
|
||||
|
||||
`~/` is aliased to `./src/` folder.
|
||||
|
||||
For example, instead of having
|
||||
|
||||
```ts
|
||||
import { isDark } from '../../../../logic'
|
||||
```
|
||||
|
||||
now, you can use
|
||||
|
||||
```ts
|
||||
import { isDark } from '~/logic'
|
||||
```
|
@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
Not Found
|
||||
</div>
|
||||
</template>
|
@ -1,52 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const name = ref('')
|
||||
|
||||
const router = useRouter()
|
||||
const go = () => {
|
||||
if (name.value)
|
||||
router.push(`/hi/${encodeURIComponent(name.value)}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="text-4xl">
|
||||
<carbon-campsite class="inline-block" />
|
||||
</p>
|
||||
<p>
|
||||
<a rel="noreferrer" href="https://github.com/antfu/vitesse-lite" target="_blank">
|
||||
Vitesse Lite
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<em class="text-sm opacity-75">Opinionated Vite Starter Template</em>
|
||||
</p>
|
||||
|
||||
<div class="py-4" />
|
||||
|
||||
<input
|
||||
id="input"
|
||||
v-model="name"
|
||||
placeholder="What's your name?"
|
||||
type="text"
|
||||
autocomplete="false"
|
||||
p="x-4 y-2"
|
||||
w="250px"
|
||||
text="center"
|
||||
bg="transparent"
|
||||
border="~ rounded gray-200 dark:gray-700"
|
||||
outline="none active:none"
|
||||
@keydown.enter="go"
|
||||
>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="m-3 text-sm btn"
|
||||
:disabled="!name"
|
||||
@click="go"
|
||||
>
|
||||
Go
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,27 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ name: string }>()
|
||||
const router = useRouter()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="text-4xl">
|
||||
<carbon-pedestrian class="inline-block" />
|
||||
</p>
|
||||
<p>
|
||||
Hi, {{ props.name }}
|
||||
</p>
|
||||
<p class="text-sm opacity-50">
|
||||
<em>Dynamic route!</em>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="btn m-3 text-sm mt-8"
|
||||
@click="router.back()"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
235
src/router.ts
235
src/router.ts
@ -1,235 +0,0 @@
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||
|
||||
// import { defineAsyncComponent } from 'vue'
|
||||
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
import generatedRoutes from 'virtual:generated-pages'
|
||||
// import generatedRoutes from 'pages-generated'
|
||||
// import { setupLayouts } from 'layouts-generated'
|
||||
|
||||
import useState from '~/hooks/useState'
|
||||
|
||||
// const Login = defineAsyncComponent(() => import('./views/Login.vue'))
|
||||
import store from '~/store'
|
||||
|
||||
import Home from '~/views/Home.vue'
|
||||
import About from '~/views/about.md'
|
||||
// import Register from '~/views/auth/Register.vue'
|
||||
import Login from '~/views/Login.vue'
|
||||
import Logout from '~/views/Logout.vue'
|
||||
import Profile from '~/components/Profile.vue'
|
||||
|
||||
import { verify_auth, check_credentials } from '~/hooks/utils'
|
||||
// import {
|
||||
// lang_url,
|
||||
// req_lang,
|
||||
// } from '~/defs/ta_defs'
|
||||
// const DataGrid = () => import('~/views/DataGrid.vue')
|
||||
//const SambaModel = () => import('~/views/SambaModel.vue')
|
||||
|
||||
const layoutsRoutes = setupLayouts(generatedRoutes)
|
||||
/*
|
||||
// import routes generated by Voie
|
||||
import pgRoutes from 'voie-pages'
|
||||
|
||||
const UIElements = defineAsyncComponent(() => import('./views/UIElements.vue'))
|
||||
const Tables = defineAsyncComponent(() => import('./views/Tables.vue'))
|
||||
const Dashboard = defineAsyncComponent(() => import('./views/Dashboard.vue'))
|
||||
const Forms = defineAsyncComponent(() => import('./views/Forms.vue'))
|
||||
const Input = defineAsyncComponent(() => import('./views/Input.vue'))
|
||||
const Home = defineAsyncComponent(() => import('./views/Home.vue'))
|
||||
const Modal = defineAsyncComponent(() => import('./views/Modal.vue'))
|
||||
const Blank = defineAsyncComponent(() => import('./views/Blank.vue'))
|
||||
const OLogin = defineAsyncComponent(() => import('./views/OLogin.vue'))
|
||||
const Entry = defineAsyncComponent(() => import('./views/Entry.vue'))
|
||||
*/
|
||||
|
||||
// https://medium.com/swlh/adding-meta-fields-and-transitions-to-vue-router-routes-f5cb78a7ed97
|
||||
// router.beforeEach((to, from, next) => {
|
||||
// if (to.meta.requireAuth) {
|
||||
// if (!localStorage.getItem("auth")) {
|
||||
// next('/notfound')
|
||||
// } else {
|
||||
// next();
|
||||
// }
|
||||
// } else {
|
||||
// next();
|
||||
// }
|
||||
// });
|
||||
|
||||
// const get_lang = (_to: any, _from: any, next: any) => {
|
||||
// req_lang(lang_url, (lang: any) => { lng: lang })
|
||||
// // req_lang(lang_url, () => next())
|
||||
// }
|
||||
|
||||
const rooturl = window.ROOT_LOCATION || location.origin
|
||||
|
||||
const check_auth = async(to: any, _from: any, next: any) => {
|
||||
useState().bcPath.value = ''
|
||||
const auth = localStorage.getItem('auth') || ''
|
||||
const check_url = `${window.ROOT_LOCATION || location.origin}/checkin`
|
||||
const login_url = `${location.origin}/ui/login`
|
||||
const login_route = '/login'
|
||||
const mapkey = to.meta.uimapkey || 'ui'
|
||||
const map_route_to = () => {
|
||||
if (to.meta.requireAuth) {
|
||||
return login_route
|
||||
}
|
||||
if (to.meta.pubLayout) {
|
||||
to.meta.layout = to.meta.pubLayout
|
||||
to.meta.useNav = !to.meta.useNav
|
||||
}
|
||||
return
|
||||
}
|
||||
if (auth !== '') {
|
||||
const defs = store.state.app_defs.main.get(mapkey)
|
||||
if (defs && defs.checkin && useState().checkin.value) {
|
||||
next()
|
||||
}
|
||||
else {
|
||||
useState().checkin.value = true
|
||||
const res = await verify_auth(mapkey, check_url, login_url)
|
||||
// if (useState().connection.value.state === '')
|
||||
// TODO redirect to a connection error page or consider PWA offline mode
|
||||
if (res && res.defs)
|
||||
next()
|
||||
else {
|
||||
const route=map_route_to()
|
||||
next(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const route=map_route_to()
|
||||
next(route)
|
||||
}
|
||||
}
|
||||
|
||||
const get_defs = async(mapkey: string) => {
|
||||
const auth = localStorage.getItem('auth') || ''
|
||||
const url = `${window.ROOT_LOCATION || location.origin}/checkin`
|
||||
if (auth !== '') {
|
||||
const res = await check_credentials(url, { data: auth, mapkey })
|
||||
if (res.token === auth)
|
||||
return res.defs || {}
|
||||
else
|
||||
return {}
|
||||
}
|
||||
else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
/*
|
||||
{
|
||||
path: '/home',
|
||||
alias: '/',
|
||||
name: 'Home',
|
||||
component: Home,
|
||||
meta: { layout: 'empty' },
|
||||
},
|
||||
{
|
||||
path: '/ui/samba',
|
||||
name: 'Samba',
|
||||
component: SambaModel,
|
||||
meta: { layout: 'AppLayout' },
|
||||
},
|
||||
*/
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Home,
|
||||
meta: {
|
||||
requireAuth: false,
|
||||
layout: 'AppLayout',
|
||||
ctx: 'home',
|
||||
// useNav: false,
|
||||
// pubLayout: 'SimpleLayout',
|
||||
mapkey: 'kloud',
|
||||
uiMapkey: 'ui',
|
||||
rooturl,
|
||||
},
|
||||
beforeEnter: check_auth,
|
||||
// (_to: any, _from: any, next: any) => {
|
||||
// req_lang(lang_url, () => next())
|
||||
// },
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: Login,
|
||||
meta: { layout: 'empty', rooturl, use_logo: true, allow_register: false, allow_reset: false },
|
||||
},
|
||||
{
|
||||
path: '/logout',
|
||||
name: 'Logout',
|
||||
component: Logout,
|
||||
meta: { layout: 'empty', rooturl, use_logo: true },
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
meta: {
|
||||
layout: 'AppLayout',
|
||||
ctx: 'about',
|
||||
rooturl,
|
||||
use_loog: true,
|
||||
},
|
||||
component: About,
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
name: 'Profile',
|
||||
meta: {
|
||||
layout: 'AppLayout',
|
||||
ctx: 'profile',
|
||||
rooturl,
|
||||
use_loog: true,
|
||||
},
|
||||
component: Profile,
|
||||
},
|
||||
// {
|
||||
// path: '/auth/register',
|
||||
// name: 'Register',
|
||||
// component: Register,
|
||||
// meta: { layout: 'GuestLayout' },
|
||||
// },
|
||||
/*
|
||||
{
|
||||
path: '/datalist',
|
||||
name: 'DataGrid',
|
||||
component: DataGrid,
|
||||
meta: {
|
||||
requireAuth: true,
|
||||
layout: 'AppLayout',
|
||||
uiMapkey: 'ui',
|
||||
mapkey: 'kloud',
|
||||
rooturl,
|
||||
bcpath: '#fa-book/librecloud/klouds',
|
||||
},
|
||||
beforeEnter: check_auth,
|
||||
// props: { lang: 'es' }, // get_lang,
|
||||
// beforeEnter: get_lang,
|
||||
// (_to: any, _from: any, next: any) => {
|
||||
// req_lang(lang_url, () => next())
|
||||
// },
|
||||
},
|
||||
*/
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
name: '404',
|
||||
meta: { layout: 'Page404' },
|
||||
component: () => import('./views/404.vue'),
|
||||
},
|
||||
...layoutsRoutes,
|
||||
]
|
||||
|
||||
// const routes: RouteRecordRaw[] = pgRoutes
|
||||
const router: any = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
})
|
||||
// routes,
|
||||
export default router
|
57
src/shims.d.ts
vendored
57
src/shims.d.ts
vendored
@ -1,57 +0,0 @@
|
||||
/* eslint-disable import/no-duplicates */
|
||||
|
||||
declare interface Window {
|
||||
// extend the window
|
||||
ROOT_LOCATION: string
|
||||
}
|
||||
|
||||
// with vite-plugin-md, markdowns can be treat as Vue components
|
||||
declare module '*.md' {
|
||||
import { ComponentOptions } from 'vue'
|
||||
const component: ComponentOptions
|
||||
export default component
|
||||
}
|
||||
/*
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
}
|
||||
*/
|
||||
declare const _APP_VERSION: string
|
||||
/*
|
||||
* Keep states in the global scope to be reusable across Vue instances.
|
||||
*
|
||||
* @see {@link /createGlobalState}
|
||||
* @param stateFactory A factory function to create the state
|
||||
*/
|
||||
/*
|
||||
declare function createGlobalState<T extends object>(
|
||||
stateFactory: () => T
|
||||
): () => T
|
||||
*/
|
||||
interface EventTarget {
|
||||
value: EventTarget|null
|
||||
name: string| null
|
||||
/**
|
||||
* Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.
|
||||
*
|
||||
* The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture.
|
||||
*
|
||||
* When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET.
|
||||
*
|
||||
* When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.
|
||||
*
|
||||
* When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed.
|
||||
*
|
||||
* The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture.
|
||||
*/
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void
|
||||
/**
|
||||
* Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
|
||||
*/
|
||||
dispatchEvent(event: Event): boolean
|
||||
/**
|
||||
* Removes the event listener in target's event listener list with the same type, callback, and options.
|
||||
*/
|
||||
removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
import { InjectionKey } from 'vue'
|
||||
import {
|
||||
createStore,
|
||||
createLogger,
|
||||
Store as VuexStore,
|
||||
useStore as baseUseStore,
|
||||
} from 'vuex'
|
||||
|
||||
import {
|
||||
app_data,
|
||||
AppDataState,
|
||||
app_check,
|
||||
AppCheckState,
|
||||
app_defs,
|
||||
AppDefsState,
|
||||
app_profile,
|
||||
AppProfileState,
|
||||
AppLangState,
|
||||
app_lang,
|
||||
} from './modules'
|
||||
|
||||
import { Store as AppDataStore } from './modules/app/data'
|
||||
import { Store as AppCheckStore } from './modules/app/check'
|
||||
import { Store as AppDefsStore } from './modules/app/defs'
|
||||
import { Store as AppProfileStore } from './modules/app/profile'
|
||||
import { Store as AppLangStore } from './modules/app/lang'
|
||||
|
||||
export interface RootState {
|
||||
data: AppDataState
|
||||
check: AppCheckState
|
||||
defs: AppDefsState
|
||||
profile: AppProfileState
|
||||
lang: AppLangState
|
||||
}
|
||||
|
||||
export type RootStore = AppDataStore<Pick<RootState, 'data'>>
|
||||
& AppCheckStore<Pick<RootState, 'check'>>
|
||||
& AppDefsStore<Pick<RootState, 'defs'>>
|
||||
& AppProfileStore<Pick<RootState, 'profile'>>
|
||||
& AppLangStore<Pick<RootState, 'lang'>>
|
||||
|
||||
// eslint-disable-next-line symbol-description
|
||||
export const key: InjectionKey<VuexStore<RootState>> = Symbol()
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production'
|
||||
|
||||
export default createStore<RootState>({
|
||||
modules: {
|
||||
app_data,
|
||||
app_check,
|
||||
app_defs,
|
||||
app_profile,
|
||||
app_lang,
|
||||
},
|
||||
strict: debug,
|
||||
plugins: debug ? [createLogger()] : [],
|
||||
})
|
||||
|
||||
// export const useStore = (): RootStore => {
|
||||
// return baseUseStore(key)
|
||||
// }
|
@ -1,44 +0,0 @@
|
||||
import { ActionContext, ActionTree } from 'vuex'
|
||||
import { Mutations, MutationTypes } from './mutations'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export enum ActionTypes {
|
||||
addCheck = 'addCheck',
|
||||
removeCheck = 'removeCheck',
|
||||
editCheck = 'editCheck'
|
||||
}
|
||||
|
||||
type AppCheckActionContext = {
|
||||
commit<K extends keyof Mutations>(
|
||||
key: K,
|
||||
payload: Parameters<Mutations[K]>[1]
|
||||
): ReturnType<Mutations[K]>
|
||||
} & Omit<ActionContext<State, RootState>, 'commit'>
|
||||
|
||||
export interface Actions {
|
||||
[ActionTypes.addCheck](
|
||||
{ commit }: AppCheckActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.removeCheck](
|
||||
{ commit }: AppCheckActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.editCheck](
|
||||
{ commit }: AppCheckActionContext,
|
||||
payload: any
|
||||
): void
|
||||
}
|
||||
|
||||
export const actions: ActionTree<State, RootState> & Actions = {
|
||||
[ActionTypes.addCheck]({ commit }, payload) {
|
||||
commit(MutationTypes.addCheck, payload)
|
||||
},
|
||||
[ActionTypes.removeCheck]({ commit }, payload) {
|
||||
commit(MutationTypes.removeCheck, payload)
|
||||
},
|
||||
[ActionTypes.editCheck]({ commit }, payload) {
|
||||
commit(MutationTypes.editCheck, payload)
|
||||
},
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export type Getters<S = State> = {
|
||||
check(state: S, key: string): any
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, RootState> & Getters = {
|
||||
check: (state, key: string) => {
|
||||
return state.check.get(key)
|
||||
},
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import {
|
||||
Store as VuexStore,
|
||||
Module,
|
||||
CommitOptions,
|
||||
DispatchOptions,
|
||||
} from 'vuex'
|
||||
|
||||
import { getters, Getters } from './getters'
|
||||
import { mutations, Mutations, MutationTypes } from './mutations'
|
||||
import { actions, Actions, ActionTypes } from './actions'
|
||||
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
interface State {
|
||||
check: Map<string, any>
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
check: new Map(),
|
||||
}
|
||||
|
||||
const data_module: Module<State, RootState> = {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
}
|
||||
|
||||
export default data_module
|
||||
|
||||
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
|
||||
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
|
||||
key: K,
|
||||
payload: P,
|
||||
options?: CommitOptions
|
||||
): ReturnType<Mutations[K]>
|
||||
} & {
|
||||
getters: {
|
||||
[K in keyof Getters]: ReturnType<Getters[K]>
|
||||
}
|
||||
} & {
|
||||
dispatch<K extends keyof Actions>(
|
||||
key: K,
|
||||
payload: Parameters<Actions[K]>[1],
|
||||
options?: DispatchOptions
|
||||
): ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
export { State, ActionTypes, MutationTypes, Store }
|
@ -1,48 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { AppCheck } from '~/store/types'
|
||||
|
||||
export enum MutationTypes {
|
||||
addCheck = 'addCheck',
|
||||
removeCheck = 'removeCheck',
|
||||
editCheck = 'editCheck'
|
||||
}
|
||||
|
||||
interface CheckMap {
|
||||
key: string
|
||||
check: any
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.addCheck](state: S, check_map: CheckMap): void
|
||||
[MutationTypes.removeCheck](state: S, check_map: CheckMap): void
|
||||
[MutationTypes.editCheck](state: S, check_map: CheckMap, key: string): void
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
[MutationTypes.addCheck](state: State, check_map: CheckMap) {
|
||||
if (check_map.key && check_map.check)
|
||||
state.check.set(check_map.key, check_map.check)
|
||||
},
|
||||
[MutationTypes.removeCheck](state: State, check_map: CheckMap) {
|
||||
if (check_map.key && check_map.check) {
|
||||
const check = state.check.get(check_map.key)
|
||||
check.splice(check.indexOf(check_map.check), 1)
|
||||
state.check.set(check_map.key, check)
|
||||
}
|
||||
},
|
||||
[MutationTypes.editCheck](state: State, check_map: CheckMap) {
|
||||
if (check_map.key && check_map.check) {
|
||||
const new_check = [] as unknown as any
|
||||
const check = state.check.get(check_map.key)
|
||||
const key = check_map.check.id
|
||||
check.forEach((it: any) => {
|
||||
if (it.id === key)
|
||||
new_check.push(check)
|
||||
else
|
||||
new_check.push(it)
|
||||
})
|
||||
state.check.set(check_map.key, new_check)
|
||||
}
|
||||
},
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { ActionContext, ActionTree } from 'vuex'
|
||||
import { Mutations, MutationTypes } from './mutations'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export enum ActionTypes {
|
||||
addData = 'addData',
|
||||
removeData = 'removeData',
|
||||
editData = 'editData'
|
||||
}
|
||||
|
||||
type AppDataActionContext = {
|
||||
commit<K extends keyof Mutations>(
|
||||
key: K,
|
||||
payload: Parameters<Mutations[K]>[1]
|
||||
): ReturnType<Mutations[K]>
|
||||
} & Omit<ActionContext<State, RootState>, 'commit'>
|
||||
|
||||
export interface Actions {
|
||||
[ActionTypes.addData](
|
||||
{ commit }: AppDataActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.removeData](
|
||||
{ commit }: AppDataActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.editData](
|
||||
{ commit }: AppDataActionContext,
|
||||
payload: any
|
||||
): void
|
||||
}
|
||||
|
||||
export const actions: ActionTree<State, RootState> & Actions = {
|
||||
[ActionTypes.addData]({ commit }, payload) {
|
||||
commit(MutationTypes.addData, payload)
|
||||
},
|
||||
[ActionTypes.removeData]({ commit }, payload) {
|
||||
commit(MutationTypes.removeData, payload)
|
||||
},
|
||||
[ActionTypes.editData]({ commit }, payload) {
|
||||
commit(MutationTypes.editData, payload)
|
||||
},
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export type Getters<S = State> = {
|
||||
data(state: S, key: string): any
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, RootState> & Getters = {
|
||||
data: (state, key: string) => {
|
||||
return state.data.get(key)
|
||||
},
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import {
|
||||
Store as VuexStore,
|
||||
Module,
|
||||
CommitOptions,
|
||||
DispatchOptions,
|
||||
} from 'vuex'
|
||||
|
||||
import { getters, Getters } from './getters'
|
||||
import { mutations, Mutations, MutationTypes } from './mutations'
|
||||
import { actions, Actions, ActionTypes } from './actions'
|
||||
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
interface State {
|
||||
data: Map<string, any>
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
data: new Map(),
|
||||
}
|
||||
|
||||
const data_module: Module<State, RootState> = {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
}
|
||||
|
||||
export default data_module
|
||||
|
||||
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
|
||||
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
|
||||
key: K,
|
||||
payload: P,
|
||||
options?: CommitOptions
|
||||
): ReturnType<Mutations[K]>
|
||||
} & {
|
||||
getters: {
|
||||
[K in keyof Getters]: ReturnType<Getters[K]>
|
||||
}
|
||||
} & {
|
||||
dispatch<K extends keyof Actions>(
|
||||
key: K,
|
||||
payload: Parameters<Actions[K]>[1],
|
||||
options?: DispatchOptions
|
||||
): ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
export { State, ActionTypes, MutationTypes, Store }
|
@ -1,48 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { AppData } from '~/store/types'
|
||||
|
||||
export enum MutationTypes {
|
||||
addData = 'addData',
|
||||
removeData = 'removeData',
|
||||
editData = 'editData'
|
||||
}
|
||||
|
||||
interface DataMap {
|
||||
key: string
|
||||
data: any
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.addData](state: S, data_map: DataMap): void
|
||||
[MutationTypes.removeData](state: S, data_map: DataMap): void
|
||||
[MutationTypes.editData](state: S, data_map: DataMap, key: string): void
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
[MutationTypes.addData](state: State, data_map: DataMap) {
|
||||
if (data_map.key && data_map.data)
|
||||
state.data.set(data_map.key, data_map.data)
|
||||
},
|
||||
[MutationTypes.removeData](state: State, data_map: DataMap) {
|
||||
if (data_map.key && data_map.data) {
|
||||
const data = state.data.get(data_map.key)
|
||||
data.splice(data.indexOf(data_map.data), 1)
|
||||
state.data.set(data_map.key, data)
|
||||
}
|
||||
},
|
||||
[MutationTypes.editData](state: State, data_map: DataMap) {
|
||||
if (data_map.key && data_map.data) {
|
||||
const new_data = [] as unknown as any
|
||||
const data = state.data.get(data_map.key)
|
||||
const key = data_map.data.id
|
||||
data.forEach((it: any) => {
|
||||
if (it.id === key)
|
||||
new_data.push(data)
|
||||
else
|
||||
new_data.push(it)
|
||||
})
|
||||
state.data.set(data_map.key, new_data)
|
||||
}
|
||||
},
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { ActionContext, ActionTree } from 'vuex'
|
||||
import { Mutations, MutationTypes } from './mutations'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export enum ActionTypes {
|
||||
addDefs = 'addDefs',
|
||||
removeDefs = 'removeDefs',
|
||||
editDefs = 'editDefs'
|
||||
}
|
||||
|
||||
type AppDefsActionContext = {
|
||||
commit<K extends keyof Mutations>(
|
||||
key: K,
|
||||
payload: Parameters<Mutations[K]>[1]
|
||||
): ReturnType<Mutations[K]>
|
||||
} & Omit<ActionContext<State, RootState>, 'commit'>
|
||||
|
||||
export interface Actions {
|
||||
[ActionTypes.addDefs](
|
||||
{ commit }: AppDefsActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.removeDefs](
|
||||
{ commit }: AppDefsActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.editDefs](
|
||||
{ commit }: AppDefsActionContext,
|
||||
payload: any
|
||||
): void
|
||||
}
|
||||
|
||||
export const actions: ActionTree<State, RootState> & Actions = {
|
||||
[ActionTypes.addDefs]({ commit }, payload) {
|
||||
commit(MutationTypes.addDefs, payload)
|
||||
},
|
||||
[ActionTypes.removeDefs]({ commit }, payload) {
|
||||
commit(MutationTypes.removeDefs, payload)
|
||||
},
|
||||
[ActionTypes.editDefs]({ commit }, payload) {
|
||||
commit(MutationTypes.editDefs, payload)
|
||||
},
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export type Getters<S = State> = {
|
||||
defs(state: S, key: string): any
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, RootState> & Getters = {
|
||||
defs: (state, key: string) => {
|
||||
return state.main.get(key)
|
||||
},
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import {
|
||||
Store as VuexStore,
|
||||
Module,
|
||||
CommitOptions,
|
||||
DispatchOptions,
|
||||
} from 'vuex'
|
||||
|
||||
import { getters, Getters } from './getters'
|
||||
import { mutations, Mutations, MutationTypes } from './mutations'
|
||||
import { actions, Actions, ActionTypes } from './actions'
|
||||
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
interface State {
|
||||
main: Map<string, any>
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
main: new Map(),
|
||||
}
|
||||
|
||||
const data_module: Module<State, RootState> = {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
}
|
||||
|
||||
export default data_module
|
||||
|
||||
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
|
||||
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
|
||||
key: K,
|
||||
payload: P,
|
||||
options?: CommitOptions
|
||||
): ReturnType<Mutations[K]>
|
||||
} & {
|
||||
getters: {
|
||||
[K in keyof Getters]: ReturnType<Getters[K]>
|
||||
}
|
||||
} & {
|
||||
dispatch<K extends keyof Actions>(
|
||||
key: K,
|
||||
payload: Parameters<Actions[K]>[1],
|
||||
options?: DispatchOptions
|
||||
): ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
export { State, ActionTypes, MutationTypes, Store }
|
@ -1,47 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
|
||||
export enum MutationTypes {
|
||||
addDefs = 'addDefs',
|
||||
removeDefs = 'removeDefs',
|
||||
editDefs = 'editDefs'
|
||||
}
|
||||
|
||||
interface DefsMap {
|
||||
key: string
|
||||
defs: any
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.addDefs](state: S, defs_map: DefsMap): void
|
||||
[MutationTypes.removeDefs](state: S, defs_map: DefsMap): void
|
||||
[MutationTypes.editDefs](state: S, defs_map: DefsMap, key: string): void
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
[MutationTypes.addDefs](state: State, defs_map: DefsMap) {
|
||||
if (defs_map.key && defs_map.defs)
|
||||
state.main.set(defs_map.key, defs_map.defs)
|
||||
},
|
||||
[MutationTypes.removeDefs](state: State, defs_map: DefsMap) {
|
||||
if (defs_map.key && defs_map.defs) {
|
||||
const defs = state.main.get(defs_map.key)
|
||||
defs.splice(defs.indexOf(defs_map.defs), 1)
|
||||
state.main.set(defs_map.key, defs)
|
||||
}
|
||||
},
|
||||
[MutationTypes.editDefs](state: State, defs_map: DefsMap) {
|
||||
if (defs_map.key && defs_map.defs) {
|
||||
const new_defs = [] as unknown as any
|
||||
const defs = state.main.get(defs_map.key)
|
||||
const key = defs_map.defs.id
|
||||
defs.forEach((it: any) => {
|
||||
if (it.id === key)
|
||||
new_defs.push(defs)
|
||||
else
|
||||
new_defs.push(it)
|
||||
})
|
||||
state.main.set(defs_map.key, new_defs)
|
||||
}
|
||||
},
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import data_module, { State as DataState, MutationTypes as DataMutationTypes, ActionTypes as DataActionTypes, Store as DataStore } from './data'
|
||||
import check_module, { State as CheckState, MutationTypes as CheckMutationTypes, ActionTypes as CheckActionTypes, Store as CheckStore } from './check'
|
||||
import defs_module, { State as DefsState, MutationTypes as DefsMutationTypes, ActionTypes as DefsActionTypes, Store as DefsStore } from './defs'
|
||||
import profile_module, { State as ProfileState, MutationTypes as ProfileMutationTypes, ActionTypes as ProfileActionTypes, Store as ProfileStore } from './profile'
|
||||
import lang_module, { State as LangState, MutationTypes as LangMutationTypes, ActionTypes as LangActionTypes, Store as LangStore } from './lang'
|
||||
|
||||
export const AppDataMutationTypes = DataMutationTypes
|
||||
export const AppCheckMutationTypes = CheckMutationTypes
|
||||
export const AppDefsMutationTypes = DefsMutationTypes
|
||||
export const AppProfileMutationTypes = ProfileMutationTypes
|
||||
export const AppLangMutationTypes = LangMutationTypes
|
||||
|
||||
export const AppDataActionTypes = DataActionTypes
|
||||
export const AppCheckActionTypes = CheckActionTypes
|
||||
export const AppDefsActionTypes = DefsActionTypes
|
||||
export const AppProfileActionTypes = ProfileActionTypes
|
||||
export const AppLangActionTypes = LangActionTypes
|
||||
|
||||
export type AppDataState= DataState
|
||||
export type AppCheckState= CheckState
|
||||
export type AppDefsState= DefsState
|
||||
export type AppProfileState= ProfileState
|
||||
export type AppLangState= LangState
|
||||
|
||||
export type AppDataStore = DataStore
|
||||
export type AppCheckStore = CheckStore
|
||||
export type AppDefsStore = DefsStore
|
||||
export type AppProfileStore = ProfileStore
|
||||
export type AppLangStore = LangStore
|
||||
|
||||
export const app_data = data_module
|
||||
export const app_check = check_module
|
||||
export const app_defs = defs_module
|
||||
export const app_profile = profile_module
|
||||
export const app_lang = lang_module
|
@ -1,68 +0,0 @@
|
||||
import { ActionContext, ActionTree } from 'vuex'
|
||||
import { Mutations, MutationTypes } from './mutations'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export enum ActionTypes {
|
||||
addLang = 'addLang',
|
||||
addLangMain = 'addLangMain',
|
||||
addLangData = 'addLangData',
|
||||
addLangForms = 'addLangForms',
|
||||
removeLang = 'removeLang',
|
||||
editLang = 'editLang'
|
||||
}
|
||||
|
||||
type AppLangActionContext = {
|
||||
commit<K extends keyof Mutations>(
|
||||
key: K,
|
||||
payload: Parameters<Mutations[K]>[1]
|
||||
): ReturnType<Mutations[K]>
|
||||
} & Omit<ActionContext<State, RootState>, 'commit'>
|
||||
|
||||
export interface Actions {
|
||||
[ActionTypes.addLang](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.addLangMain](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.addLangData](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.addLangForms](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.removeLang](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.editLang](
|
||||
{ commit }: AppLangActionContext,
|
||||
payload: any
|
||||
): void
|
||||
}
|
||||
|
||||
export const actions: ActionTree<State, RootState> & Actions = {
|
||||
[ActionTypes.addLang]({ commit }, payload) {
|
||||
commit(MutationTypes.addLang, payload)
|
||||
},
|
||||
[ActionTypes.addLangMain]({ commit }, payload) {
|
||||
commit(MutationTypes.addLangMain, payload)
|
||||
},
|
||||
[ActionTypes.addLangData]({ commit }, payload) {
|
||||
commit(MutationTypes.addLangData, payload)
|
||||
},
|
||||
[ActionTypes.addLangForms]({ commit }, payload) {
|
||||
commit(MutationTypes.addLangForms, payload)
|
||||
},
|
||||
[ActionTypes.removeLang]({ commit }, payload) {
|
||||
commit(MutationTypes.removeLang, payload)
|
||||
},
|
||||
[ActionTypes.editLang]({ commit }, payload) {
|
||||
commit(MutationTypes.editLang, payload)
|
||||
},
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export type Getters<S = State> = {
|
||||
lang(state: S, key: string): any
|
||||
langMain(state: S, key: string): any
|
||||
langData(state: S, key: string): any
|
||||
langForms(state: S, key: string): any
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, RootState> & Getters = {
|
||||
lang: (state: State, key: string) => {
|
||||
return state.lang.get(key)
|
||||
},
|
||||
langMain: (state: State, key: string) => {
|
||||
return state.lang.get(key)?.main || null
|
||||
},
|
||||
langData: (state: State, key: string) => {
|
||||
return state.lang.get(key)?.data || null
|
||||
},
|
||||
langForms: (state: State, key: string) => {
|
||||
return state.lang.get(key)?.forms || null
|
||||
},
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import {
|
||||
Store as VuexStore,
|
||||
Module,
|
||||
CommitOptions,
|
||||
DispatchOptions,
|
||||
} from 'vuex'
|
||||
|
||||
import { getters, Getters } from './getters'
|
||||
import { mutations, Mutations, MutationTypes } from './mutations'
|
||||
import { actions, Actions, ActionTypes } from './actions'
|
||||
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
import { AppLang } from '~/store/types'
|
||||
|
||||
interface State {
|
||||
lang: Map<string, AppLang>
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
lang: new Map(),
|
||||
}
|
||||
|
||||
const data_module: Module<State, RootState> = {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
}
|
||||
|
||||
export default data_module
|
||||
|
||||
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
|
||||
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
|
||||
key: K,
|
||||
payload: P,
|
||||
options?: CommitOptions
|
||||
): ReturnType<Mutations[K]>
|
||||
} & {
|
||||
getters: {
|
||||
[K in keyof Getters]: ReturnType<Getters[K]>
|
||||
}
|
||||
} & {
|
||||
dispatch<K extends keyof Actions>(
|
||||
key: K,
|
||||
payload: Parameters<Actions[K]>[1],
|
||||
options?: DispatchOptions
|
||||
): ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
export { State, ActionTypes, MutationTypes, Store }
|
@ -1,108 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { AppLang, AppCtxLang, LangMain, LangData, LangForms } from '~/store/types'
|
||||
|
||||
export enum MutationTypes {
|
||||
addLang = 'addLang',
|
||||
addLangMain = 'addLangMain',
|
||||
addLangData = 'addLangData',
|
||||
addLangForms = 'addLangForms',
|
||||
removeLang = 'removeLang',
|
||||
editLang = 'editLang'
|
||||
}
|
||||
interface LangMap {
|
||||
key: string
|
||||
lang: AppLang
|
||||
}
|
||||
interface LangSection {
|
||||
key: string
|
||||
section: any
|
||||
}
|
||||
interface CtxLangMap {
|
||||
key: string
|
||||
lang: AppCtxLang
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.addLang](state: S, lang_map: LangMap): void
|
||||
[MutationTypes.addLangMain](state: S, lang_map: LangSection): void
|
||||
[MutationTypes.addLangData](state: S, lang_map: LangSection): void
|
||||
[MutationTypes.addLangForms](state: S, lang_map: LangSection): void
|
||||
[MutationTypes.removeLang](state: S, lang_map: CtxLangMap): void
|
||||
[MutationTypes.editLang](state: S, lang_map: CtxLangMap): void
|
||||
}
|
||||
|
||||
const get_lang_map = (state: State, mapkey: string): AppLang => {
|
||||
const lng = state.lang.get(mapkey)
|
||||
return lng || { main: {}, data: {}, forms: {} }
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
[MutationTypes.addLang](state: State, lang_map: LangMap) {
|
||||
state.lang.set(lang_map.key, lang_map.lang)
|
||||
},
|
||||
[MutationTypes.addLangMain](state, lang_map: LangSection) {
|
||||
const lng = get_lang_map(state, lang_map.key)
|
||||
lng.main = lang_map.section
|
||||
state.lang.set(lang_map.key, lng)
|
||||
},
|
||||
[MutationTypes.addLangData](state, lang_map: LangSection) {
|
||||
const lng = get_lang_map(state, lang_map.key)
|
||||
lng.data = lang_map.section
|
||||
state.lang.set(lang_map.key, lng)
|
||||
},
|
||||
[MutationTypes.addLangForms](state, lang_map: LangSection) {
|
||||
const lng = get_lang_map(state, lang_map.key)
|
||||
lng.data = lang_map.section
|
||||
state.lang.set(lang_map.key, lng)
|
||||
},
|
||||
[MutationTypes.removeLang](state: State, lang_map: CtxLangMap) {
|
||||
const lang = get_lang_map(state, lang_map.key)
|
||||
const key = lang_map.lang.lng.key
|
||||
switch (lang_map.lang.ctx) {
|
||||
case 'main':
|
||||
if (lang.main[key]) {
|
||||
delete lang.main[key]
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
case 'data':
|
||||
if (lang.data[key]) {
|
||||
delete lang.data[key]
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
case 'forms':
|
||||
if (lang.forms[key]) {
|
||||
delete lang.forms[key]
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
}
|
||||
},
|
||||
[MutationTypes.editLang](state: State, lang_map: CtxLangMap) {
|
||||
const lang = get_lang_map(state, lang_map.key)
|
||||
const key = lang_map.lang.lng.key
|
||||
const val = lang_map.lang.lng.text
|
||||
switch (lang_map.lang.ctx) {
|
||||
case 'main':
|
||||
if (lang.main[key]) {
|
||||
lang.main[key] = val
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
case 'data':
|
||||
if (lang.data[key]) {
|
||||
lang.data[key] = val
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
case 'forms':
|
||||
if (lang.forms[key]) {
|
||||
lang.forms[key] = val
|
||||
state.lang.set(lang_map.key, lang)
|
||||
}
|
||||
break
|
||||
}
|
||||
},
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { ActionContext, ActionTree } from 'vuex'
|
||||
import { Mutations, MutationTypes } from './mutations'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export enum ActionTypes {
|
||||
addProfile = 'addProfile',
|
||||
removeProfile = 'removeProfile',
|
||||
editProfile = 'editProfile'
|
||||
}
|
||||
|
||||
type AppProfileActionContext = {
|
||||
commit<K extends keyof Mutations>(
|
||||
key: K,
|
||||
payload: Parameters<Mutations[K]>[1]
|
||||
): ReturnType<Mutations[K]>
|
||||
} & Omit<ActionContext<State, RootState>, 'commit'>
|
||||
|
||||
export interface Actions {
|
||||
[ActionTypes.addProfile](
|
||||
{ commit }: AppProfileActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.removeProfile](
|
||||
{ commit }: AppProfileActionContext,
|
||||
payload: any
|
||||
): void
|
||||
[ActionTypes.editProfile](
|
||||
{ commit }: AppProfileActionContext,
|
||||
payload: any
|
||||
): void
|
||||
}
|
||||
|
||||
export const actions: ActionTree<State, RootState> & Actions = {
|
||||
[ActionTypes.addProfile]({ commit }, payload) {
|
||||
commit(MutationTypes.addProfile, payload)
|
||||
},
|
||||
[ActionTypes.removeProfile]({ commit }, payload) {
|
||||
commit(MutationTypes.removeProfile, payload)
|
||||
},
|
||||
[ActionTypes.editProfile]({ commit }, payload) {
|
||||
commit(MutationTypes.editProfile, payload)
|
||||
},
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
export type Getters<S = State> = {
|
||||
profile(state: S): any
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, RootState> & Getters = {
|
||||
profile: (state: State) => {
|
||||
return state.profile
|
||||
},
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import {
|
||||
Store as VuexStore,
|
||||
Module,
|
||||
CommitOptions,
|
||||
DispatchOptions,
|
||||
} from 'vuex'
|
||||
|
||||
import { getters, Getters } from './getters'
|
||||
import { mutations, Mutations, MutationTypes } from './mutations'
|
||||
import { actions, Actions, ActionTypes } from './actions'
|
||||
|
||||
import { RootState } from '~/store/index'
|
||||
|
||||
interface State {
|
||||
profile: any
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
profile: {},
|
||||
}
|
||||
|
||||
const data_module: Module<State, RootState> = {
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
}
|
||||
|
||||
export default data_module
|
||||
|
||||
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
|
||||
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
|
||||
key: K,
|
||||
payload: P,
|
||||
options?: CommitOptions
|
||||
): ReturnType<Mutations[K]>
|
||||
} & {
|
||||
getters: {
|
||||
[K in keyof Getters]: ReturnType<Getters[K]>
|
||||
}
|
||||
} & {
|
||||
dispatch<K extends keyof Actions>(
|
||||
key: K,
|
||||
payload: Parameters<Actions[K]>[1],
|
||||
options?: DispatchOptions
|
||||
): ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
export { State, ActionTypes, MutationTypes, Store }
|
@ -1,37 +0,0 @@
|
||||
import { MutationTree } from 'vuex'
|
||||
import { State } from './index'
|
||||
|
||||
export enum MutationTypes {
|
||||
addProfile = 'addProfile',
|
||||
removeProfile = 'removeProfile',
|
||||
editProfile = 'editProfile'
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.addProfile](state: S, profile: any): void
|
||||
[MutationTypes.removeProfile](state: S, target: any): void
|
||||
[MutationTypes.editProfile](state: S, target: any, key: string): void
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
[MutationTypes.addProfile](state: State, profile: any) {
|
||||
state.profile = profile
|
||||
},
|
||||
[MutationTypes.removeProfile](state: State, target: any) {
|
||||
const profile = state.profile as any
|
||||
const key = target.key
|
||||
if (profile[key]) {
|
||||
delete profile[key]
|
||||
state.profile = profile
|
||||
}
|
||||
},
|
||||
[MutationTypes.editProfile](state: State, target: any) {
|
||||
const profile = state.profile as any
|
||||
const key = target.key
|
||||
const data = target.data
|
||||
if (profile[key]) {
|
||||
profile[key] = data
|
||||
state.profile = profile
|
||||
}
|
||||
},
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './app'
|
@ -1,97 +0,0 @@
|
||||
import { useStore, Store } from 'vuex'
|
||||
|
||||
interface InternalModule<S, A, M, G> {
|
||||
state: S
|
||||
actions: A
|
||||
mutations: M
|
||||
getters: G
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows us to access the internal vuex properties and
|
||||
* maps them in a way which removes the module prefix.
|
||||
*/
|
||||
function getFromStoreByType<T>(
|
||||
moduleName: string,
|
||||
type: unknown,
|
||||
isNamespaced: boolean,
|
||||
) {
|
||||
if (isNamespaced) {
|
||||
return Object.keys(type)
|
||||
.filter(t => t.startsWith(`${moduleName}/`))
|
||||
.reduce((acc, curr) => {
|
||||
const typeName = curr.split('/').pop()
|
||||
const typeValue = type[curr][0]
|
||||
|
||||
return { [typeName]: typeValue, ...acc }
|
||||
}, {}) as T
|
||||
}
|
||||
|
||||
return Object.keys(type).reduce((acc, curr) => {
|
||||
const typeValue = type[curr][0]
|
||||
|
||||
return { [curr]: typeValue, ...acc }
|
||||
}, {}) as T
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to wrap the getters in a Proxy because we only want to
|
||||
* "access" the getter if it actually being accessed.
|
||||
*
|
||||
* We could technically use the getFromStoreByType function but
|
||||
* the getter would be invoked multiple types on store instantiation.
|
||||
*
|
||||
* This is just a little cheeky workaround. Proxy <3
|
||||
*/
|
||||
function wrapGettersInProxy<G>(
|
||||
moduleName: string,
|
||||
getters: G,
|
||||
isNamespaced: boolean,
|
||||
) {
|
||||
return new Proxy(getters as Object, {
|
||||
get(_, prop: string) {
|
||||
if (isNamespaced)
|
||||
return getters[`${moduleName}/${prop}`]
|
||||
|
||||
return getters[prop]
|
||||
},
|
||||
}) as G
|
||||
}
|
||||
|
||||
function isModuleNamespaced<S>(moduleName: string, store: Store<S>): boolean {
|
||||
// @ts-ignore internal Vuex object that isn't typed.
|
||||
return Boolean(store._modulesNamespaceMap[`${moduleName}/`])
|
||||
}
|
||||
|
||||
export default function useStoreModule<S = any, A = any, M = any, G = any>(
|
||||
moduleName: string,
|
||||
storeName?: string,
|
||||
): InternalModule<S, A, M, G> {
|
||||
// @ts-ignore useStore doesn't yet accept a key as arg
|
||||
const store = storeName ? useStore(storeName) : useStore()
|
||||
const state = store.state[moduleName]
|
||||
const isNamespaced = isModuleNamespaced(moduleName, store)
|
||||
|
||||
const actions = getFromStoreByType<A>(
|
||||
moduleName,
|
||||
// @ts-ignore internal Vuex object that isn't typed.
|
||||
store._actions,
|
||||
isNamespaced,
|
||||
)
|
||||
|
||||
const mutations = getFromStoreByType<M>(
|
||||
moduleName,
|
||||
// @ts-ignore internal Vuex object that isn't typed.
|
||||
store._mutations,
|
||||
isNamespaced,
|
||||
)
|
||||
|
||||
const getters = wrapGettersInProxy<G>(moduleName, store.getters, isNamespaced)
|
||||
|
||||
return {
|
||||
actions,
|
||||
mutations,
|
||||
state,
|
||||
getters,
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
import {
|
||||
AppDataMutationTypes,
|
||||
AppDataActionTypes,
|
||||
AppCheckMutationTypes,
|
||||
AppCheckActionTypes,
|
||||
AppDefsMutationTypes,
|
||||
AppDefsActionTypes,
|
||||
AppProfileMutationTypes,
|
||||
AppProfileActionTypes,
|
||||
AppLangMutationTypes,
|
||||
AppLangActionTypes,
|
||||
} from './modules/app/index'
|
||||
|
||||
export const AppDataMutation = AppDataMutationTypes
|
||||
export const AppDataAction = AppDataActionTypes
|
||||
export const AppCheckMutation = AppCheckMutationTypes
|
||||
export const AppCheckAction = AppCheckActionTypes
|
||||
export const AppDefsMutation = AppDefsMutationTypes
|
||||
export const AppDefsAction = AppDefsActionTypes
|
||||
export const AppProfileMutation = AppProfileMutationTypes
|
||||
export const AppProfileAction = AppProfileActionTypes
|
||||
export const AppLangMutation = AppLangMutationTypes
|
||||
export const AppLangAction = AppLangActionTypes
|
||||
|
||||
export interface LangCtxKey {
|
||||
ctx: string
|
||||
key: string
|
||||
}
|
||||
|
||||
export interface LangItem {
|
||||
key: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface LangMain {
|
||||
[key: string]: string
|
||||
}
|
||||
export interface LangData {
|
||||
[key: string]: string
|
||||
}
|
||||
export interface LangForms {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface AppLang {
|
||||
main: LangMain
|
||||
data: LangData
|
||||
forms: LangForms
|
||||
}
|
||||
|
||||
export interface AppCtxLang {
|
||||
ctx: string
|
||||
lng: LangItem
|
||||
}
|
||||
export interface AppDefs {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface AppProfile {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface AppData {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface AppCheck {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
/*
|
||||
export interface AppStore {
|
||||
defs: AppDefs
|
||||
profile: AppProfile
|
||||
data: [AppData]
|
||||
lang: AppLang
|
||||
}
|
||||
*/
|
@ -1,43 +0,0 @@
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
background: #121212;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
margin: 2em;
|
||||
}
|
||||
.markdown-body p {
|
||||
margin-top: 1em;;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
padding: 2em;
|
||||
background: rgba(243,244,246);
|
||||
}
|
||||
.dark .markdown-body pre {
|
||||
background: rgba(75, 85, 99,var(--tw-bg-opacity))
|
||||
}
|
||||
.markdown-body a {
|
||||
color: rgba(37, 99, 235);
|
||||
}
|
||||
.btn {
|
||||
@apply px-4 py-1 rounded inline-block
|
||||
bg-teal-600 text-white cursor-pointer
|
||||
hover:bg-teal-700
|
||||
disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
@apply inline-block cursor-pointer select-none
|
||||
opacity-75 transition duration-200 ease-in-out
|
||||
hover:opacity-100 hover:text-teal-600;
|
||||
font-size: 0.9em;
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
export const enum LanguageType {
|
||||
en = 'en',
|
||||
es = 'es',
|
||||
None = 'None',
|
||||
}
|
||||
export interface StatusItemType {
|
||||
title: string
|
||||
content: string
|
||||
lang: LanguageType
|
||||
datetime: string
|
||||
isOpen: boolean
|
||||
}
|
||||
export interface StatusItemDataType {
|
||||
[key: string]: any
|
||||
title: string
|
||||
content: string
|
||||
lang: LanguageType
|
||||
datetime: string
|
||||
}
|
||||
export const enum ReqType {
|
||||
tcp = 'tcp',
|
||||
https = 'https',
|
||||
NotSet = 'NotSet',
|
||||
}
|
||||
export const enum CriticalType {
|
||||
yes = 'yes',
|
||||
cloud = 'cloud',
|
||||
group = 'group',
|
||||
ifresized = 'ifresized',
|
||||
no = 'no',
|
||||
}
|
||||
export interface SrvcType {
|
||||
name: string
|
||||
path: string
|
||||
req: ReqType
|
||||
target: string
|
||||
liveness: string
|
||||
critical: CriticalType
|
||||
}
|
||||
export interface SrvcInfoType {
|
||||
[key: string]: any
|
||||
name: string
|
||||
info: string
|
||||
srvc: SrvcType
|
||||
}
|
||||
export interface CloudGroupItemType {
|
||||
[key: string]: any
|
||||
hostname: string
|
||||
tsksrvcs: SrvcType[]
|
||||
appsrvcs: SrvcType[]
|
||||
}
|
||||
export interface CloudGroupServcType {
|
||||
[key: string]: any
|
||||
hostname: string
|
||||
name: string
|
||||
tsksrvcs: SrvcInfoElemType[]
|
||||
appsrvcs: SrvcInfoElemType[]
|
||||
}
|
||||
|
||||
export interface CloudDataCheck {
|
||||
[key: string]: any
|
||||
name: string
|
||||
apps: Map<string, Map<string, CloudGroupServcType>>
|
||||
cloud: Map<string, Map<string, CloudGroupServcType>>
|
||||
infos: StatusItemType[]
|
||||
}
|
||||
export interface CloudOptionType {
|
||||
name: string
|
||||
option: number
|
||||
}
|
||||
export interface CloudGroupDataType {
|
||||
[key: string]: CloudGroupItemType[] | any
|
||||
}
|
||||
export interface ResCloudDataCheck {
|
||||
[key: string]: any
|
||||
name: string
|
||||
cloud: CloudGroupDataType
|
||||
apps: CloudGroupDataType
|
||||
// cloud: CloudGroupSrvcType
|
||||
// statusentries: StatusItemDataType[]
|
||||
}
|
||||
export interface ResCloudDataCheckDefs {
|
||||
[key: string]: any
|
||||
check: ResCloudDataCheck[]
|
||||
defs: any
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
export enum MessageType {
|
||||
Show,
|
||||
Success,
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
}
|
||||
export interface MenuItemType {
|
||||
id: string
|
||||
title: string
|
||||
active: boolean
|
||||
link: string
|
||||
}
|
||||
|
||||
export enum NavItemType {
|
||||
router_link = 'router_link',
|
||||
app_link = 'app_link',
|
||||
a_blank = 'a_blank',
|
||||
a_link = 'a_link',
|
||||
cloud_link = 'cloud_link',
|
||||
module_label = 'module_label',
|
||||
separator = 'separator',
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="px-4 py-10 text-center text-teal-700 dark:text-gray-200">
|
||||
<div>
|
||||
<p class="text-4xl">
|
||||
<carbon-warning class="inline-block" />
|
||||
</p>
|
||||
</div>
|
||||
<router-view />
|
||||
<div>
|
||||
<button
|
||||
class="btn m-3 text-sm mt-8"
|
||||
@click="router.back()"
|
||||
>
|
||||
{{ t('button.back') }}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
@ -1,21 +0,0 @@
|
||||
---
|
||||
title: About
|
||||
---
|
||||
|
||||
<div class="text-center">
|
||||
<!-- You can use Vue components inside markdown -->
|
||||
<carbon-dicom-overlay class="text-4xl mb-6 m-auto" />
|
||||
<h3>About</h3>
|
||||
</div>
|
||||
|
||||
[Vitesse](https://github.com/antfu/vitesse) is an opinionated [Vite](https://github.com/vitejs/vite) starter template made by [@antfu](https://github.com/antfu) for mocking apps swiftly. With **file-based routing**, **components auto importing**, **markdown support**, I18n, PWA and uses **Tailwind** v2 for UI.
|
||||
|
||||
```js
|
||||
// syntax highlighting example
|
||||
function vitesse() {
|
||||
const foo = 'bar'
|
||||
console.log(foo)
|
||||
}
|
||||
```
|
||||
|
||||
heck out the [GitHub repo](https://github.com/antfu/vitesse) for more details.
|
@ -1,329 +0,0 @@
|
||||
<template>
|
||||
<NavMenu v-if="use_nav" :usetitle="false" :title="title" navtitle="" :items="navMenuItems" @on-nav-menu="onNavMenu">
|
||||
<template #opslist v-if="clds_groups.length > 0 ">
|
||||
<li class="mr-3">
|
||||
<select id="cld-select" class="rounded-xl bg-light-300 form-select p-2 mt-1 block w-full ddark:hover:bg-gray-800 ddark:bg-gray-500 ddark:text-gray-200 bg-gray-200 text-gray-800" @change="update_cloud_selection">
|
||||
<option
|
||||
v-for="(cld, index) in clouds_options"
|
||||
:key="index"
|
||||
class="bg-gray-200 text-gray-800 appearance-none border-none inline-block py-3 pl-3 pr-8 rounded leading-tight ddark:hover:bg-gray-800 ddark:bg-gray-500 ddark:text-gray-200"
|
||||
:selected="cld_sel_idx === index"
|
||||
>
|
||||
{{ cld.name }}
|
||||
</option>
|
||||
</select>
|
||||
</li>
|
||||
</template>
|
||||
<template #search v-if="(cld_selected.cloud && cld_selected.cloud.size > 0 ) || cld_selected.apps && cld_selected.apps.size > 0">
|
||||
<input id="search" v-model="search" class="rounded-l-full w-full py-2 px-2 text-gray-700 leading-tight focus:outline-none" type="text" :placeholder="t('nav.Search','Search')">
|
||||
<div class="p-1">
|
||||
<button
|
||||
class="bg-blue-500 text-white rounded-full p-2 hover:bg-blue-400 focus:outline-none flex items-center justify-center"
|
||||
@click="on_search"
|
||||
>
|
||||
<span class="text-xs">
|
||||
<carbon-search class="align-bottom" />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template #lastitems>
|
||||
<li class="mr-3">
|
||||
<MenuLocales :label-mode="localesLabelMode" :include-current="includeCurrLocale" />
|
||||
</li>
|
||||
</template>
|
||||
</NavMenu>
|
||||
<Profile v-if="show_profile" />
|
||||
<div id="tophome">
|
||||
<div v-if="cld_selected.cloud && cld_selected.cloud.size > 0" class="-mt-2 text-gray-800 lg:p-1">
|
||||
<CloudGroups
|
||||
:title="t('nav.Tasks','Services')"
|
||||
target="tsksrvcs"
|
||||
:groups="cld_selected.cloud"
|
||||
:search="search"
|
||||
:hide="tasks_hide"
|
||||
@on-cloud-group="onCloudGroup"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="cld_selected.apps && cld_selected.apps.size > 0" class="mt-1 text-gray-800 p-2 lg:p-4">
|
||||
<CloudGroups
|
||||
:title="t('nav.Apps','Apps')"
|
||||
target="appsrvcs"
|
||||
:groups="cld_selected.apps"
|
||||
:search="search"
|
||||
:hide="apps_hide"
|
||||
@on-cloud-group="onCloudGroup"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="cld_selected.infos && cld_selected.infos.length > 0" class="shadow-lg mx-auto bg-gray-100 text-gray-800 mt-4 md:mt-2 bg-light-800 dark:bg-gray-600 w-full p-2 rounded-l">
|
||||
<Infos :items="cld_selected.infos" :title="t('nav.Informations','Informations')"
|
||||
@on-cloud-info-item="onCloudInfoItem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import CloudGroups from '~/components/CloudGroups.vue'
|
||||
// import ProfileView from '~/components/ProfileView.vue'
|
||||
import NavMenu from '~/components/NavMenu.vue'
|
||||
import Infos from '~/views/Infos.vue'
|
||||
import Profile from '~/components/Profile.vue'
|
||||
import { load_data } from '~/hooks/utils'
|
||||
// import { translate, show_message } from '~/hooks/utils'
|
||||
import useState from '~/hooks/useState'
|
||||
import { StatusItemType, StatusItemDataType, ResCloudDataCheckDefs, CloudGroupServcType, CloudDataCheck,CloudOptionType } from '~/typs/clouds'
|
||||
import { SideMenuItemType } from '~/typs/cmpnts'
|
||||
import MenuLocales from '@/menus/MenuLocales.vue'
|
||||
import { AppDefsAction } from '~/store/types'
|
||||
// import { AppDataAction, AppCheckAction, AppDefsAction } from '~/store/types'
|
||||
|
||||
enum LocalesLabelModes {
|
||||
value = 'val',
|
||||
translation = 'trans',
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const map_key = router.currentRoute.value.meta.mapkey as string || 'ui'
|
||||
const use_nav = router.currentRoute.value.meta.useNav as boolean
|
||||
const ctx = router.currentRoute.value.meta.ctx || ''
|
||||
const localesLabelMode = ref(LocalesLabelModes.translation)
|
||||
const includeCurrLocale = true
|
||||
|
||||
const store = useStore()
|
||||
const { t } = useI18n()
|
||||
const title = ref('Services Status')
|
||||
const search = useState().search
|
||||
// const router = useRouter()
|
||||
// const go = () => {
|
||||
// if (name.value)
|
||||
// router.push(`/hi/${encodeURIComponent(name.value)}`)
|
||||
// }
|
||||
const show_profile = computed(() => useState().show_profile.value)
|
||||
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
|
||||
|
||||
const menu_items = computed((): SideMenuItemType[] => {
|
||||
const defsMenuItems = defs.value && defs.value.sidebar && defs.value.sidebar.menu_items ? defs.value.sidebar.menu_items : [] as SideMenuItemType[]
|
||||
const all_items = [].concat(defsMenuItems || []) // .concat(useState().sidebarMenuItems.value as SideMenuItemType[] | any)
|
||||
useState().sidebarMenuItems.value = all_items.filter((itm: SideMenuItemType) => {
|
||||
if (itm.ctx && itm.ctx === ctx) {
|
||||
return true
|
||||
} else if (itm.ctx && itm.ctx !== ctx) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
return useState().sidebarMenuItems.value
|
||||
})
|
||||
const navMenuItems = computed(() => {
|
||||
const menu_items_active = menu_items.value.filter(menuitem => {
|
||||
switch (menuitem.click) {
|
||||
case 'tsksrvcs':
|
||||
return cld_selected.value.cloud && cld_selected.value.cloud.size > 0
|
||||
break
|
||||
case 'appsrvcs':
|
||||
return cld_selected.value.apps && cld_selected.value.apps.size > 0
|
||||
break
|
||||
case 'srvcstatus':
|
||||
return cld_selected.value.infos && cld_selected.value.infos.length > 0
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
return menu_items_active
|
||||
})
|
||||
const on_search = () => {
|
||||
}
|
||||
const tasks_hide = ref(false)
|
||||
const apps_hide = ref(false)
|
||||
const onCloudGroup = (target: string) => {
|
||||
if (target) {
|
||||
switch (target) {
|
||||
case useState().tsksrvcs:
|
||||
tasks_hide.value = !tasks_hide.value
|
||||
break
|
||||
case useState().appsrvcs:
|
||||
apps_hide.value = !apps_hide.value
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
const onAppHome = () => {
|
||||
const dom_id = document.getElementById('tophome')
|
||||
if (dom_id) {
|
||||
dom_id.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
|
||||
setTimeout(() => window.scrollBy(0, -40), 1000)
|
||||
}
|
||||
}
|
||||
useState().app_home_click.value = onAppHome
|
||||
useState().backdrop_blur.value = 2
|
||||
useState().back_opacity.value = 100
|
||||
useState().panels.value.search = { style: 'h-auto'}
|
||||
|
||||
const onNavMenu = (item: SideMenuItemType) => {
|
||||
if (item) {
|
||||
const dom_id = document.getElementById(item.click as string)
|
||||
if (dom_id) {
|
||||
dom_id.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
|
||||
setTimeout(() => window.scrollBy(0, -40), 1000)
|
||||
}
|
||||
// const new_defs = JSON.parse(JSON.stringify(store.state.app_defs.main.get(map_key)))
|
||||
// new_defs.sidebar.menu_items = menu_items.value.map(i => ({ ...i, active: i.click !== item.click? false : !i.active }))
|
||||
// store.dispatch(AppDefsAction.addDefs, new_defs)
|
||||
switch (item.click) {
|
||||
case useState().tsksrvcs:
|
||||
tasks_hide.value = false
|
||||
break
|
||||
case useState().appsrvcs:
|
||||
apps_hide.value = false
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
useState().side_menu_click.value = onNavMenu
|
||||
const cld_default_name = 'ma'
|
||||
const clds_groups = ref([] as CloudDataCheck[])
|
||||
const cld_sel_idx= ref(0)
|
||||
const cld_selected = ref({} as CloudDataCheck)
|
||||
|
||||
const clouds_options = computed(() => {
|
||||
const options = [] as CloudOptionType[]
|
||||
clds_groups.value.forEach((it,idx) => {
|
||||
options.push({
|
||||
name: it.name,
|
||||
option: idx,
|
||||
})
|
||||
})
|
||||
return options
|
||||
})
|
||||
const update_cloud_selection = (e: any) => {
|
||||
if (clds_groups.value[e.target.selectedIndex]) {
|
||||
cld_sel_idx.value=e.target.selectedIndex
|
||||
cld_selected.value = clds_groups.value[cld_sel_idx.value]
|
||||
}
|
||||
}
|
||||
const onCloudInfoItem = (item: StatusItemType) => {
|
||||
if (item) {
|
||||
clds_groups.value[cld_sel_idx.value].infos = clds_groups.value[cld_sel_idx.value].infos.map((i: StatusItemType) => ({
|
||||
...i, isOpen: i.title === item.title && i.datetime === item.datetime ? !i.isOpen : false
|
||||
}))
|
||||
cld_selected.value = clds_groups.value[cld_sel_idx.value]
|
||||
}
|
||||
}
|
||||
const sortInfos = (data: StatusItemType[], rev: boolean): StatusItemType[] => {
|
||||
const mapped = data.map(function(el, i) {
|
||||
return { index: i, value: parseInt(el.datetime.replaceAll(' ','').replaceAll('/','').replaceAll(':',''),0) || 0 };
|
||||
})
|
||||
mapped.sort(function(a, b) {
|
||||
if (a.value > b.value) {
|
||||
return rev ? -1 : 1;
|
||||
}
|
||||
if (a.value < b.value) {
|
||||
return rev ? 1 : -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
const result = mapped.map(function(el){
|
||||
return data[el.index];
|
||||
});
|
||||
return result
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
useState().sidebarMenuItems.value = useState().sidebarMenuItems.value.filter((itm: SideMenuItemType) => {
|
||||
if (itm.ctx && itm.ctx === ctx) {
|
||||
return false
|
||||
} else if (itm.ctx && itm.ctx !== ctx) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
useState().side_menu_click.value = () => router.push('/')
|
||||
useState().app_home_click.value = () => router.push('/')
|
||||
})
|
||||
onMounted(async() => {
|
||||
// await nextTick()
|
||||
const use_local = false
|
||||
let url = 'groups.json'
|
||||
const rooturl = window.ROOT_LOCATION || location.origin
|
||||
if (!use_local)
|
||||
url = `${rooturl}/info`
|
||||
|
||||
clds_groups.value = [] as CloudDataCheck[]
|
||||
await load_data(url, 0, 2000, (res: ResCloudDataCheckDefs) => {
|
||||
// use Map to keep objects order
|
||||
// use Object.keys + sort to map same result order
|
||||
const clouds_groups = [] as CloudDataCheck[]
|
||||
res.check.forEach((kld,kldidx) => {
|
||||
if (kld.name === cld_default_name)
|
||||
cld_sel_idx.value=kldidx
|
||||
const check_data: Map<string, Map<string, CloudGroupServcType>> = new Map()
|
||||
clouds_groups[kldidx] = {} as CloudDataCheck
|
||||
Object.keys(kld.apps).sort().forEach((grp_key) => {
|
||||
const data: Map<string, CloudGroupServcType> = new Map()
|
||||
Object.keys(kld.apps[grp_key]).sort().forEach((key) => {
|
||||
const grp_res: CloudGroupServcType[] = kld.apps[grp_key][key].filter((it:CloudGroupServcType) => it.tsksrvcs.length > 0 || it.appsrvcs.length > 0)
|
||||
if (grp_res.length > 0)
|
||||
data.set(key, kld.apps[grp_key][key])
|
||||
})
|
||||
if (data.size > 0)
|
||||
check_data.set(grp_key, data)
|
||||
})
|
||||
clouds_groups[kldidx] = {
|
||||
name: kld.name,
|
||||
apps: check_data,
|
||||
cloud: kld.cloud ? new Map() : check_data,
|
||||
infos: [] as StatusItemType[],
|
||||
}
|
||||
if (kld.cloud) {
|
||||
Object.keys(kld.cloud).sort().forEach((grp_key) => {
|
||||
Object.keys(kld.cloud[grp_key]).sort().forEach((key) => {
|
||||
const data: CloudGroupServcType[] = kld.cloud[grp_key][key]
|
||||
data.forEach((it, index) => {
|
||||
if (clouds_groups[kldidx].apps.get(grp_key)) {
|
||||
const m = clouds_groups[kldidx].apps.get(grp_key)
|
||||
if (m && m.size > 0 && m.get(key) && it.tsksrvcs) {
|
||||
const m_data = m.get(key)
|
||||
if (m_data && m_data[index]) {
|
||||
m_data[index].tsksrvcs = it.tsksrvcs
|
||||
const new_data: Map<string, CloudGroupServcType> = new Map()
|
||||
new_data.set(key, m_data)
|
||||
clouds_groups[kldidx].cloud.set(grp_key, new_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
let infos: StatusItemType[] = []
|
||||
if (kld.infos) {
|
||||
kld.infos.forEach((it: StatusItemDataType) => {
|
||||
infos.push({ ...it, isOpen: false })
|
||||
})
|
||||
infos = sortInfos(infos,true)
|
||||
}
|
||||
clouds_groups[kldidx].infos = infos
|
||||
})
|
||||
clds_groups.value = clouds_groups
|
||||
cld_selected.value = clds_groups.value[cld_sel_idx.value]
|
||||
if (res.defs) {
|
||||
store.dispatch(AppDefsAction.addDefs, { key: map_key, defs: res.defs })
|
||||
}
|
||||
useState().sidebarMenuItems.value = res.defs.sidebar.menu_items.filter((itm: SideMenuItemType) => {
|
||||
if (itm.ctx && itm.ctx === ctx) {
|
||||
return true
|
||||
} else if (itm.ctx && itm.ctx !== ctx) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user