Initial commit
35
README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# vue
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur).
|
||||||
|
|
||||||
|
## Type Support for `.vue` Imports in TS
|
||||||
|
|
||||||
|
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates.
|
||||||
|
|
||||||
|
However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can run `Volar: Switch TS Plugin on/off` from VS Code command palette.
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type-Check, Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
717
auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,717 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
const $api: typeof import('./src/utils/api')['$api']
|
||||||
|
const COOKIE_MAX_AGE_1_YEAR: typeof import('./src/utils/constants')['COOKIE_MAX_AGE_1_YEAR']
|
||||||
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||||
|
const alphaDashValidator: typeof import('./src/@core/utils/validators')['alphaDashValidator']
|
||||||
|
const alphaValidator: typeof import('./src/@core/utils/validators')['alphaValidator']
|
||||||
|
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||||
|
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||||
|
const avatarText: typeof import('./src/@core/utils/formatters')['avatarText']
|
||||||
|
const betweenValidator: typeof import('./src/@core/utils/validators')['betweenValidator']
|
||||||
|
const computed: typeof import('vue')['computed']
|
||||||
|
const computedAsync: typeof import('@vueuse/core')['computedAsync']
|
||||||
|
const computedEager: typeof import('@vueuse/core')['computedEager']
|
||||||
|
const computedInject: typeof import('@vueuse/core')['computedInject']
|
||||||
|
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
|
||||||
|
const confirmedValidator: typeof import('./src/@core/utils/validators')['confirmedValidator']
|
||||||
|
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 createGenericProjection: typeof import('@vueuse/math')['createGenericProjection']
|
||||||
|
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||||
|
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
|
||||||
|
const createPinia: typeof import('pinia')['createPinia']
|
||||||
|
const createProjection: typeof import('@vueuse/math')['createProjection']
|
||||||
|
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
|
||||||
|
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
|
||||||
|
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
|
||||||
|
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
|
||||||
|
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
|
||||||
|
const createUrl: typeof import('./src/@core/composable/createUrl')['createUrl']
|
||||||
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
|
||||||
|
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
|
||||||
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
|
const defineLoader: typeof import('vue-router/auto')['defineLoader']
|
||||||
|
const definePage: typeof import('unplugin-vue-router/runtime')['definePage']
|
||||||
|
const defineStore: typeof import('pinia')['defineStore']
|
||||||
|
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||||
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
|
const emailValidator: typeof import('./src/@core/utils/validators')['emailValidator']
|
||||||
|
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||||
|
const formatDate: typeof import('./src/@core/utils/formatters')['formatDate']
|
||||||
|
const formatDateToMonthShort: typeof import('./src/@core/utils/formatters')['formatDateToMonthShort']
|
||||||
|
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||||
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
|
const h: typeof import('vue')['h']
|
||||||
|
const hexToRgb: typeof import('./src/@core/utils/colorConverter')['hexToRgb']
|
||||||
|
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||||
|
const inject: typeof import('vue')['inject']
|
||||||
|
const injectLocal: typeof import('@vueuse/core')['injectLocal']
|
||||||
|
const integerValidator: typeof import('./src/@core/utils/validators')['integerValidator']
|
||||||
|
const isDefined: typeof import('@vueuse/core')['isDefined']
|
||||||
|
const isEmpty: typeof import('./src/@core/utils/helpers')['isEmpty']
|
||||||
|
const isEmptyArray: typeof import('./src/@core/utils/helpers')['isEmptyArray']
|
||||||
|
const isNullOrUndefined: typeof import('./src/@core/utils/helpers')['isNullOrUndefined']
|
||||||
|
const isObject: typeof import('./src/@core/utils/helpers')['isObject']
|
||||||
|
const isProxy: typeof import('vue')['isProxy']
|
||||||
|
const isReactive: typeof import('vue')['isReactive']
|
||||||
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
|
const isRef: typeof import('vue')['isRef']
|
||||||
|
const isToday: typeof import('./src/@core/utils/helpers')['isToday']
|
||||||
|
const kFormatter: typeof import('./src/@core/utils/formatters')['kFormatter']
|
||||||
|
const lengthValidator: typeof import('./src/@core/utils/validators')['lengthValidator']
|
||||||
|
const logicAnd: typeof import('@vueuse/math')['logicAnd']
|
||||||
|
const logicNot: typeof import('@vueuse/math')['logicNot']
|
||||||
|
const logicOr: typeof import('@vueuse/math')['logicOr']
|
||||||
|
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
|
||||||
|
const mapActions: typeof import('pinia')['mapActions']
|
||||||
|
const mapGetters: typeof import('pinia')['mapGetters']
|
||||||
|
const mapState: typeof import('pinia')['mapState']
|
||||||
|
const mapStores: typeof import('pinia')['mapStores']
|
||||||
|
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||||
|
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 onBeforeRouteLeave: typeof import('vue-router/auto')['onBeforeRouteLeave']
|
||||||
|
const onBeforeRouteUpdate: typeof import('vue-router/auto')['onBeforeRouteUpdate']
|
||||||
|
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 onLongPress: typeof import('@vueuse/core')['onLongPress']
|
||||||
|
const onMounted: typeof import('vue')['onMounted']
|
||||||
|
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||||
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||||
|
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||||
|
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 onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||||
|
const paginationMeta: typeof import('./src/utils/paginationMeta')['paginationMeta']
|
||||||
|
const passwordValidator: typeof import('./src/@core/utils/validators')['passwordValidator']
|
||||||
|
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
||||||
|
const prefixWithPlus: typeof import('./src/@core/utils/formatters')['prefixWithPlus']
|
||||||
|
const provide: typeof import('vue')['provide']
|
||||||
|
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
||||||
|
const reactify: typeof import('@vueuse/core')['reactify']
|
||||||
|
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
||||||
|
const reactive: typeof import('vue')['reactive']
|
||||||
|
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
|
||||||
|
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
|
||||||
|
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
||||||
|
const readonly: typeof import('vue')['readonly']
|
||||||
|
const ref: typeof import('vue')['ref']
|
||||||
|
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
|
||||||
|
const refDebounced: typeof import('@vueuse/core')['refDebounced']
|
||||||
|
const refDefault: typeof import('@vueuse/core')['refDefault']
|
||||||
|
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
||||||
|
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
||||||
|
const regexValidator: typeof import('./src/@core/utils/validators')['regexValidator']
|
||||||
|
const registerPlugins: typeof import('./src/@core/utils/plugins')['registerPlugins']
|
||||||
|
const requiredValidator: typeof import('./src/@core/utils/validators')['requiredValidator']
|
||||||
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
|
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
||||||
|
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||||
|
const resolveVuetifyTheme: typeof import('./src/@core/utils/vuetify')['resolveVuetifyTheme']
|
||||||
|
const rgbaToHex: typeof import('./src/@core/utils/colorConverter')['rgbaToHex']
|
||||||
|
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||||
|
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
||||||
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
|
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||||
|
const syncRef: typeof import('@vueuse/core')['syncRef']
|
||||||
|
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
||||||
|
const templateRef: typeof import('@vueuse/core')['templateRef']
|
||||||
|
const throttledRef: typeof import('@vueuse/core')['throttledRef']
|
||||||
|
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 toValue: typeof import('vue')['toValue']
|
||||||
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
|
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
|
||||||
|
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 urlValidator: typeof import('./src/@core/utils/validators')['urlValidator']
|
||||||
|
const useAbility: typeof import('./src/plugins/casl/composables/useAbility')['useAbility']
|
||||||
|
const useAbs: typeof import('@vueuse/math')['useAbs']
|
||||||
|
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||||
|
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||||
|
const useApi: typeof import('./src/composables/useApi')['useApi']
|
||||||
|
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
|
||||||
|
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
|
||||||
|
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
|
||||||
|
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
|
||||||
|
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
|
||||||
|
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
|
||||||
|
const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
|
||||||
|
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
|
||||||
|
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
|
||||||
|
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
|
||||||
|
const useArraySome: typeof import('@vueuse/core')['useArraySome']
|
||||||
|
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
|
||||||
|
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
||||||
|
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||||
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
|
const useAverage: typeof import('@vueuse/math')['useAverage']
|
||||||
|
const useBase64: typeof import('@vueuse/core')['useBase64']
|
||||||
|
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||||
|
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
||||||
|
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
|
||||||
|
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
|
||||||
|
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
||||||
|
const useCached: typeof import('@vueuse/core')['useCached']
|
||||||
|
const useCeil: typeof import('@vueuse/math')['useCeil']
|
||||||
|
const useClamp: typeof import('@vueuse/math')['useClamp']
|
||||||
|
const useClipboard: typeof import('@vueuse/core')['useClipboard']
|
||||||
|
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
|
||||||
|
const useCloned: typeof import('@vueuse/core')['useCloned']
|
||||||
|
const useColorMode: typeof import('@vueuse/core')['useColorMode']
|
||||||
|
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
|
||||||
|
const useCookie: typeof import('./src/@core/composable/useCookie')['useCookie']
|
||||||
|
const useCounter: typeof import('@vueuse/core')['useCounter']
|
||||||
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
|
const useCssVar: typeof import('@vueuse/core')['useCssVar']
|
||||||
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
|
||||||
|
const useCycleList: typeof import('@vueuse/core')['useCycleList']
|
||||||
|
const useDark: typeof import('@vueuse/core')['useDark']
|
||||||
|
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
|
||||||
|
const useDebounce: typeof import('@vueuse/core')['useDebounce']
|
||||||
|
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
|
||||||
|
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
|
||||||
|
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 useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
|
||||||
|
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
|
||||||
|
const useDraggable: typeof import('@vueuse/core')['useDraggable']
|
||||||
|
const useDropZone: typeof import('@vueuse/core')['useDropZone']
|
||||||
|
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
|
||||||
|
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
|
||||||
|
const useElementHover: typeof import('@vueuse/core')['useElementHover']
|
||||||
|
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 useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
|
||||||
|
const useFavicon: typeof import('@vueuse/core')['useFavicon']
|
||||||
|
const useFetch: typeof import('@vueuse/core')['useFetch']
|
||||||
|
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
|
||||||
|
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
|
||||||
|
const useFloor: typeof import('@vueuse/math')['useFloor']
|
||||||
|
const useFocus: typeof import('@vueuse/core')['useFocus']
|
||||||
|
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
||||||
|
const useFps: typeof import('@vueuse/core')['useFps']
|
||||||
|
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
||||||
|
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
||||||
|
const useGenerateImageVariant: typeof import('./src/@core/composable/useGenerateImageVariant')['useGenerateImageVariant']
|
||||||
|
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
||||||
|
const useI18n: typeof import('vue-i18n')['useI18n']
|
||||||
|
const useId: typeof import('vue')['useId']
|
||||||
|
const useIdle: typeof import('@vueuse/core')['useIdle']
|
||||||
|
const useImage: typeof import('@vueuse/core')['useImage']
|
||||||
|
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
|
||||||
|
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 useMath: typeof import('@vueuse/math')['useMath']
|
||||||
|
const useMax: typeof import('@vueuse/math')['useMax']
|
||||||
|
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
|
||||||
|
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
||||||
|
const useMemoize: typeof import('@vueuse/core')['useMemoize']
|
||||||
|
const useMemory: typeof import('@vueuse/core')['useMemory']
|
||||||
|
const useMin: typeof import('@vueuse/math')['useMin']
|
||||||
|
const useModel: typeof import('vue')['useModel']
|
||||||
|
const useMounted: typeof import('@vueuse/core')['useMounted']
|
||||||
|
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 useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
|
||||||
|
const useNetwork: typeof import('@vueuse/core')['useNetwork']
|
||||||
|
const useNow: typeof import('@vueuse/core')['useNow']
|
||||||
|
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
|
||||||
|
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
|
||||||
|
const useOnline: typeof import('@vueuse/core')['useOnline']
|
||||||
|
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
|
||||||
|
const useParallax: typeof import('@vueuse/core')['useParallax']
|
||||||
|
const useParentElement: typeof import('@vueuse/core')['useParentElement']
|
||||||
|
const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
|
||||||
|
const usePermission: typeof import('@vueuse/core')['usePermission']
|
||||||
|
const usePointer: typeof import('@vueuse/core')['usePointer']
|
||||||
|
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
|
||||||
|
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
|
||||||
|
const usePrecision: typeof import('@vueuse/math')['usePrecision']
|
||||||
|
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
|
||||||
|
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
|
||||||
|
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
|
||||||
|
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
|
||||||
|
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
|
||||||
|
const usePrevious: typeof import('@vueuse/core')['usePrevious']
|
||||||
|
const useProjection: typeof import('@vueuse/math')['useProjection']
|
||||||
|
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
||||||
|
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
||||||
|
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
||||||
|
const useResponsiveLeftSidebar: typeof import('./src/@core/composable/useResponsiveSidebar')['useResponsiveLeftSidebar']
|
||||||
|
const useRound: typeof import('@vueuse/math')['useRound']
|
||||||
|
const useRoute: typeof import('vue-router/auto')['useRoute']
|
||||||
|
const useRouter: typeof import('vue-router/auto')['useRouter']
|
||||||
|
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
||||||
|
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
||||||
|
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
||||||
|
const useScroll: typeof import('@vueuse/core')['useScroll']
|
||||||
|
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
|
||||||
|
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
|
||||||
|
const useShare: typeof import('@vueuse/core')['useShare']
|
||||||
|
const useSkins: typeof import('./src/@core/composable/useSkins')['useSkins']
|
||||||
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
|
const useSorted: typeof import('@vueuse/core')['useSorted']
|
||||||
|
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
|
||||||
|
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
|
||||||
|
const useStepper: typeof import('@vueuse/core')['useStepper']
|
||||||
|
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
|
||||||
|
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
|
||||||
|
const useSum: typeof import('@vueuse/math')['useSum']
|
||||||
|
const useSupported: typeof import('@vueuse/core')['useSupported']
|
||||||
|
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
||||||
|
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||||
|
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
||||||
|
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
|
||||||
|
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
|
||||||
|
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
|
||||||
|
const useThrottle: typeof import('@vueuse/core')['useThrottle']
|
||||||
|
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
||||||
|
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
||||||
|
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
||||||
|
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
||||||
|
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
||||||
|
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
|
||||||
|
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
|
||||||
|
const useTitle: typeof import('@vueuse/core')['useTitle']
|
||||||
|
const useToNumber: typeof import('@vueuse/core')['useToNumber']
|
||||||
|
const useToString: typeof import('@vueuse/core')['useToString']
|
||||||
|
const useToggle: typeof import('@vueuse/core')['useToggle']
|
||||||
|
const useTransition: typeof import('@vueuse/core')['useTransition']
|
||||||
|
const useTrunc: typeof import('@vueuse/math')['useTrunc']
|
||||||
|
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
|
||||||
|
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
|
||||||
|
const useVModel: typeof import('@vueuse/core')['useVModel']
|
||||||
|
const useVModels: typeof import('@vueuse/core')['useVModels']
|
||||||
|
const useVibrate: typeof import('@vueuse/core')['useVibrate']
|
||||||
|
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
|
||||||
|
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
|
||||||
|
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
|
||||||
|
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 watchArray: typeof import('@vueuse/core')['watchArray']
|
||||||
|
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
|
||||||
|
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
|
||||||
|
const watchDeep: typeof import('@vueuse/core')['watchDeep']
|
||||||
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
|
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
|
||||||
|
const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
|
||||||
|
const watchOnce: typeof import('@vueuse/core')['watchOnce']
|
||||||
|
const watchPausable: typeof import('@vueuse/core')['watchPausable']
|
||||||
|
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||||
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||||
|
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
|
||||||
|
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
||||||
|
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||||
|
const whenever: typeof import('@vueuse/core')['whenever']
|
||||||
|
}
|
||||||
|
// for type re-export
|
||||||
|
declare global {
|
||||||
|
// @ts-ignore
|
||||||
|
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||||
|
import('vue')
|
||||||
|
}
|
||||||
|
|
||||||
|
// for vue template auto import
|
||||||
|
import { UnwrapRef } from 'vue'
|
||||||
|
declare module 'vue' {
|
||||||
|
interface GlobalComponents {}
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
readonly $api: UnwrapRef<typeof import('./src/utils/api')['$api']>
|
||||||
|
readonly COOKIE_MAX_AGE_1_YEAR: UnwrapRef<typeof import('./src/utils/constants')['COOKIE_MAX_AGE_1_YEAR']>
|
||||||
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||||
|
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||||
|
readonly alphaDashValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['alphaDashValidator']>
|
||||||
|
readonly alphaValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['alphaValidator']>
|
||||||
|
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||||
|
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||||
|
readonly avatarText: UnwrapRef<typeof import('./src/@core/utils/formatters')['avatarText']>
|
||||||
|
readonly betweenValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['betweenValidator']>
|
||||||
|
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||||
|
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
|
||||||
|
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>
|
||||||
|
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']>
|
||||||
|
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']>
|
||||||
|
readonly confirmedValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['confirmedValidator']>
|
||||||
|
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
|
||||||
|
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
|
||||||
|
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||||
|
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
|
||||||
|
readonly createGenericProjection: UnwrapRef<typeof import('@vueuse/math')['createGenericProjection']>
|
||||||
|
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']>
|
||||||
|
readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']>
|
||||||
|
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
|
||||||
|
readonly createProjection: UnwrapRef<typeof import('@vueuse/math')['createProjection']>
|
||||||
|
readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']>
|
||||||
|
readonly createReusableTemplate: UnwrapRef<typeof import('@vueuse/core')['createReusableTemplate']>
|
||||||
|
readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']>
|
||||||
|
readonly createTemplatePromise: UnwrapRef<typeof import('@vueuse/core')['createTemplatePromise']>
|
||||||
|
readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']>
|
||||||
|
readonly createUrl: UnwrapRef<typeof import('./src/@core/composable/createUrl')['createUrl']>
|
||||||
|
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||||
|
readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']>
|
||||||
|
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
||||||
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||||
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||||
|
readonly definePage: UnwrapRef<typeof import('unplugin-vue-router/runtime')['definePage']>
|
||||||
|
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||||
|
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
||||||
|
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||||
|
readonly emailValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['emailValidator']>
|
||||||
|
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
|
||||||
|
readonly formatDate: UnwrapRef<typeof import('./src/@core/utils/formatters')['formatDate']>
|
||||||
|
readonly formatDateToMonthShort: UnwrapRef<typeof import('./src/@core/utils/formatters')['formatDateToMonthShort']>
|
||||||
|
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
|
||||||
|
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||||
|
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||||
|
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||||
|
readonly hexToRgb: UnwrapRef<typeof import('./src/@core/utils/colorConverter')['hexToRgb']>
|
||||||
|
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
|
||||||
|
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||||
|
readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
|
||||||
|
readonly integerValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['integerValidator']>
|
||||||
|
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
|
||||||
|
readonly isEmpty: UnwrapRef<typeof import('./src/@core/utils/helpers')['isEmpty']>
|
||||||
|
readonly isEmptyArray: UnwrapRef<typeof import('./src/@core/utils/helpers')['isEmptyArray']>
|
||||||
|
readonly isNullOrUndefined: UnwrapRef<typeof import('./src/@core/utils/helpers')['isNullOrUndefined']>
|
||||||
|
readonly isObject: UnwrapRef<typeof import('./src/@core/utils/helpers')['isObject']>
|
||||||
|
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||||
|
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||||
|
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||||
|
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||||
|
readonly isToday: UnwrapRef<typeof import('./src/@core/utils/helpers')['isToday']>
|
||||||
|
readonly kFormatter: UnwrapRef<typeof import('./src/@core/utils/formatters')['kFormatter']>
|
||||||
|
readonly lengthValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['lengthValidator']>
|
||||||
|
readonly logicAnd: UnwrapRef<typeof import('@vueuse/math')['logicAnd']>
|
||||||
|
readonly logicNot: UnwrapRef<typeof import('@vueuse/math')['logicNot']>
|
||||||
|
readonly logicOr: UnwrapRef<typeof import('@vueuse/math')['logicOr']>
|
||||||
|
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
|
||||||
|
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||||
|
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||||
|
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||||
|
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
|
||||||
|
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
|
||||||
|
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||||
|
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||||
|
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||||
|
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||||
|
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router/auto')['onBeforeRouteLeave']>
|
||||||
|
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router/auto')['onBeforeRouteUpdate']>
|
||||||
|
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||||
|
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||||
|
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']>
|
||||||
|
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||||
|
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||||
|
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']>
|
||||||
|
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']>
|
||||||
|
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||||
|
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||||
|
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||||
|
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||||
|
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||||
|
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']>
|
||||||
|
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||||
|
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||||
|
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
||||||
|
readonly paginationMeta: UnwrapRef<typeof import('./src/utils/paginationMeta')['paginationMeta']>
|
||||||
|
readonly passwordValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['passwordValidator']>
|
||||||
|
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
||||||
|
readonly prefixWithPlus: UnwrapRef<typeof import('./src/@core/utils/formatters')['prefixWithPlus']>
|
||||||
|
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||||
|
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
||||||
|
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
|
||||||
|
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
|
||||||
|
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||||
|
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']>
|
||||||
|
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']>
|
||||||
|
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']>
|
||||||
|
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||||
|
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||||
|
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']>
|
||||||
|
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']>
|
||||||
|
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']>
|
||||||
|
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']>
|
||||||
|
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']>
|
||||||
|
readonly regexValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['regexValidator']>
|
||||||
|
readonly registerPlugins: UnwrapRef<typeof import('./src/@core/utils/plugins')['registerPlugins']>
|
||||||
|
readonly requiredValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['requiredValidator']>
|
||||||
|
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||||
|
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
|
||||||
|
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
|
||||||
|
readonly resolveVuetifyTheme: UnwrapRef<typeof import('./src/@core/utils/vuetify')['resolveVuetifyTheme']>
|
||||||
|
readonly rgbaToHex: UnwrapRef<typeof import('./src/@core/utils/colorConverter')['rgbaToHex']>
|
||||||
|
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
|
||||||
|
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
|
||||||
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||||
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||||
|
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||||
|
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||||
|
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
||||||
|
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
||||||
|
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
|
||||||
|
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']>
|
||||||
|
readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']>
|
||||||
|
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||||
|
readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']>
|
||||||
|
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||||
|
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||||
|
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||||
|
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||||
|
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
|
||||||
|
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
|
||||||
|
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']>
|
||||||
|
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']>
|
||||||
|
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']>
|
||||||
|
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||||
|
readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']>
|
||||||
|
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
|
||||||
|
readonly urlValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['urlValidator']>
|
||||||
|
readonly useAbs: UnwrapRef<typeof import('@vueuse/math')['useAbs']>
|
||||||
|
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
|
||||||
|
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
|
||||||
|
readonly useApi: UnwrapRef<typeof import('./src/composables/useApi')['useApi']>
|
||||||
|
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
|
||||||
|
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
|
||||||
|
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
|
||||||
|
readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']>
|
||||||
|
readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']>
|
||||||
|
readonly useArrayFindLast: UnwrapRef<typeof import('@vueuse/core')['useArrayFindLast']>
|
||||||
|
readonly useArrayIncludes: UnwrapRef<typeof import('@vueuse/core')['useArrayIncludes']>
|
||||||
|
readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']>
|
||||||
|
readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']>
|
||||||
|
readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']>
|
||||||
|
readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']>
|
||||||
|
readonly useArrayUnique: UnwrapRef<typeof import('@vueuse/core')['useArrayUnique']>
|
||||||
|
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']>
|
||||||
|
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']>
|
||||||
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||||
|
readonly useAverage: UnwrapRef<typeof import('@vueuse/math')['useAverage']>
|
||||||
|
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
|
||||||
|
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
|
||||||
|
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
|
||||||
|
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
|
||||||
|
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
|
||||||
|
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
|
||||||
|
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
|
||||||
|
readonly useCeil: UnwrapRef<typeof import('@vueuse/math')['useCeil']>
|
||||||
|
readonly useClamp: UnwrapRef<typeof import('@vueuse/math')['useClamp']>
|
||||||
|
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
|
||||||
|
readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
|
||||||
|
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
|
||||||
|
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
|
||||||
|
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
|
||||||
|
readonly useCookie: UnwrapRef<typeof import('./src/@core/composable/useCookie')['useCookie']>
|
||||||
|
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
|
||||||
|
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||||
|
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
|
||||||
|
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||||
|
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']>
|
||||||
|
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']>
|
||||||
|
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']>
|
||||||
|
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']>
|
||||||
|
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']>
|
||||||
|
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']>
|
||||||
|
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']>
|
||||||
|
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']>
|
||||||
|
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']>
|
||||||
|
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']>
|
||||||
|
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']>
|
||||||
|
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']>
|
||||||
|
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']>
|
||||||
|
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']>
|
||||||
|
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']>
|
||||||
|
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']>
|
||||||
|
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']>
|
||||||
|
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
|
||||||
|
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
|
||||||
|
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
|
||||||
|
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
|
||||||
|
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
|
||||||
|
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
|
||||||
|
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']>
|
||||||
|
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']>
|
||||||
|
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']>
|
||||||
|
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']>
|
||||||
|
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']>
|
||||||
|
readonly useFloor: UnwrapRef<typeof import('@vueuse/math')['useFloor']>
|
||||||
|
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']>
|
||||||
|
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']>
|
||||||
|
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']>
|
||||||
|
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
|
||||||
|
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
|
||||||
|
readonly useGenerateImageVariant: UnwrapRef<typeof import('./src/@core/composable/useGenerateImageVariant')['useGenerateImageVariant']>
|
||||||
|
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
|
||||||
|
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']>
|
||||||
|
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||||
|
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
|
||||||
|
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
|
||||||
|
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
|
||||||
|
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']>
|
||||||
|
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']>
|
||||||
|
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
|
||||||
|
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
|
||||||
|
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
|
||||||
|
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
|
||||||
|
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
|
||||||
|
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']>
|
||||||
|
readonly useMath: UnwrapRef<typeof import('@vueuse/math')['useMath']>
|
||||||
|
readonly useMax: UnwrapRef<typeof import('@vueuse/math')['useMax']>
|
||||||
|
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']>
|
||||||
|
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']>
|
||||||
|
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
|
||||||
|
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
|
||||||
|
readonly useMin: UnwrapRef<typeof import('@vueuse/math')['useMin']>
|
||||||
|
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
|
||||||
|
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
|
||||||
|
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
|
||||||
|
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
|
||||||
|
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']>
|
||||||
|
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']>
|
||||||
|
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']>
|
||||||
|
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']>
|
||||||
|
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']>
|
||||||
|
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']>
|
||||||
|
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']>
|
||||||
|
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']>
|
||||||
|
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']>
|
||||||
|
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']>
|
||||||
|
readonly useParentElement: UnwrapRef<typeof import('@vueuse/core')['useParentElement']>
|
||||||
|
readonly usePerformanceObserver: UnwrapRef<typeof import('@vueuse/core')['usePerformanceObserver']>
|
||||||
|
readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']>
|
||||||
|
readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']>
|
||||||
|
readonly usePointerLock: UnwrapRef<typeof import('@vueuse/core')['usePointerLock']>
|
||||||
|
readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']>
|
||||||
|
readonly usePrecision: UnwrapRef<typeof import('@vueuse/math')['usePrecision']>
|
||||||
|
readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']>
|
||||||
|
readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']>
|
||||||
|
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']>
|
||||||
|
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']>
|
||||||
|
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']>
|
||||||
|
readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']>
|
||||||
|
readonly useProjection: UnwrapRef<typeof import('@vueuse/math')['useProjection']>
|
||||||
|
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
|
||||||
|
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
|
||||||
|
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
|
||||||
|
readonly useResponsiveLeftSidebar: UnwrapRef<typeof import('./src/@core/composable/useResponsiveSidebar')['useResponsiveLeftSidebar']>
|
||||||
|
readonly useRound: UnwrapRef<typeof import('@vueuse/math')['useRound']>
|
||||||
|
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
|
||||||
|
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
|
||||||
|
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
||||||
|
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
||||||
|
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
|
||||||
|
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']>
|
||||||
|
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']>
|
||||||
|
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']>
|
||||||
|
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']>
|
||||||
|
readonly useSkins: UnwrapRef<typeof import('./src/@core/composable/useSkins')['useSkins']>
|
||||||
|
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||||
|
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']>
|
||||||
|
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']>
|
||||||
|
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']>
|
||||||
|
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']>
|
||||||
|
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']>
|
||||||
|
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']>
|
||||||
|
readonly useSum: UnwrapRef<typeof import('@vueuse/math')['useSum']>
|
||||||
|
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']>
|
||||||
|
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
|
||||||
|
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
||||||
|
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']>
|
||||||
|
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']>
|
||||||
|
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']>
|
||||||
|
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']>
|
||||||
|
readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']>
|
||||||
|
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
|
||||||
|
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
|
||||||
|
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']>
|
||||||
|
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']>
|
||||||
|
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
|
||||||
|
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']>
|
||||||
|
readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']>
|
||||||
|
readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']>
|
||||||
|
readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']>
|
||||||
|
readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']>
|
||||||
|
readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']>
|
||||||
|
readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']>
|
||||||
|
readonly useTrunc: UnwrapRef<typeof import('@vueuse/math')['useTrunc']>
|
||||||
|
readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']>
|
||||||
|
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']>
|
||||||
|
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']>
|
||||||
|
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']>
|
||||||
|
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']>
|
||||||
|
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']>
|
||||||
|
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']>
|
||||||
|
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']>
|
||||||
|
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']>
|
||||||
|
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']>
|
||||||
|
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']>
|
||||||
|
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']>
|
||||||
|
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']>
|
||||||
|
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']>
|
||||||
|
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||||
|
readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']>
|
||||||
|
readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']>
|
||||||
|
readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']>
|
||||||
|
readonly watchDeep: UnwrapRef<typeof import('@vueuse/core')['watchDeep']>
|
||||||
|
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||||
|
readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']>
|
||||||
|
readonly watchImmediate: UnwrapRef<typeof import('@vueuse/core')['watchImmediate']>
|
||||||
|
readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']>
|
||||||
|
readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']>
|
||||||
|
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||||
|
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||||
|
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']>
|
||||||
|
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']>
|
||||||
|
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']>
|
||||||
|
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']>
|
||||||
|
}
|
||||||
|
}
|
||||||
384
components.d.ts
vendored
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
AddAuthenticatorAppDialog: typeof import('./src/components/dialogs/AddAuthenticatorAppDialog.vue')['default']
|
||||||
|
AddEditAddressDialog: typeof import('./src/components/dialogs/AddEditAddressDialog.vue')['default']
|
||||||
|
AddEditPermissionDialog: typeof import('./src/components/dialogs/AddEditPermissionDialog.vue')['default']
|
||||||
|
AddEditRoleDialog: typeof import('./src/components/dialogs/AddEditRoleDialog.vue')['default']
|
||||||
|
AddPaymentMethodDialog: typeof import('./src/components/dialogs/AddPaymentMethodDialog.vue')['default']
|
||||||
|
AppBarSearch: typeof import('./src/@core/components/AppBarSearch.vue')['default']
|
||||||
|
AppCardActions: typeof import('./src/@core/components/cards/AppCardActions.vue')['default']
|
||||||
|
AppCardCode: typeof import('./src/@core/components/cards/AppCardCode.vue')['default']
|
||||||
|
AppDateTimePicker: typeof import('./src/@core/components/app-form-elements/AppDateTimePicker.vue')['default']
|
||||||
|
AppDrawerHeaderSection: typeof import('./src/@core/components/AppDrawerHeaderSection.vue')['default']
|
||||||
|
AppLoadingIndicator: typeof import('./src/components/AppLoadingIndicator.vue')['default']
|
||||||
|
AppPricing: typeof import('./src/components/AppPricing.vue')['default']
|
||||||
|
AppSearchHeader: typeof import('./src/components/AppSearchHeader.vue')['default']
|
||||||
|
AppStepper: typeof import('./src/@core/components/AppStepper.vue')['default']
|
||||||
|
BuyNow: typeof import('./src/@core/components/BuyNow.vue')['default']
|
||||||
|
CardAddEditDialog: typeof import('./src/components/dialogs/CardAddEditDialog.vue')['default']
|
||||||
|
CardStatisticsHorizontal: typeof import('./src/@core/components/cards/CardStatisticsHorizontal.vue')['default']
|
||||||
|
CardStatisticsVertical: typeof import('./src/@core/components/cards/CardStatisticsVertical.vue')['default']
|
||||||
|
CardStatisticsWithIcon: typeof import('./src/@core/components/cards/CardStatisticsWithIcon.vue')['default']
|
||||||
|
CardStatisticsWithImages: typeof import('./src/@core/components/cards/CardStatisticsWithImages.vue')['default']
|
||||||
|
ConfirmDialog: typeof import('./src/components/dialogs/ConfirmDialog.vue')['default']
|
||||||
|
CreateAppDialog: typeof import('./src/components/dialogs/CreateAppDialog.vue')['default']
|
||||||
|
CustomCheckboxes: typeof import('./src/@core/components/app-form-elements/CustomCheckboxes.vue')['default']
|
||||||
|
CustomCheckboxesWithIcon: typeof import('./src/@core/components/app-form-elements/CustomCheckboxesWithIcon.vue')['default']
|
||||||
|
CustomCheckboxesWithImage: typeof import('./src/@core/components/app-form-elements/CustomCheckboxesWithImage.vue')['default']
|
||||||
|
CustomizerSection: typeof import('./src/@core/components/CustomizerSection.vue')['default']
|
||||||
|
CustomRadios: typeof import('./src/@core/components/app-form-elements/CustomRadios.vue')['default']
|
||||||
|
CustomRadiosWithIcon: typeof import('./src/@core/components/app-form-elements/CustomRadiosWithIcon.vue')['default']
|
||||||
|
CustomRadiosWithImage: typeof import('./src/@core/components/app-form-elements/CustomRadiosWithImage.vue')['default']
|
||||||
|
DemoAlertBasic: typeof import('./src/views/demos/components/alert/DemoAlertBasic.vue')['default']
|
||||||
|
DemoAlertBorder: typeof import('./src/views/demos/components/alert/DemoAlertBorder.vue')['default']
|
||||||
|
DemoAlertClosable: typeof import('./src/views/demos/components/alert/DemoAlertClosable.vue')['default']
|
||||||
|
DemoAlertColoredBorder: typeof import('./src/views/demos/components/alert/DemoAlertColoredBorder.vue')['default']
|
||||||
|
DemoAlertColors: typeof import('./src/views/demos/components/alert/DemoAlertColors.vue')['default']
|
||||||
|
DemoAlertDensity: typeof import('./src/views/demos/components/alert/DemoAlertDensity.vue')['default']
|
||||||
|
DemoAlertElevation: typeof import('./src/views/demos/components/alert/DemoAlertElevation.vue')['default']
|
||||||
|
DemoAlertIcons: typeof import('./src/views/demos/components/alert/DemoAlertIcons.vue')['default']
|
||||||
|
DemoAlertOutlined: typeof import('./src/views/demos/components/alert/DemoAlertOutlined.vue')['default']
|
||||||
|
DemoAlertProminent: typeof import('./src/views/demos/components/alert/DemoAlertProminent.vue')['default']
|
||||||
|
DemoAlertTonal: typeof import('./src/views/demos/components/alert/DemoAlertTonal.vue')['default']
|
||||||
|
DemoAlertType: typeof import('./src/views/demos/components/alert/DemoAlertType.vue')['default']
|
||||||
|
DemoAlertVModelSupport: typeof import('./src/views/demos/components/alert/DemoAlertVModelSupport.vue')['default']
|
||||||
|
DemoAutocompleteAsyncItems: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteAsyncItems.vue')['default']
|
||||||
|
DemoAutocompleteBasic: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteBasic.vue')['default']
|
||||||
|
DemoAutocompleteChips: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteChips.vue')['default']
|
||||||
|
DemoAutocompleteClearable: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteClearable.vue')['default']
|
||||||
|
DemoAutocompleteCustomFilter: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteCustomFilter.vue')['default']
|
||||||
|
DemoAutocompleteDensity: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteDensity.vue')['default']
|
||||||
|
DemoAutocompleteMultiple: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteMultiple.vue')['default']
|
||||||
|
DemoAutocompleteSlots: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteSlots.vue')['default']
|
||||||
|
DemoAutocompleteStateSelector: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteStateSelector.vue')['default']
|
||||||
|
DemoAutocompleteValidation: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteValidation.vue')['default']
|
||||||
|
DemoAutocompleteVariant: typeof import('./src/views/demos/forms/form-elements/autocomplete/DemoAutocompleteVariant.vue')['default']
|
||||||
|
DemoAvatarColors: typeof import('./src/views/demos/components/avatar/DemoAvatarColors.vue')['default']
|
||||||
|
DemoAvatarGroup: typeof import('./src/views/demos/components/avatar/DemoAvatarGroup.vue')['default']
|
||||||
|
DemoAvatarIcons: typeof import('./src/views/demos/components/avatar/DemoAvatarIcons.vue')['default']
|
||||||
|
DemoAvatarImages: typeof import('./src/views/demos/components/avatar/DemoAvatarImages.vue')['default']
|
||||||
|
DemoAvatarRounded: typeof import('./src/views/demos/components/avatar/DemoAvatarRounded.vue')['default']
|
||||||
|
DemoAvatarSizes: typeof import('./src/views/demos/components/avatar/DemoAvatarSizes.vue')['default']
|
||||||
|
DemoAvatarTonal: typeof import('./src/views/demos/components/avatar/DemoAvatarTonal.vue')['default']
|
||||||
|
DemoBadgeAvatarStatus: typeof import('./src/views/demos/components/badge/DemoBadgeAvatarStatus.vue')['default']
|
||||||
|
DemoBadgeColor: typeof import('./src/views/demos/components/badge/DemoBadgeColor.vue')['default']
|
||||||
|
DemoBadgeDynamicNotifications: typeof import('./src/views/demos/components/badge/DemoBadgeDynamicNotifications.vue')['default']
|
||||||
|
DemoBadgeIcon: typeof import('./src/views/demos/components/badge/DemoBadgeIcon.vue')['default']
|
||||||
|
DemoBadgeMaximumValue: typeof import('./src/views/demos/components/badge/DemoBadgeMaximumValue.vue')['default']
|
||||||
|
DemoBadgePosition: typeof import('./src/views/demos/components/badge/DemoBadgePosition.vue')['default']
|
||||||
|
DemoBadgeShowOnHover: typeof import('./src/views/demos/components/badge/DemoBadgeShowOnHover.vue')['default']
|
||||||
|
DemoBadgeStyle: typeof import('./src/views/demos/components/badge/DemoBadgeStyle.vue')['default']
|
||||||
|
DemoBadgeTabs: typeof import('./src/views/demos/components/badge/DemoBadgeTabs.vue')['default']
|
||||||
|
DemoBadgeTonal: typeof import('./src/views/demos/components/badge/DemoBadgeTonal.vue')['default']
|
||||||
|
DemoButtonBlock: typeof import('./src/views/demos/components/button/DemoButtonBlock.vue')['default']
|
||||||
|
DemoButtonColors: typeof import('./src/views/demos/components/button/DemoButtonColors.vue')['default']
|
||||||
|
DemoButtonFlat: typeof import('./src/views/demos/components/button/DemoButtonFlat.vue')['default']
|
||||||
|
DemoButtonGroup: typeof import('./src/views/demos/components/button/DemoButtonGroup.vue')['default']
|
||||||
|
DemoButtonIcon: typeof import('./src/views/demos/components/button/DemoButtonIcon.vue')['default']
|
||||||
|
DemoButtonIconOnly: typeof import('./src/views/demos/components/button/DemoButtonIconOnly.vue')['default']
|
||||||
|
DemoButtonLink: typeof import('./src/views/demos/components/button/DemoButtonLink.vue')['default']
|
||||||
|
DemoButtonLoaders: typeof import('./src/views/demos/components/button/DemoButtonLoaders.vue')['default']
|
||||||
|
DemoButtonOutlined: typeof import('./src/views/demos/components/button/DemoButtonOutlined.vue')['default']
|
||||||
|
DemoButtonPlain: typeof import('./src/views/demos/components/button/DemoButtonPlain.vue')['default']
|
||||||
|
DemoButtonRounded: typeof import('./src/views/demos/components/button/DemoButtonRounded.vue')['default']
|
||||||
|
DemoButtonRouter: typeof import('./src/views/demos/components/button/DemoButtonRouter.vue')['default']
|
||||||
|
DemoButtonSizing: typeof import('./src/views/demos/components/button/DemoButtonSizing.vue')['default']
|
||||||
|
DemoButtonText: typeof import('./src/views/demos/components/button/DemoButtonText.vue')['default']
|
||||||
|
DemoButtonTonal: typeof import('./src/views/demos/components/button/DemoButtonTonal.vue')['default']
|
||||||
|
DemoCheckboxBasic: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxBasic.vue')['default']
|
||||||
|
DemoCheckboxCheckboxValue: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxCheckboxValue.vue')['default']
|
||||||
|
DemoCheckboxColors: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxColors.vue')['default']
|
||||||
|
DemoCheckboxDensity: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxDensity.vue')['default']
|
||||||
|
DemoCheckboxIcon: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxIcon.vue')['default']
|
||||||
|
DemoCheckboxInlineTextField: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxInlineTextField.vue')['default']
|
||||||
|
DemoCheckboxLabelSlot: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxLabelSlot.vue')['default']
|
||||||
|
DemoCheckboxModelAsArray: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxModelAsArray.vue')['default']
|
||||||
|
DemoCheckboxStates: typeof import('./src/views/demos/forms/form-elements/checkbox/DemoCheckboxStates.vue')['default']
|
||||||
|
DemoChipClosable: typeof import('./src/views/demos/components/chip/DemoChipClosable.vue')['default']
|
||||||
|
DemoChipColor: typeof import('./src/views/demos/components/chip/DemoChipColor.vue')['default']
|
||||||
|
DemoChipElevated: typeof import('./src/views/demos/components/chip/DemoChipElevated.vue')['default']
|
||||||
|
DemoChipExpandable: typeof import('./src/views/demos/components/chip/DemoChipExpandable.vue')['default']
|
||||||
|
DemoChipInSelects: typeof import('./src/views/demos/components/chip/DemoChipInSelects.vue')['default']
|
||||||
|
DemoChipLabel: typeof import('./src/views/demos/components/chip/DemoChipLabel.vue')['default']
|
||||||
|
DemoChipOutlined: typeof import('./src/views/demos/components/chip/DemoChipOutlined.vue')['default']
|
||||||
|
DemoChipSizes: typeof import('./src/views/demos/components/chip/DemoChipSizes.vue')['default']
|
||||||
|
DemoChipWithAvatar: typeof import('./src/views/demos/components/chip/DemoChipWithAvatar.vue')['default']
|
||||||
|
DemoChipWithIcon: typeof import('./src/views/demos/components/chip/DemoChipWithIcon.vue')['default']
|
||||||
|
DemoComboboxBasic: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxBasic.vue')['default']
|
||||||
|
DemoComboboxClearable: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxClearable.vue')['default']
|
||||||
|
DemoComboboxDensity: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxDensity.vue')['default']
|
||||||
|
DemoComboboxMultiple: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxMultiple.vue')['default']
|
||||||
|
DemoComboboxNoDataWithChips: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxNoDataWithChips.vue')['default']
|
||||||
|
DemoComboboxVariant: typeof import('./src/views/demos/forms/form-elements/combobox/DemoComboboxVariant.vue')['default']
|
||||||
|
DemoCustomInputCustomCheckboxes: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomCheckboxes.vue')['default']
|
||||||
|
DemoCustomInputCustomCheckboxesWithIcon: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomCheckboxesWithIcon.vue')['default']
|
||||||
|
DemoCustomInputCustomCheckboxesWithImage: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomCheckboxesWithImage.vue')['default']
|
||||||
|
DemoCustomInputCustomRadios: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomRadios.vue')['default']
|
||||||
|
DemoCustomInputCustomRadiosWithIcon: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomRadiosWithIcon.vue')['default']
|
||||||
|
DemoCustomInputCustomRadiosWithImage: typeof import('./src/views/demos/forms/form-elements/custom-input/DemoCustomInputCustomRadiosWithImage.vue')['default']
|
||||||
|
DemoDataTableBasic: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableBasic.vue')['default']
|
||||||
|
DemoDataTableCellSlot: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableCellSlot.vue')['default']
|
||||||
|
DemoDataTableDense: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableDense.vue')['default']
|
||||||
|
DemoDataTableExpandableRows: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableExpandableRows.vue')['default']
|
||||||
|
DemoDataTableExternalPagination: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableExternalPagination.vue')['default']
|
||||||
|
DemoDataTableFixedHeader: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableFixedHeader.vue')['default']
|
||||||
|
DemoDataTableGroupingRows: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableGroupingRows.vue')['default']
|
||||||
|
DemoDataTableKitchenSink: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableKitchenSink.vue')['default']
|
||||||
|
DemoDataTableRowEditingViaDialog: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableRowEditingViaDialog.vue')['default']
|
||||||
|
DemoDataTableRowSelection: typeof import('./src/views/demos/forms/tables/data-table/DemoDataTableRowSelection.vue')['default']
|
||||||
|
DemoDateTimePickerBasic: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerBasic.vue')['default']
|
||||||
|
DemoDateTimePickerDateAndTime: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerDateAndTime.vue')['default']
|
||||||
|
DemoDateTimePickerDisabledRange: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerDisabledRange.vue')['default']
|
||||||
|
DemoDateTimePickerHumanFriendly: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerHumanFriendly.vue')['default']
|
||||||
|
DemoDateTimePickerInline: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerInline.vue')['default']
|
||||||
|
DemoDateTimePickerMultipleDates: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerMultipleDates.vue')['default']
|
||||||
|
DemoDateTimePickerRange: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerRange.vue')['default']
|
||||||
|
DemoDateTimePickerTimePicker: typeof import('./src/views/demos/forms/form-elements/date-time-picker/DemoDateTimePickerTimePicker.vue')['default']
|
||||||
|
DemoDialogBasic: typeof import('./src/views/demos/components/dialog/DemoDialogBasic.vue')['default']
|
||||||
|
DemoDialogForm: typeof import('./src/views/demos/components/dialog/DemoDialogForm.vue')['default']
|
||||||
|
DemoDialogFullscreen: typeof import('./src/views/demos/components/dialog/DemoDialogFullscreen.vue')['default']
|
||||||
|
DemoDialogLoader: typeof import('./src/views/demos/components/dialog/DemoDialogLoader.vue')['default']
|
||||||
|
DemoDialogNesting: typeof import('./src/views/demos/components/dialog/DemoDialogNesting.vue')['default']
|
||||||
|
DemoDialogOverflowed: typeof import('./src/views/demos/components/dialog/DemoDialogOverflowed.vue')['default']
|
||||||
|
DemoDialogPersistent: typeof import('./src/views/demos/components/dialog/DemoDialogPersistent.vue')['default']
|
||||||
|
DemoDialogScrollable: typeof import('./src/views/demos/components/dialog/DemoDialogScrollable.vue')['default']
|
||||||
|
DemoEditorBasicEditor: typeof import('./src/views/demos/forms/form-elements/editor/DemoEditorBasicEditor.vue')['default']
|
||||||
|
DemoEditorCustomEditor: typeof import('./src/views/demos/forms/form-elements/editor/DemoEditorCustomEditor.vue')['default']
|
||||||
|
DemoExpansionPanelAccordion: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelAccordion.vue')['default']
|
||||||
|
DemoExpansionPanelBasic: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelBasic.vue')['default']
|
||||||
|
DemoExpansionPanelCustomIcon: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelCustomIcon.vue')['default']
|
||||||
|
DemoExpansionPanelCustomizedAccordion: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelCustomizedAccordion.vue')['default']
|
||||||
|
DemoExpansionPanelInset: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelInset.vue')['default']
|
||||||
|
DemoExpansionPanelModel: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelModel.vue')['default']
|
||||||
|
DemoExpansionPanelPopout: typeof import('./src/views/demos/components/expansion-panel/DemoExpansionPanelPopout.vue')['default']
|
||||||
|
DemoFileInputAccept: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputAccept.vue')['default']
|
||||||
|
DemoFileInputBasic: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputBasic.vue')['default']
|
||||||
|
DemoFileInputChips: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputChips.vue')['default']
|
||||||
|
DemoFileInputCounter: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputCounter.vue')['default']
|
||||||
|
DemoFileInputDensity: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputDensity.vue')['default']
|
||||||
|
DemoFileInputLoading: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputLoading.vue')['default']
|
||||||
|
DemoFileInputMultiple: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputMultiple.vue')['default']
|
||||||
|
DemoFileInputPrependIcon: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputPrependIcon.vue')['default']
|
||||||
|
DemoFileInputSelectionSlot: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputSelectionSlot.vue')['default']
|
||||||
|
DemoFileInputShowSize: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputShowSize.vue')['default']
|
||||||
|
DemoFileInputValidation: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputValidation.vue')['default']
|
||||||
|
DemoFileInputVariant: typeof import('./src/views/demos/forms/form-elements/file-input/DemoFileInputVariant.vue')['default']
|
||||||
|
DemoFormLayoutCollapsible: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutCollapsible.vue')['default']
|
||||||
|
DemoFormLayoutFormHint: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutFormHint.vue')['default']
|
||||||
|
DemoFormLayoutFormSticky: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutFormSticky.vue')['default']
|
||||||
|
DemoFormLayoutFormValidation: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutFormValidation.vue')['default']
|
||||||
|
DemoFormLayoutFormWithTabs: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutFormWithTabs.vue')['default']
|
||||||
|
DemoFormLayoutHorizontalForm: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutHorizontalForm.vue')['default']
|
||||||
|
DemoFormLayoutHorizontalFormWithIcons: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutHorizontalFormWithIcons.vue')['default']
|
||||||
|
DemoFormLayoutMultipleColumn: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutMultipleColumn.vue')['default']
|
||||||
|
DemoFormLayoutVerticalForm: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutVerticalForm.vue')['default']
|
||||||
|
DemoFormLayoutVerticalFormWithIcons: typeof import('./src/views/demos/forms/form-layout/DemoFormLayoutVerticalFormWithIcons.vue')['default']
|
||||||
|
DemoFormValidationSimpleFormValidation: typeof import('./src/views/demos/forms/form-validation/DemoFormValidationSimpleFormValidation.vue')['default']
|
||||||
|
DemoFormValidationValidatingMultipleRules: typeof import('./src/views/demos/forms/form-validation/DemoFormValidationValidatingMultipleRules.vue')['default']
|
||||||
|
DemoFormValidationValidationTypes: typeof import('./src/views/demos/forms/form-validation/DemoFormValidationValidationTypes.vue')['default']
|
||||||
|
DemoFormWizardIconsBasic: typeof import('./src/views/demos/forms/form-wizard/form-wizard-icons/DemoFormWizardIconsBasic.vue')['default']
|
||||||
|
DemoFormWizardIconsValidation: typeof import('./src/views/demos/forms/form-wizard/form-wizard-icons/DemoFormWizardIconsValidation.vue')['default']
|
||||||
|
DemoFormWizardIconsVertical: typeof import('./src/views/demos/forms/form-wizard/form-wizard-icons/DemoFormWizardIconsVertical.vue')['default']
|
||||||
|
DemoFormWizardNumberedBasic: typeof import('./src/views/demos/forms/form-wizard/form-wizard-numbered/DemoFormWizardNumberedBasic.vue')['default']
|
||||||
|
DemoFormWizardNumberedValidation: typeof import('./src/views/demos/forms/form-wizard/form-wizard-numbered/DemoFormWizardNumberedValidation.vue')['default']
|
||||||
|
DemoFormWizardNumberedVertical: typeof import('./src/views/demos/forms/form-wizard/form-wizard-numbered/DemoFormWizardNumberedVertical.vue')['default']
|
||||||
|
DemoListActionAndItemGroup: typeof import('./src/views/demos/components/list/DemoListActionAndItemGroup.vue')['default']
|
||||||
|
DemoListBasic: typeof import('./src/views/demos/components/list/DemoListBasic.vue')['default']
|
||||||
|
DemoListDensity: typeof import('./src/views/demos/components/list/DemoListDensity.vue')['default']
|
||||||
|
DemoListNav: typeof import('./src/views/demos/components/list/DemoListNav.vue')['default']
|
||||||
|
DemoListProgressList: typeof import('./src/views/demos/components/list/DemoListProgressList.vue')['default']
|
||||||
|
DemoListRounded: typeof import('./src/views/demos/components/list/DemoListRounded.vue')['default']
|
||||||
|
DemoListShaped: typeof import('./src/views/demos/components/list/DemoListShaped.vue')['default']
|
||||||
|
DemoListSubGroup: typeof import('./src/views/demos/components/list/DemoListSubGroup.vue')['default']
|
||||||
|
DemoListThreeLine: typeof import('./src/views/demos/components/list/DemoListThreeLine.vue')['default']
|
||||||
|
DemoListTwoLinesAndSubheader: typeof import('./src/views/demos/components/list/DemoListTwoLinesAndSubheader.vue')['default']
|
||||||
|
DemoListUserList: typeof import('./src/views/demos/components/list/DemoListUserList.vue')['default']
|
||||||
|
DemoMenuActivatorAndTooltip: typeof import('./src/views/demos/components/menu/DemoMenuActivatorAndTooltip.vue')['default']
|
||||||
|
DemoMenuBasic: typeof import('./src/views/demos/components/menu/DemoMenuBasic.vue')['default']
|
||||||
|
DemoMenuCustomTransitions: typeof import('./src/views/demos/components/menu/DemoMenuCustomTransitions.vue')['default']
|
||||||
|
DemoMenuLocation: typeof import('./src/views/demos/components/menu/DemoMenuLocation.vue')['default']
|
||||||
|
DemoMenuOpenOnHover: typeof import('./src/views/demos/components/menu/DemoMenuOpenOnHover.vue')['default']
|
||||||
|
DemoMenuPopover: typeof import('./src/views/demos/components/menu/DemoMenuPopover.vue')['default']
|
||||||
|
DemoOtpInputBasic: typeof import('./src/views/demos/forms/form-elements/otp-input/DemoOtpInputBasic.vue')['default']
|
||||||
|
DemoOtpInputFinish: typeof import('./src/views/demos/forms/form-elements/otp-input/DemoOtpInputFinish.vue')['default']
|
||||||
|
DemoOtpInputHidden: typeof import('./src/views/demos/forms/form-elements/otp-input/DemoOtpInputHidden.vue')['default']
|
||||||
|
DemoPaginationBasic: typeof import('./src/views/demos/components/pagination/DemoPaginationBasic.vue')['default']
|
||||||
|
DemoPaginationCircle: typeof import('./src/views/demos/components/pagination/DemoPaginationCircle.vue')['default']
|
||||||
|
DemoPaginationColor: typeof import('./src/views/demos/components/pagination/DemoPaginationColor.vue')['default']
|
||||||
|
DemoPaginationDisabled: typeof import('./src/views/demos/components/pagination/DemoPaginationDisabled.vue')['default']
|
||||||
|
DemoPaginationIcons: typeof import('./src/views/demos/components/pagination/DemoPaginationIcons.vue')['default']
|
||||||
|
DemoPaginationLength: typeof import('./src/views/demos/components/pagination/DemoPaginationLength.vue')['default']
|
||||||
|
DemoPaginationOutline: typeof import('./src/views/demos/components/pagination/DemoPaginationOutline.vue')['default']
|
||||||
|
DemoPaginationOutlineCircle: typeof import('./src/views/demos/components/pagination/DemoPaginationOutlineCircle.vue')['default']
|
||||||
|
DemoPaginationSize: typeof import('./src/views/demos/components/pagination/DemoPaginationSize.vue')['default']
|
||||||
|
DemoPaginationTotalVisible: typeof import('./src/views/demos/components/pagination/DemoPaginationTotalVisible.vue')['default']
|
||||||
|
DemoProgressCircularColor: typeof import('./src/views/demos/components/progress-circular/DemoProgressCircularColor.vue')['default']
|
||||||
|
DemoProgressCircularIndeterminate: typeof import('./src/views/demos/components/progress-circular/DemoProgressCircularIndeterminate.vue')['default']
|
||||||
|
DemoProgressCircularRotate: typeof import('./src/views/demos/components/progress-circular/DemoProgressCircularRotate.vue')['default']
|
||||||
|
DemoProgressCircularSize: typeof import('./src/views/demos/components/progress-circular/DemoProgressCircularSize.vue')['default']
|
||||||
|
DemoProgressLinearBuffering: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearBuffering.vue')['default']
|
||||||
|
DemoProgressLinearColor: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearColor.vue')['default']
|
||||||
|
DemoProgressLinearIndeterminate: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearIndeterminate.vue')['default']
|
||||||
|
DemoProgressLinearReversed: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearReversed.vue')['default']
|
||||||
|
DemoProgressLinearRounded: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearRounded.vue')['default']
|
||||||
|
DemoProgressLinearSlots: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearSlots.vue')['default']
|
||||||
|
DemoProgressLinearStriped: typeof import('./src/views/demos/components/progress-linear/DemoProgressLinearStriped.vue')['default']
|
||||||
|
DemoRadioBasic: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioBasic.vue')['default']
|
||||||
|
DemoRadioColors: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioColors.vue')['default']
|
||||||
|
DemoRadioDensity: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioDensity.vue')['default']
|
||||||
|
DemoRadioIcon: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioIcon.vue')['default']
|
||||||
|
DemoRadioInline: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioInline.vue')['default']
|
||||||
|
DemoRadioLabelSlot: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioLabelSlot.vue')['default']
|
||||||
|
DemoRadioValidation: typeof import('./src/views/demos/forms/form-elements/radio/DemoRadioValidation.vue')['default']
|
||||||
|
DemoRangeSliderBasic: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderBasic.vue')['default']
|
||||||
|
DemoRangeSliderColor: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderColor.vue')['default']
|
||||||
|
DemoRangeSliderDisabled: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderDisabled.vue')['default']
|
||||||
|
DemoRangeSliderStep: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderStep.vue')['default']
|
||||||
|
DemoRangeSliderThumbLabel: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderThumbLabel.vue')['default']
|
||||||
|
DemoRangeSliderVertical: typeof import('./src/views/demos/forms/form-elements/range-slider/DemoRangeSliderVertical.vue')['default']
|
||||||
|
DemoRatingBasic: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingBasic.vue')['default']
|
||||||
|
DemoRatingClearable: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingClearable.vue')['default']
|
||||||
|
DemoRatingColors: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingColors.vue')['default']
|
||||||
|
DemoRatingDensity: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingDensity.vue')['default']
|
||||||
|
DemoRatingHover: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingHover.vue')['default']
|
||||||
|
DemoRatingIncremented: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingIncremented.vue')['default']
|
||||||
|
DemoRatingItemSlot: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingItemSlot.vue')['default']
|
||||||
|
DemoRatingLength: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingLength.vue')['default']
|
||||||
|
DemoRatingReadonly: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingReadonly.vue')['default']
|
||||||
|
DemoRatingSize: typeof import('./src/views/demos/forms/form-elements/rating/DemoRatingSize.vue')['default']
|
||||||
|
DemoSelectBasic: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectBasic.vue')['default']
|
||||||
|
DemoSelectChips: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectChips.vue')['default']
|
||||||
|
DemoSelectCustomTextAndValue: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectCustomTextAndValue.vue')['default']
|
||||||
|
DemoSelectDensity: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectDensity.vue')['default']
|
||||||
|
DemoSelectIcons: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectIcons.vue')['default']
|
||||||
|
DemoSelectMenuProps: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectMenuProps.vue')['default']
|
||||||
|
DemoSelectMultiple: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectMultiple.vue')['default']
|
||||||
|
DemoSelectSelectionSlot: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectSelectionSlot.vue')['default']
|
||||||
|
DemoSelectVariant: typeof import('./src/views/demos/forms/form-elements/select/DemoSelectVariant.vue')['default']
|
||||||
|
DemoSimpleTableBasic: typeof import('./src/views/demos/forms/tables/simple-table/DemoSimpleTableBasic.vue')['default']
|
||||||
|
DemoSimpleTableDensity: typeof import('./src/views/demos/forms/tables/simple-table/DemoSimpleTableDensity.vue')['default']
|
||||||
|
DemoSimpleTableFixedHeader: typeof import('./src/views/demos/forms/tables/simple-table/DemoSimpleTableFixedHeader.vue')['default']
|
||||||
|
DemoSimpleTableHeight: typeof import('./src/views/demos/forms/tables/simple-table/DemoSimpleTableHeight.vue')['default']
|
||||||
|
DemoSimpleTableTheme: typeof import('./src/views/demos/forms/tables/simple-table/DemoSimpleTableTheme.vue')['default']
|
||||||
|
DemoSliderAppendAndPrepend: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderAppendAndPrepend.vue')['default']
|
||||||
|
DemoSliderAppendTextField: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderAppendTextField.vue')['default']
|
||||||
|
DemoSliderBasic: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderBasic.vue')['default']
|
||||||
|
DemoSliderColors: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderColors.vue')['default']
|
||||||
|
DemoSliderDisabledAndReadonly: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderDisabledAndReadonly.vue')['default']
|
||||||
|
DemoSliderIcons: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderIcons.vue')['default']
|
||||||
|
DemoSliderMinAndMax: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderMinAndMax.vue')['default']
|
||||||
|
DemoSliderSize: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderSize.vue')['default']
|
||||||
|
DemoSliderStep: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderStep.vue')['default']
|
||||||
|
DemoSliderThumb: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderThumb.vue')['default']
|
||||||
|
DemoSliderTicks: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderTicks.vue')['default']
|
||||||
|
DemoSliderValidation: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderValidation.vue')['default']
|
||||||
|
DemoSliderVertical: typeof import('./src/views/demos/forms/form-elements/slider/DemoSliderVertical.vue')['default']
|
||||||
|
DemoSnackbarBasic: typeof import('./src/views/demos/components/snackbar/DemoSnackbarBasic.vue')['default']
|
||||||
|
DemoSnackbarMultiLine: typeof import('./src/views/demos/components/snackbar/DemoSnackbarMultiLine.vue')['default']
|
||||||
|
DemoSnackbarPosition: typeof import('./src/views/demos/components/snackbar/DemoSnackbarPosition.vue')['default']
|
||||||
|
DemoSnackbarTimeout: typeof import('./src/views/demos/components/snackbar/DemoSnackbarTimeout.vue')['default']
|
||||||
|
DemoSnackbarTransition: typeof import('./src/views/demos/components/snackbar/DemoSnackbarTransition.vue')['default']
|
||||||
|
DemoSnackbarVariants: typeof import('./src/views/demos/components/snackbar/DemoSnackbarVariants.vue')['default']
|
||||||
|
DemoSnackbarVertical: typeof import('./src/views/demos/components/snackbar/DemoSnackbarVertical.vue')['default']
|
||||||
|
DemoSnackbarWithAction: typeof import('./src/views/demos/components/snackbar/DemoSnackbarWithAction.vue')['default']
|
||||||
|
DemoSwiperAutoplay: typeof import('./src/views/demos/components/swiper/DemoSwiperAutoplay.vue')['default']
|
||||||
|
DemoSwiperBasic: typeof import('./src/views/demos/components/swiper/DemoSwiperBasic.vue')['default']
|
||||||
|
DemoSwiperCenteredSlidesOption1: typeof import('./src/views/demos/components/swiper/DemoSwiperCenteredSlidesOption1.vue')['default']
|
||||||
|
DemoSwiperCenteredSlidesOption2: typeof import('./src/views/demos/components/swiper/DemoSwiperCenteredSlidesOption2.vue')['default']
|
||||||
|
DemoSwiperCoverflowEffect: typeof import('./src/views/demos/components/swiper/DemoSwiperCoverflowEffect.vue')['default']
|
||||||
|
DemoSwiperCubeEffect: typeof import('./src/views/demos/components/swiper/DemoSwiperCubeEffect.vue')['default']
|
||||||
|
DemoSwiperFade: typeof import('./src/views/demos/components/swiper/DemoSwiperFade.vue')['default']
|
||||||
|
DemoSwiperGallery: typeof import('./src/views/demos/components/swiper/DemoSwiperGallery.vue')['default']
|
||||||
|
DemoSwiperGrid: typeof import('./src/views/demos/components/swiper/DemoSwiperGrid.vue')['default']
|
||||||
|
DemoSwiperLazyLoading: typeof import('./src/views/demos/components/swiper/DemoSwiperLazyLoading.vue')['default']
|
||||||
|
DemoSwiperMultipleSlidesPerView: typeof import('./src/views/demos/components/swiper/DemoSwiperMultipleSlidesPerView.vue')['default']
|
||||||
|
DemoSwiperNavigation: typeof import('./src/views/demos/components/swiper/DemoSwiperNavigation.vue')['default']
|
||||||
|
DemoSwiperPagination: typeof import('./src/views/demos/components/swiper/DemoSwiperPagination.vue')['default']
|
||||||
|
DemoSwiperProgress: typeof import('./src/views/demos/components/swiper/DemoSwiperProgress.vue')['default']
|
||||||
|
DemoSwiperResponsiveBreakpoints: typeof import('./src/views/demos/components/swiper/DemoSwiperResponsiveBreakpoints.vue')['default']
|
||||||
|
DemoSwiperVirtualSlides: typeof import('./src/views/demos/components/swiper/DemoSwiperVirtualSlides.vue')['default']
|
||||||
|
DemoSwitchBasic: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchBasic.vue')['default']
|
||||||
|
DemoSwitchColors: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchColors.vue')['default']
|
||||||
|
DemoSwitchInset: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchInset.vue')['default']
|
||||||
|
DemoSwitchLabelSlot: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchLabelSlot.vue')['default']
|
||||||
|
DemoSwitchModelAsArray: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchModelAsArray.vue')['default']
|
||||||
|
DemoSwitchStates: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchStates.vue')['default']
|
||||||
|
DemoSwitchTrueAndFalseValue: typeof import('./src/views/demos/forms/form-elements/switch/DemoSwitchTrueAndFalseValue.vue')['default']
|
||||||
|
DemoTabsAlignment: typeof import('./src/views/demos/components/tabs/DemoTabsAlignment.vue')['default']
|
||||||
|
DemoTabsBasic: typeof import('./src/views/demos/components/tabs/DemoTabsBasic.vue')['default']
|
||||||
|
DemoTabsBasicPill: typeof import('./src/views/demos/components/tabs/DemoTabsBasicPill.vue')['default']
|
||||||
|
DemoTabsCustomIcons: typeof import('./src/views/demos/components/tabs/DemoTabsCustomIcons.vue')['default']
|
||||||
|
DemoTabsDynamic: typeof import('./src/views/demos/components/tabs/DemoTabsDynamic.vue')['default']
|
||||||
|
DemoTabsFixed: typeof import('./src/views/demos/components/tabs/DemoTabsFixed.vue')['default']
|
||||||
|
DemoTabsGrow: typeof import('./src/views/demos/components/tabs/DemoTabsGrow.vue')['default']
|
||||||
|
DemoTabsPagination: typeof import('./src/views/demos/components/tabs/DemoTabsPagination.vue')['default']
|
||||||
|
DemoTabsProgrammaticNavigation: typeof import('./src/views/demos/components/tabs/DemoTabsProgrammaticNavigation.vue')['default']
|
||||||
|
DemoTabsStacked: typeof import('./src/views/demos/components/tabs/DemoTabsStacked.vue')['default']
|
||||||
|
DemoTabsVertical: typeof import('./src/views/demos/components/tabs/DemoTabsVertical.vue')['default']
|
||||||
|
DemoTabsVerticalPill: typeof import('./src/views/demos/components/tabs/DemoTabsVerticalPill.vue')['default']
|
||||||
|
DemoTextareaAutoGrow: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaAutoGrow.vue')['default']
|
||||||
|
DemoTextareaBasic: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaBasic.vue')['default']
|
||||||
|
DemoTextareaBrowserAutocomplete: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaBrowserAutocomplete.vue')['default']
|
||||||
|
DemoTextareaClearable: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaClearable.vue')['default']
|
||||||
|
DemoTextareaCounter: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaCounter.vue')['default']
|
||||||
|
DemoTextareaIcons: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaIcons.vue')['default']
|
||||||
|
DemoTextareaNoResize: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaNoResize.vue')['default']
|
||||||
|
DemoTextareaRows: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaRows.vue')['default']
|
||||||
|
DemoTextareaStates: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaStates.vue')['default']
|
||||||
|
DemoTextareaValidation: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaValidation.vue')['default']
|
||||||
|
DemoTextareaVariant: typeof import('./src/views/demos/forms/form-elements/textarea/DemoTextareaVariant.vue')['default']
|
||||||
|
DemoTextfieldBasic: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldBasic.vue')['default']
|
||||||
|
DemoTextfieldClearable: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldClearable.vue')['default']
|
||||||
|
DemoTextfieldCounter: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldCounter.vue')['default']
|
||||||
|
DemoTextfieldCustomColors: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldCustomColors.vue')['default']
|
||||||
|
DemoTextfieldDensity: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldDensity.vue')['default']
|
||||||
|
DemoTextfieldIconEvents: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldIconEvents.vue')['default']
|
||||||
|
DemoTextfieldIcons: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldIcons.vue')['default']
|
||||||
|
DemoTextfieldIconSlots: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldIconSlots.vue')['default']
|
||||||
|
DemoTextfieldLabelSlot: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldLabelSlot.vue')['default']
|
||||||
|
DemoTextfieldPasswordInput: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldPasswordInput.vue')['default']
|
||||||
|
DemoTextfieldPrefixesAndSuffixes: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldPrefixesAndSuffixes.vue')['default']
|
||||||
|
DemoTextfieldSingleLine: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldSingleLine.vue')['default']
|
||||||
|
DemoTextfieldState: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldState.vue')['default']
|
||||||
|
DemoTextfieldValidation: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldValidation.vue')['default']
|
||||||
|
DemoTextfieldVariant: typeof import('./src/views/demos/forms/form-elements/textfield/DemoTextfieldVariant.vue')['default']
|
||||||
|
DemoTooltipDelayOnHover: typeof import('./src/views/demos/components/tooltip/DemoTooltipDelayOnHover.vue')['default']
|
||||||
|
DemoTooltipEvents: typeof import('./src/views/demos/components/tooltip/DemoTooltipEvents.vue')['default']
|
||||||
|
DemoTooltipLocation: typeof import('./src/views/demos/components/tooltip/DemoTooltipLocation.vue')['default']
|
||||||
|
DemoTooltipTooltipOnVariousElements: typeof import('./src/views/demos/components/tooltip/DemoTooltipTooltipOnVariousElements.vue')['default']
|
||||||
|
DemoTooltipTransition: typeof import('./src/views/demos/components/tooltip/DemoTooltipTransition.vue')['default']
|
||||||
|
DemoTooltipVModelSupport: typeof import('./src/views/demos/components/tooltip/DemoTooltipVModelSupport.vue')['default']
|
||||||
|
DialogCloseBtn: typeof import('./src/@core/components/DialogCloseBtn.vue')['default']
|
||||||
|
DropZone: typeof import('./src/@core/components/DropZone.vue')['default']
|
||||||
|
EnableOneTimePasswordDialog: typeof import('./src/components/dialogs/EnableOneTimePasswordDialog.vue')['default']
|
||||||
|
ErrorHeader: typeof import('./src/components/ErrorHeader.vue')['default']
|
||||||
|
I18n: typeof import('./src/@core/components/I18n.vue')['default']
|
||||||
|
MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default']
|
||||||
|
Notifications: typeof import('./src/@core/components/Notifications.vue')['default']
|
||||||
|
PaymentProvidersDialog: typeof import('./src/components/dialogs/PaymentProvidersDialog.vue')['default']
|
||||||
|
PricingPlanDialog: typeof import('./src/components/dialogs/PricingPlanDialog.vue')['default']
|
||||||
|
ReferAndEarnDialog: typeof import('./src/components/dialogs/ReferAndEarnDialog.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
ScrollToTop: typeof import('./src/@core/components/ScrollToTop.vue')['default']
|
||||||
|
ShareProjectDialog: typeof import('./src/components/dialogs/ShareProjectDialog.vue')['default']
|
||||||
|
Shortcuts: typeof import('./src/@core/components/Shortcuts.vue')['default']
|
||||||
|
TheCustomizer: typeof import('./src/@core/components/TheCustomizer.vue')['default']
|
||||||
|
ThemeSwitcher: typeof import('./src/@core/components/ThemeSwitcher.vue')['default']
|
||||||
|
TimelineBasic: typeof import('./src/views/demos/components/timeline/TimelineBasic.vue')['default']
|
||||||
|
TimelineOutlined: typeof import('./src/views/demos/components/timeline/TimelineOutlined.vue')['default']
|
||||||
|
TimelineWithIcons: typeof import('./src/views/demos/components/timeline/TimelineWithIcons.vue')['default']
|
||||||
|
TiptapEditor: typeof import('./src/@core/components/TiptapEditor.vue')['default']
|
||||||
|
TwoFactorAuthDialog: typeof import('./src/components/dialogs/TwoFactorAuthDialog.vue')['default']
|
||||||
|
UserInfoEditDialog: typeof import('./src/components/dialogs/UserInfoEditDialog.vue')['default']
|
||||||
|
UserUpgradePlanDialog: typeof import('./src/components/dialogs/UserUpgradePlanDialog.vue')['default']
|
||||||
|
VueApexCharts: typeof import('vue3-apexcharts')['default']
|
||||||
|
}
|
||||||
|
}
|
||||||
25
dev.Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
FROM node:lts
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies based on the preferred package manager
|
||||||
|
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||||
|
elif [ -f package-lock.json ]; then npm i; \
|
||||||
|
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
|
||||||
|
# Allow install without lockfile, so example works even without Node.js installed locally
|
||||||
|
else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Note: Don't expose ports here, Compose will handle that for us
|
||||||
|
|
||||||
|
# Start vue.js in development mode based on the preferred package manager
|
||||||
|
CMD \
|
||||||
|
if [ -f yarn.lock ]; then yarn dev --host; \
|
||||||
|
elif [ -f package-lock.json ]; then npm run dev -- --host; \
|
||||||
|
elif [ -f pnpm-lock.yaml ]; then pnpm dev --host; \
|
||||||
|
else yarn dev --host; \
|
||||||
|
fi
|
||||||
14
docker-compose.dev.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
vue-project:
|
||||||
|
container_name: vue-project_dev
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: dev.Dockerfile
|
||||||
|
volumes:
|
||||||
|
- ./src:/app/src
|
||||||
|
- ./public:/app/public
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 5173:5173
|
||||||
11
docker-compose.prod.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
vue-project:
|
||||||
|
container_name: vue-project_prod
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: prod.Dockerfile
|
||||||
|
image: vue-app
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
12
env.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'vue-router'
|
||||||
|
declare module 'vue-router' {
|
||||||
|
interface RouteMeta {
|
||||||
|
action?: string
|
||||||
|
subject?: string
|
||||||
|
layoutWrapperClasses?: string
|
||||||
|
navActiveLink?: RouteLocationRaw
|
||||||
|
layout?: 'blank' | 'default'
|
||||||
|
unauthenticatedOnly?: boolean
|
||||||
|
public?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
64
index.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Materialize - Vuejs Admin Template</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/loader.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<div id="loading-bg">
|
||||||
|
<div class="loading-logo">
|
||||||
|
<!-- svg logo -->
|
||||||
|
<svg width="86" height="46" viewBox="0 0 268 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="matrix(-.8652 .50142 .49859 .86684 195.571 0)"
|
||||||
|
fill="var(--initial-loader-color)" />
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="matrix(-.8652 .50142 .49859 .86684 196.084 0)"
|
||||||
|
fill="url(#a)" fill-opacity=".4" />
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="rotate(30.094 86.573 322.042) skewX(.187)"
|
||||||
|
fill="var(--initial-loader-color)" />
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="matrix(-.8652 .50142 .49859 .86684 94.197 0)"
|
||||||
|
fill="var(--initial-loader-color)" />
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="matrix(-.8652 .50142 .49859 .86684 94.197 0)"
|
||||||
|
fill="url(#b)" fill-opacity=".4" />
|
||||||
|
<rect width="50.289" height="143.953" rx="25.144" transform="rotate(30.094 35.886 133.493) skewX(.187)"
|
||||||
|
fill="var(--initial-loader-color)" />
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="a" x1="25.144" y1="0" x2="25.144" y2="143.953" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop />
|
||||||
|
<stop offset="1" stop-opacity="0" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="b" x1="25.144" y1="0" x2="25.144" y2="143.953" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop />
|
||||||
|
<stop offset="1" stop-opacity="0" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class=" loading">
|
||||||
|
<div class="effect-1 effects"></div>
|
||||||
|
<div class="effect-2 effects"></div>
|
||||||
|
<div class="effect-3 effects"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
<script>
|
||||||
|
const loaderColor = localStorage.getItem('materialize-initial-loader-bg') || '#FFFFFF'
|
||||||
|
const primaryColor = localStorage.getItem('materialize-initial-loader-color') || '#666CFF'
|
||||||
|
|
||||||
|
if (loaderColor)
|
||||||
|
document.documentElement.style.setProperty('--initial-loader-bg', loaderColor)
|
||||||
|
if (loaderColor)
|
||||||
|
document.documentElement.style.setProperty('--initial-loader-bg', loaderColor)
|
||||||
|
|
||||||
|
if (primaryColor)
|
||||||
|
document.documentElement.style.setProperty('--initial-loader-color', primaryColor)
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
14
nginx.conf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# nginx.conf
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Additional configurations go here...
|
||||||
|
}
|
||||||
16087
package-lock.json
generated
Normal file
137
package.json
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
{
|
||||||
|
"name": "materialize-vuejs-admin-template",
|
||||||
|
"version": "2.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview --port 5050",
|
||||||
|
"typecheck": "vue-tsc --noEmit",
|
||||||
|
"lint": "eslint . -c .eslintrc.cjs --fix --ext .ts,.js,.cjs,.vue,.tsx,.jsx",
|
||||||
|
"build:icons": "tsx src/plugins/iconify/build-icons.ts",
|
||||||
|
"msw:init": "msw init public/ --save",
|
||||||
|
"postinstall": "npm run build:icons && npm run msw:init"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@casl/ability": "6.7.2",
|
||||||
|
"@casl/vue": "2.2.2",
|
||||||
|
"@floating-ui/dom": "1.6.8",
|
||||||
|
"@formkit/drag-and-drop": "0.1.6",
|
||||||
|
"@iconify-json/bxl": "1.2.2",
|
||||||
|
"@sindresorhus/is": "7.0.1",
|
||||||
|
"@tiptap/extension-highlight": "^2.10.4",
|
||||||
|
"@tiptap/extension-image": "^2.10.4",
|
||||||
|
"@tiptap/extension-link": "^2.10.4",
|
||||||
|
"@tiptap/extension-text-align": "^2.10.4",
|
||||||
|
"@tiptap/pm": "^2.10.4",
|
||||||
|
"@tiptap/starter-kit": "^2.10.4",
|
||||||
|
"@tiptap/vue-3": "^2.10.4",
|
||||||
|
"@vueuse/core": "10.11.1",
|
||||||
|
"@vueuse/math": "10.11.1",
|
||||||
|
"apexcharts": "3.54.1",
|
||||||
|
"chart.js": "4.4.7",
|
||||||
|
"cookie-es": "1.2.2",
|
||||||
|
"destr": "2.0.3",
|
||||||
|
"eslint-plugin-regexp": "2.7.0",
|
||||||
|
"jwt-decode": "4.0.0",
|
||||||
|
"mapbox-gl": "3.5.2",
|
||||||
|
"ofetch": "1.4.1",
|
||||||
|
"pinia": "2.3.0",
|
||||||
|
"prismjs": "1.29.0",
|
||||||
|
"roboto-fontface": "0.10.0",
|
||||||
|
"shepherd.js": "13.0.3",
|
||||||
|
"swiper": "11.1.15",
|
||||||
|
"ufo": "1.5.4",
|
||||||
|
"unplugin-vue-define-options": "1.5.3",
|
||||||
|
"vue": "3.5.13",
|
||||||
|
"vue-chartjs": "5.3.2",
|
||||||
|
"vue-flatpickr-component": "11.0.5",
|
||||||
|
"vue-i18n": "10.0.4",
|
||||||
|
"vue-prism-component": "2.0.0",
|
||||||
|
"vue-router": "4.5.0",
|
||||||
|
"vue3-apexcharts": "1.5.3",
|
||||||
|
"vue3-perfect-scrollbar": "2.0.0",
|
||||||
|
"vuetify": "3.7.5",
|
||||||
|
"webfontloader": "1.6.28"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config-vue": "0.43.1",
|
||||||
|
"@antfu/utils": "0.7.10",
|
||||||
|
"@fullcalendar/core": "6.1.15",
|
||||||
|
"@fullcalendar/daygrid": "6.1.15",
|
||||||
|
"@fullcalendar/interaction": "6.1.15",
|
||||||
|
"@fullcalendar/list": "6.1.15",
|
||||||
|
"@iconify-json/ri": "1.2.5",
|
||||||
|
"@fullcalendar/timegrid": "6.1.15",
|
||||||
|
"@fullcalendar/vue3": "6.1.15",
|
||||||
|
"@iconify-json/mdi": "1.2.2",
|
||||||
|
"@iconify/tools": "4.1.1",
|
||||||
|
"@iconify/utils": "2.2.1",
|
||||||
|
"@iconify/vue": "4.1.2",
|
||||||
|
"@intlify/unplugin-vue-i18n": "5.3.1",
|
||||||
|
"@stylistic/stylelint-config": "1.0.1",
|
||||||
|
"@stylistic/stylelint-plugin": "2.1.3",
|
||||||
|
"@tiptap/extension-character-count": "^2.10.4",
|
||||||
|
"@tiptap/extension-placeholder": "^2.10.4",
|
||||||
|
"@tiptap/extension-subscript": "^2.10.4",
|
||||||
|
"@tiptap/extension-superscript": "^2.10.4",
|
||||||
|
"@tiptap/extension-underline": "^2.10.4",
|
||||||
|
"@types/mapbox-gl": "3.4.1",
|
||||||
|
"@types/node": "22.10.2",
|
||||||
|
"@types/webfontloader": "1.6.38",
|
||||||
|
"@typescript-eslint/eslint-plugin": "7.18.0",
|
||||||
|
"@typescript-eslint/parser": "7.18.0",
|
||||||
|
"@videojs-player/vue": "1.0.0",
|
||||||
|
"@vitejs/plugin-vue": "5.2.1",
|
||||||
|
"@vitejs/plugin-vue-jsx": "4.1.1",
|
||||||
|
"eslint": "8.57.1",
|
||||||
|
"eslint-config-airbnb-base": "15.0.0",
|
||||||
|
"eslint-import-resolver-typescript": "3.7.0",
|
||||||
|
"eslint-plugin-case-police": "0.6.1",
|
||||||
|
"eslint-plugin-import": "2.31.0",
|
||||||
|
"eslint-plugin-promise": "6.6.0",
|
||||||
|
"eslint-plugin-regex": "1.10.0",
|
||||||
|
"eslint-plugin-sonarjs": "0.24.0",
|
||||||
|
"eslint-plugin-unicorn": "51.0.1",
|
||||||
|
"eslint-plugin-vue": "9.32.0",
|
||||||
|
"msw": "2.3.4",
|
||||||
|
"postcss-html": "1.7.0",
|
||||||
|
"postcss-scss": "4.0.9",
|
||||||
|
"sass": "1.76.0",
|
||||||
|
"shiki": "1.24.4",
|
||||||
|
"stylelint": "16.8.0",
|
||||||
|
"stylelint-config-idiomatic-order": "10.0.0",
|
||||||
|
"stylelint-config-standard-scss": "13.1.0",
|
||||||
|
"stylelint-use-logical-spec": "5.0.1",
|
||||||
|
"tsx": "4.19.2",
|
||||||
|
"type-fest": "4.30.2",
|
||||||
|
"typescript": "5.7.2",
|
||||||
|
"unplugin-auto-import": "0.18.6",
|
||||||
|
"unplugin-vue-components": "0.27.5",
|
||||||
|
"unplugin-vue-router": "0.8.8",
|
||||||
|
"video.js": "8.6.0",
|
||||||
|
"vite": "5.4.11",
|
||||||
|
"vite-plugin-vue-devtools": "7.3.7",
|
||||||
|
"vite-plugin-vue-layouts": "0.11.0",
|
||||||
|
"vite-plugin-vuetify": "2.0.3",
|
||||||
|
"vite-svg-loader": "5.1.0",
|
||||||
|
"vue-shepherd": "3.0.0",
|
||||||
|
"vue-tsc": "2.2.0"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"postcss": "^8",
|
||||||
|
"@tiptap/core": "^2",
|
||||||
|
"@types/video.js": "^7",
|
||||||
|
"sass": "1.76.0"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"postcss": "^8",
|
||||||
|
"@tiptap/core": "^2",
|
||||||
|
"@types/video.js": "^7",
|
||||||
|
"sass": "1.76.0"
|
||||||
|
},
|
||||||
|
"msw": {
|
||||||
|
"workerDirectory": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
9916
pnpm-lock.yaml
generated
Normal file
41
prod.Dockerfile
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Use the official Node.js image as the base image
|
||||||
|
FROM node:18 as builder
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package.json and yarn.lock to the container
|
||||||
|
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||||
|
elif [ -f package-lock.json ]; then npm i; \
|
||||||
|
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
|
||||||
|
else echo "Lockfile not found." && exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build vue.js based on the preferred package manager
|
||||||
|
RUN \
|
||||||
|
if [ -f yarn.lock ]; then yarn build; \
|
||||||
|
elif [ -f package-lock.json ]; then npm run build; \
|
||||||
|
elif [ -f pnpm-lock.yaml ]; then pnpm run build; \
|
||||||
|
else yarn build; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use Nginx as the production server
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
# Copy the custom Nginx configuration file
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Copy the built Vue.js files to the Nginx web server directory
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Expose port 80 for Nginx
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start Nginx when the container runs
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/images/avatars/avatar-1.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
public/images/avatars/avatar-2.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
10
public/images/svg/discord.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="59" height="58" viewBox="0 0 59 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path d="M23.2164 41.2571L20.475 46.6946C20.2986 47.0654 19.9986 47.3632 19.6265 47.5368C19.2544 47.7105 18.8334 47.7491 18.4359 47.6462C12.8852 46.2868 8.08203 43.9305 4.59297 40.8946C4.32992 40.6625 4.1389 40.3599 4.04253 40.0226C3.94616 39.6853 3.94848 39.3275 4.04922 38.9915L11.7297 13.3446C11.8044 13.0821 11.9397 12.8409 12.1247 12.6402C12.3096 12.4395 12.539 12.285 12.7945 12.1891C14.9645 11.2989 17.2085 10.6014 19.5008 10.1047C19.9413 10.0083 20.4019 10.0774 20.7947 10.2988C21.1875 10.5203 21.485 10.8787 21.6305 11.3055L23.4203 16.7204C27.3437 16.1766 31.3234 16.1766 35.2469 16.7204L37.0367 11.3055C37.1822 10.8787 37.4797 10.5203 37.8725 10.2988C38.2653 10.0774 38.7259 10.0083 39.1664 10.1047C41.4587 10.6014 43.7027 11.2989 45.8727 12.1891C46.1282 12.285 46.3576 12.4395 46.5425 12.6402C46.7275 12.8409 46.8628 13.0821 46.9375 13.3446L54.618 38.9915C54.7187 39.3275 54.721 39.6853 54.6247 40.0226C54.5283 40.3599 54.3373 40.6625 54.0742 40.8946C50.5852 43.9305 45.782 46.2868 40.2313 47.6462C39.8338 47.7491 39.4128 47.7105 39.0407 47.5368C38.6686 47.3632 38.3686 47.0654 38.1922 46.6946L35.4508 41.2571C33.4242 41.5421 31.3802 41.6859 29.3336 41.6876C27.287 41.6859 25.243 41.5421 23.2164 41.2571Z" fill="#4B465C"/>
|
||||||
|
<path d="M23.2164 41.2571L20.475 46.6946C20.2986 47.0654 19.9986 47.3632 19.6265 47.5368C19.2544 47.7105 18.8334 47.7491 18.4359 47.6462C12.8852 46.2868 8.08203 43.9305 4.59297 40.8946C4.32992 40.6625 4.1389 40.3599 4.04253 40.0226C3.94616 39.6853 3.94848 39.3275 4.04922 38.9915L11.7297 13.3446C11.8044 13.0821 11.9397 12.8409 12.1247 12.6402C12.3096 12.4395 12.539 12.285 12.7945 12.1891C14.9645 11.2989 17.2085 10.6014 19.5008 10.1047C19.9413 10.0083 20.4019 10.0774 20.7947 10.2988C21.1875 10.5203 21.485 10.8787 21.6305 11.3055L23.4203 16.7204C27.3437 16.1766 31.3234 16.1766 35.2469 16.7204L37.0367 11.3055C37.1822 10.8787 37.4797 10.5203 37.8725 10.2988C38.2653 10.0774 38.7259 10.0083 39.1664 10.1047C41.4587 10.6014 43.7027 11.2989 45.8727 12.1891C46.1282 12.285 46.3576 12.4395 46.5425 12.6402C46.7275 12.8409 46.8628 13.0821 46.9375 13.3446L54.618 38.9915C54.7187 39.3275 54.721 39.6853 54.6247 40.0226C54.5283 40.3599 54.3373 40.6625 54.0742 40.8946C50.5852 43.9305 45.782 46.2868 40.2313 47.6462C39.8338 47.7491 39.4128 47.7105 39.0407 47.5368C38.6686 47.3632 38.3686 47.0654 38.1922 46.6946L35.4508 41.2571C33.4242 41.5421 31.3802 41.6859 29.3336 41.6876C27.287 41.6859 25.243 41.5421 23.2164 41.2571Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.8022 32.625C24.8022 34.1265 23.585 35.3438 22.0835 35.3438C20.582 35.3438 19.3647 34.1265 19.3647 32.625C19.3647 31.1235 20.582 29.9062 22.0835 29.9062C23.585 29.9062 24.8022 31.1235 24.8022 32.625ZM39.3022 32.625C39.3022 34.1265 38.085 35.3438 36.5835 35.3438C35.082 35.3438 33.8647 34.1265 33.8647 32.625C33.8647 31.1235 35.082 29.9062 36.5835 29.9062C38.085 29.9062 39.3022 31.1235 39.3022 32.625Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.8022 32.625C24.8022 34.1265 23.585 35.3438 22.0835 35.3438C20.582 35.3438 19.3647 34.1265 19.3647 32.625C19.3647 31.1235 20.582 29.9062 22.0835 29.9062C23.585 29.9062 24.8022 31.1235 24.8022 32.625ZM39.3022 32.625C39.3022 34.1265 38.085 35.3438 36.5835 35.3438C35.082 35.3438 33.8647 34.1265 33.8647 32.625C33.8647 31.1235 35.082 29.9062 36.5835 29.9062C38.085 29.9062 39.3022 31.1235 39.3022 32.625Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
<path d="M17.1898 18.1251C21.119 16.8936 25.2161 16.2821 29.3336 16.3126C33.4511 16.2821 37.5482 16.8936 41.4773 18.1251M41.4773 39.8751C37.5482 41.1065 33.4511 41.718 29.3336 41.6876C25.2161 41.718 21.119 41.1065 17.1898 39.8751M35.4508 41.2571L38.1922 46.6946C38.3686 47.0654 38.6686 47.3632 39.0407 47.5368C39.4128 47.7105 39.8338 47.7491 40.2313 47.6462C45.782 46.2868 50.5852 43.9305 54.0742 40.8946C54.3373 40.6625 54.5283 40.3599 54.6247 40.0226C54.721 39.6853 54.7187 39.3275 54.618 38.9915L46.9375 13.3446C46.8628 13.0821 46.7275 12.8409 46.5425 12.6402C46.3576 12.4395 46.1282 12.285 45.8727 12.1891C43.7027 11.2989 41.4587 10.6014 39.1664 10.1047C38.7259 10.0083 38.2653 10.0774 37.8725 10.2988C37.4797 10.5203 37.1822 10.8787 37.0367 11.3055L35.2469 16.7204M23.2164 41.2571L20.475 46.6946C20.2986 47.0654 19.9986 47.3632 19.6265 47.5368C19.2544 47.7105 18.8334 47.7491 18.4359 47.6462C12.8852 46.2868 8.08203 43.9305 4.59297 40.8946C4.32992 40.6625 4.1389 40.3599 4.04253 40.0226C3.94616 39.6853 3.94848 39.3275 4.04922 38.9915L11.7297 13.3446C11.8044 13.0821 11.9397 12.8409 12.1247 12.6402C12.3096 12.4395 12.539 12.285 12.7945 12.1891C14.9645 11.2989 17.2085 10.6014 19.5008 10.1047C19.9413 10.0083 20.4019 10.0774 20.7947 10.2988C21.1875 10.5203 21.485 10.8787 21.6305 11.3055L23.4203 16.7204" stroke="#4B465C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M17.1898 18.1251C21.119 16.8936 25.2161 16.2821 29.3336 16.3126C33.4511 16.2821 37.5482 16.8936 41.4773 18.1251M41.4773 39.8751C37.5482 41.1065 33.4511 41.718 29.3336 41.6876C25.2161 41.718 21.119 41.1065 17.1898 39.8751M35.4508 41.2571L38.1922 46.6946C38.3686 47.0654 38.6686 47.3632 39.0407 47.5368C39.4128 47.7105 39.8338 47.7491 40.2313 47.6462C45.782 46.2868 50.5852 43.9305 54.0742 40.8946C54.3373 40.6625 54.5283 40.3599 54.6247 40.0226C54.721 39.6853 54.7187 39.3275 54.618 38.9915L46.9375 13.3446C46.8628 13.0821 46.7275 12.8409 46.5425 12.6402C46.3576 12.4395 46.1282 12.285 45.8727 12.1891C43.7027 11.2989 41.4587 10.6014 39.1664 10.1047C38.7259 10.0083 38.2653 10.0774 37.8725 10.2988C37.4797 10.5203 37.1822 10.8787 37.0367 11.3055L35.2469 16.7204M23.2164 41.2571L20.475 46.6946C20.2986 47.0654 19.9986 47.3632 19.6265 47.5368C19.2544 47.7105 18.8334 47.7491 18.4359 47.6462C12.8852 46.2868 8.08203 43.9305 4.59297 40.8946C4.32992 40.6625 4.1389 40.3599 4.04253 40.0226C3.94616 39.6853 3.94848 39.3275 4.04922 38.9915L11.7297 13.3446C11.8044 13.0821 11.9397 12.8409 12.1247 12.6402C12.3096 12.4395 12.539 12.285 12.7945 12.1891C14.9645 11.2989 17.2085 10.6014 19.5008 10.1047C19.9413 10.0083 20.4019 10.0774 20.7947 10.2988C21.1875 10.5203 21.485 10.8787 21.6305 11.3055L23.4203 16.7204" stroke="white" stroke-opacity="0.2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.2 KiB |
8
public/images/svg/gift.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="58" height="58" viewBox="0 0 58 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.2689 8.56722C31.7876 9.05354 31.3688 9.84814 31.029 10.8704C30.6946 11.8767 30.4652 13.0152 30.31 14.1032C30.1553 15.1872 30.0776 16.197 30.0386 16.9371C30.0358 16.991 30.0332 17.0434 30.0307 17.0943C30.0816 17.0918 30.134 17.0892 30.1879 17.0864C30.928 17.0475 31.9378 16.9697 33.0218 16.815C34.1098 16.6598 35.2483 16.4304 36.2546 16.096C37.2769 15.7562 38.0715 15.3374 38.5578 14.8561C39.3907 14.0223 39.8587 12.8919 39.8587 11.7133C39.8587 10.5339 39.3901 9.4028 38.5562 8.56883C37.7222 7.73487 36.5911 7.26636 35.4117 7.26636C34.2331 7.26636 33.1027 7.73427 32.2689 8.56722ZM39.2633 15.5649L39.9704 16.272C41.1794 15.0629 41.8587 13.4231 41.8587 11.7133C41.8587 10.0035 41.1794 8.36365 39.9704 7.15462C38.7614 5.94559 37.1216 5.26636 35.4117 5.26636C33.7019 5.26636 32.0621 5.94559 30.853 7.15461L30.8499 7.15774C30.0518 7.96296 29.5111 9.09639 29.1311 10.2396C29.0855 10.3767 29.0418 10.5154 28.9999 10.6551C28.958 10.5154 28.9143 10.3767 28.8688 10.2396C28.4888 9.09639 27.9481 7.96296 27.1499 7.15774L27.1468 7.15462C25.9378 5.94559 24.298 5.26636 22.5882 5.26636C20.8783 5.26636 19.2385 5.94559 18.0295 7.15462C16.8205 8.36366 16.1412 10.0035 16.1412 11.7133C16.1412 13.4231 16.8205 15.0629 18.0295 16.272L18.7366 15.5649L18.0326 16.2751C18.3589 16.5985 18.7391 16.8797 19.152 17.125H9.0625C7.5092 17.125 6.25 18.3842 6.25 19.9375V27.1875C6.25 28.7408 7.5092 30 9.0625 30H9.875V45.3125C9.875 46.0584 10.1713 46.7738 10.6988 47.3012C11.2262 47.8287 11.9416 48.125 12.6875 48.125H29H45.3125C46.0584 48.125 46.7738 47.8287 47.3012 47.3012C47.8287 46.7738 48.125 46.0584 48.125 45.3125V30H48.9375C50.4908 30 51.75 28.7408 51.75 27.1875V19.9375C51.75 18.3842 50.4908 17.125 48.9375 17.125H38.8479C39.2608 16.8797 39.641 16.5985 39.9673 16.2751L39.2633 15.5649ZM9.0625 19.125C8.61377 19.125 8.25 19.4888 8.25 19.9375V27.1875C8.25 27.6362 8.61377 28 9.0625 28H10.875H28V19.125H9.0625ZM30 19.125V28H47.125H48.9375C49.3862 28 49.75 27.6362 49.75 27.1875V19.9375C49.75 19.4888 49.3862 19.125 48.9375 19.125H30ZM28 30H11.875V45.3125C11.875 45.528 11.9606 45.7347 12.113 45.887C12.2653 46.0394 12.472 46.125 12.6875 46.125H28V30ZM30 46.125V30H46.125V45.3125C46.125 45.528 46.0394 45.7347 45.887 45.887C45.7347 46.0394 45.528 46.125 45.3125 46.125H30ZM21.7452 16.096C20.723 15.7562 19.9284 15.3374 19.4421 14.8562C18.6091 14.0223 18.1412 12.8919 18.1412 11.7133C18.1412 10.5339 18.6097 9.4028 19.4437 8.56883C20.2777 7.73487 21.4088 7.26636 22.5882 7.26636C23.7668 7.26636 24.8972 7.73428 25.731 8.56725C26.2123 9.05357 26.6311 9.84816 26.9708 10.8704C27.3053 11.8767 27.5346 13.0152 27.6899 14.1032C27.8445 15.1872 27.9223 16.197 27.9613 16.9371C27.9641 16.991 27.9667 17.0434 27.9691 17.0943C27.9183 17.0918 27.8659 17.0892 27.812 17.0864C27.0719 17.0475 26.0621 16.9697 24.978 16.815C23.89 16.6598 22.7516 16.4304 21.7452 16.096Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.2689 8.56722C31.7876 9.05354 31.3688 9.84814 31.029 10.8704C30.6946 11.8767 30.4652 13.0152 30.31 14.1032C30.1553 15.1872 30.0776 16.197 30.0386 16.9371C30.0358 16.991 30.0332 17.0434 30.0307 17.0943C30.0816 17.0918 30.134 17.0892 30.1879 17.0864C30.928 17.0475 31.9378 16.9697 33.0218 16.815C34.1098 16.6598 35.2483 16.4304 36.2546 16.096C37.2769 15.7562 38.0715 15.3374 38.5578 14.8561C39.3907 14.0223 39.8587 12.8919 39.8587 11.7133C39.8587 10.5339 39.3901 9.4028 38.5562 8.56883C37.7222 7.73487 36.5911 7.26636 35.4117 7.26636C34.2331 7.26636 33.1027 7.73427 32.2689 8.56722ZM39.2633 15.5649L39.9704 16.272C41.1794 15.0629 41.8587 13.4231 41.8587 11.7133C41.8587 10.0035 41.1794 8.36365 39.9704 7.15462C38.7614 5.94559 37.1216 5.26636 35.4117 5.26636C33.7019 5.26636 32.0621 5.94559 30.853 7.15461L30.8499 7.15774C30.0518 7.96296 29.5111 9.09639 29.1311 10.2396C29.0855 10.3767 29.0418 10.5154 28.9999 10.6551C28.958 10.5154 28.9143 10.3767 28.8688 10.2396C28.4888 9.09639 27.9481 7.96296 27.1499 7.15774L27.1468 7.15462C25.9378 5.94559 24.298 5.26636 22.5882 5.26636C20.8783 5.26636 19.2385 5.94559 18.0295 7.15462C16.8205 8.36366 16.1412 10.0035 16.1412 11.7133C16.1412 13.4231 16.8205 15.0629 18.0295 16.272L18.7366 15.5649L18.0326 16.2751C18.3589 16.5985 18.7391 16.8797 19.152 17.125H9.0625C7.5092 17.125 6.25 18.3842 6.25 19.9375V27.1875C6.25 28.7408 7.5092 30 9.0625 30H9.875V45.3125C9.875 46.0584 10.1713 46.7738 10.6988 47.3012C11.2262 47.8287 11.9416 48.125 12.6875 48.125H29H45.3125C46.0584 48.125 46.7738 47.8287 47.3012 47.3012C47.8287 46.7738 48.125 46.0584 48.125 45.3125V30H48.9375C50.4908 30 51.75 28.7408 51.75 27.1875V19.9375C51.75 18.3842 50.4908 17.125 48.9375 17.125H38.8479C39.2608 16.8797 39.641 16.5985 39.9673 16.2751L39.2633 15.5649ZM9.0625 19.125C8.61377 19.125 8.25 19.4888 8.25 19.9375V27.1875C8.25 27.6362 8.61377 28 9.0625 28H10.875H28V19.125H9.0625ZM30 19.125V28H47.125H48.9375C49.3862 28 49.75 27.6362 49.75 27.1875V19.9375C49.75 19.4888 49.3862 19.125 48.9375 19.125H30ZM28 30H11.875V45.3125C11.875 45.528 11.9606 45.7347 12.113 45.887C12.2653 46.0394 12.472 46.125 12.6875 46.125H28V30ZM30 46.125V30H46.125V45.3125C46.125 45.528 46.0394 45.7347 45.887 45.887C45.7347 46.0394 45.528 46.125 45.3125 46.125H30ZM21.7452 16.096C20.723 15.7562 19.9284 15.3374 19.4421 14.8562C18.6091 14.0223 18.1412 12.8919 18.1412 11.7133C18.1412 10.5339 18.6097 9.4028 19.4437 8.56883C20.2777 7.73487 21.4088 7.26636 22.5882 7.26636C23.7668 7.26636 24.8972 7.73428 25.731 8.56725C26.2123 9.05357 26.6311 9.84816 26.9708 10.8704C27.3053 11.8767 27.5346 13.0152 27.6899 14.1032C27.8445 15.1872 27.9223 16.197 27.9613 16.9371C27.9641 16.991 27.9667 17.0434 27.9691 17.0943C27.9183 17.0918 27.8659 17.0892 27.812 17.0864C27.0719 17.0475 26.0621 16.9697 24.978 16.815C23.89 16.6598 22.7516 16.4304 21.7452 16.096Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path d="M47.125 29V45.3125C47.125 45.7932 46.934 46.2542 46.5941 46.5941C46.2542 46.934 45.7932 47.125 45.3125 47.125H12.6875C12.2068 47.125 11.7458 46.934 11.4059 46.5941C11.066 46.2542 10.875 45.7932 10.875 45.3125V29H47.125Z" fill="#4B465C"/>
|
||||||
|
<path d="M47.125 29V45.3125C47.125 45.7932 46.934 46.2542 46.5941 46.5941C46.2542 46.934 45.7932 47.125 45.3125 47.125H12.6875C12.2068 47.125 11.7458 46.934 11.4059 46.5941C11.066 46.2542 10.875 45.7932 10.875 45.3125V29H47.125Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.3 KiB |
8
public/images/svg/keyboard.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="1em" height="1em" viewBox="0 0 59 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path d="M50.9702 12.6875H7.69678C6.6332 12.6875 5.771 13.5497 5.771 14.6133V43.3867C5.771 44.4503 6.6332 45.3125 7.69678 45.3125H50.9702C52.0338 45.3125 52.896 44.4503 52.896 43.3867V14.6133C52.896 13.5497 52.0338 12.6875 50.9702 12.6875Z" fill="#4B465C"/>
|
||||||
|
<path d="M50.9702 12.6875H7.69678C6.6332 12.6875 5.771 13.5497 5.771 14.6133V43.3867C5.771 44.4503 6.6332 45.3125 7.69678 45.3125H50.9702C52.0338 45.3125 52.896 44.4503 52.896 43.3867V14.6133C52.896 13.5497 52.0338 12.6875 50.9702 12.6875Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.021 14.6133C7.021 14.2401 7.32355 13.9375 7.69678 13.9375H50.9702C51.3434 13.9375 51.646 14.2401 51.646 14.6133V43.3867C51.646 43.7599 51.3434 44.0625 50.9702 44.0625H7.69678C7.32355 44.0625 7.021 43.7599 7.021 43.3867V14.6133ZM7.69678 11.4375C5.94284 11.4375 4.521 12.8593 4.521 14.6133V43.3867C4.521 45.1407 5.94284 46.5625 7.69678 46.5625H50.9702C52.7242 46.5625 54.146 45.1407 54.146 43.3867V14.6133C54.146 12.8593 52.7242 11.4375 50.9702 11.4375H7.69678ZM13.021 20.75C12.4687 20.75 12.021 21.1977 12.021 21.75C12.021 22.3023 12.4687 22.75 13.021 22.75H45.646C46.1983 22.75 46.646 22.3023 46.646 21.75C46.646 21.1977 46.1983 20.75 45.646 20.75H13.021ZM13.021 28C12.4687 28 12.021 28.4477 12.021 29C12.021 29.5523 12.4687 30 13.021 30H45.646C46.1983 30 46.646 29.5523 46.646 29C46.646 28.4477 46.1983 28 45.646 28H13.021ZM12.021 36.25C12.021 35.6977 12.4687 35.25 13.021 35.25H14.8335C15.3858 35.25 15.8335 35.6977 15.8335 36.25C15.8335 36.8023 15.3858 37.25 14.8335 37.25H13.021C12.4687 37.25 12.021 36.8023 12.021 36.25ZM22.0835 35.25C21.5312 35.25 21.0835 35.6977 21.0835 36.25C21.0835 36.8023 21.5312 37.25 22.0835 37.25H36.5835C37.1358 37.25 37.5835 36.8023 37.5835 36.25C37.5835 35.6977 37.1358 35.25 36.5835 35.25H22.0835ZM42.8335 36.25C42.8335 35.6977 43.2812 35.25 43.8335 35.25H45.646C46.1983 35.25 46.646 35.6977 46.646 36.25C46.646 36.8023 46.1983 37.25 45.646 37.25H43.8335C43.2812 37.25 42.8335 36.8023 42.8335 36.25Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.021 14.6133C7.021 14.2401 7.32355 13.9375 7.69678 13.9375H50.9702C51.3434 13.9375 51.646 14.2401 51.646 14.6133V43.3867C51.646 43.7599 51.3434 44.0625 50.9702 44.0625H7.69678C7.32355 44.0625 7.021 43.7599 7.021 43.3867V14.6133ZM7.69678 11.4375C5.94284 11.4375 4.521 12.8593 4.521 14.6133V43.3867C4.521 45.1407 5.94284 46.5625 7.69678 46.5625H50.9702C52.7242 46.5625 54.146 45.1407 54.146 43.3867V14.6133C54.146 12.8593 52.7242 11.4375 50.9702 11.4375H7.69678ZM13.021 20.75C12.4687 20.75 12.021 21.1977 12.021 21.75C12.021 22.3023 12.4687 22.75 13.021 22.75H45.646C46.1983 22.75 46.646 22.3023 46.646 21.75C46.646 21.1977 46.1983 20.75 45.646 20.75H13.021ZM13.021 28C12.4687 28 12.021 28.4477 12.021 29C12.021 29.5523 12.4687 30 13.021 30H45.646C46.1983 30 46.646 29.5523 46.646 29C46.646 28.4477 46.1983 28 45.646 28H13.021ZM12.021 36.25C12.021 35.6977 12.4687 35.25 13.021 35.25H14.8335C15.3858 35.25 15.8335 35.6977 15.8335 36.25C15.8335 36.8023 15.3858 37.25 14.8335 37.25H13.021C12.4687 37.25 12.021 36.8023 12.021 36.25ZM22.0835 35.25C21.5312 35.25 21.0835 35.6977 21.0835 36.25C21.0835 36.8023 21.5312 37.25 22.0835 37.25H36.5835C37.1358 37.25 37.5835 36.8023 37.5835 36.25C37.5835 35.6977 37.1358 35.25 36.5835 35.25H22.0835ZM42.8335 36.25C42.8335 35.6977 43.2812 35.25 43.8335 35.25H45.646C46.1983 35.25 46.646 35.6977 46.646 36.25C46.646 36.8023 46.1983 37.25 45.646 37.25H43.8335C43.2812 37.25 42.8335 36.8023 42.8335 36.25Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
8
public/images/svg/laptop.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="1em" height="1em" viewBox="0 0 59 58" fill="#4B465C" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path d="M9.72925 39.875V16.3125C9.72925 15.3511 10.1112 14.4291 10.791 13.7492C11.4708 13.0694 12.3928 12.6875 13.3542 12.6875H45.9792C46.9407 12.6875 47.8627 13.0694 48.5425 13.7492C49.2223 14.4291 49.6042 15.3511 49.6042 16.3125V39.875H9.72925Z" fill="#4B465C"/>
|
||||||
|
<path d="M9.72925 39.875V16.3125C9.72925 15.3511 10.1112 14.4291 10.791 13.7492C11.4708 13.0694 12.3928 12.6875 13.3542 12.6875H45.9792C46.9407 12.6875 47.8627 13.0694 48.5425 13.7492C49.2223 14.4291 49.6042 15.3511 49.6042 16.3125V39.875H9.72925Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
<path d="M8.72925 39.875C8.72925 40.4273 9.17696 40.875 9.72925 40.875C10.2815 40.875 10.7292 40.4273 10.7292 39.875H8.72925ZM13.3542 12.6875V11.6875V12.6875ZM45.9792 12.6875V11.6875V12.6875ZM48.6042 39.875C48.6042 40.4273 49.052 40.875 49.6042 40.875C50.1565 40.875 50.6042 40.4273 50.6042 39.875H48.6042ZM6.10425 39.875V38.875C5.55196 38.875 5.10425 39.3227 5.10425 39.875H6.10425ZM53.2292 39.875H54.2292C54.2292 39.3227 53.7815 38.875 53.2292 38.875V39.875ZM6.10425 43.5H5.10425H6.10425ZM33.2917 20.9375C33.844 20.9375 34.2917 20.4898 34.2917 19.9375C34.2917 19.3852 33.844 18.9375 33.2917 18.9375V20.9375ZM26.0417 18.9375C25.4895 18.9375 25.0417 19.3852 25.0417 19.9375C25.0417 20.4898 25.4895 20.9375 26.0417 20.9375V18.9375ZM10.7292 39.875V16.3125H8.72925V39.875H10.7292ZM10.7292 16.3125C10.7292 15.6163 11.0058 14.9486 11.4981 14.4563L10.0839 13.0421C9.21652 13.9095 8.72925 15.0859 8.72925 16.3125H10.7292ZM11.4981 14.4563C11.9904 13.9641 12.6581 13.6875 13.3542 13.6875L13.3542 11.6875C12.1276 11.6875 10.9512 12.1748 10.0839 13.0421L11.4981 14.4563ZM13.3542 13.6875H45.9792V11.6875H13.3542V13.6875ZM45.9792 13.6875C46.6754 13.6875 47.3431 13.9641 47.8354 14.4563L49.2496 13.0421C48.3823 12.1748 47.2059 11.6875 45.9792 11.6875V13.6875ZM47.8354 14.4563C48.3277 14.9486 48.6042 15.6163 48.6042 16.3125H50.6042C50.6042 15.0859 50.117 13.9095 49.2496 13.0421L47.8354 14.4563ZM48.6042 16.3125V39.875H50.6042V16.3125H48.6042ZM6.10425 40.875H53.2292V38.875H6.10425V40.875ZM52.2292 39.875V43.5H54.2292V39.875H52.2292ZM52.2292 43.5C52.2292 44.1962 51.9527 44.8639 51.4604 45.3562L52.8746 46.7704C53.742 45.903 54.2292 44.7266 54.2292 43.5H52.2292ZM51.4604 45.3562C50.9681 45.8484 50.3004 46.125 49.6042 46.125V48.125C50.8309 48.125 52.0073 47.6377 52.8746 46.7704L51.4604 45.3562ZM49.6042 46.125H9.72925V48.125H49.6042V46.125ZM9.72925 46.125C9.03305 46.125 8.36538 45.8484 7.87309 45.3562L6.45888 46.7704C7.32623 47.6377 8.50262 48.125 9.72925 48.125V46.125ZM7.87309 45.3562C7.38081 44.8639 7.10425 44.1962 7.10425 43.5H5.10425C5.10425 44.7266 5.59152 45.903 6.45888 46.7704L7.87309 45.3562ZM7.10425 43.5V39.875H5.10425V43.5H7.10425ZM33.2917 18.9375H26.0417V20.9375H33.2917V18.9375Z" fill="#4B465C"/>
|
||||||
|
<path d="M8.72925 39.875C8.72925 40.4273 9.17696 40.875 9.72925 40.875C10.2815 40.875 10.7292 40.4273 10.7292 39.875H8.72925ZM13.3542 12.6875V11.6875V12.6875ZM45.9792 12.6875V11.6875V12.6875ZM48.6042 39.875C48.6042 40.4273 49.052 40.875 49.6042 40.875C50.1565 40.875 50.6042 40.4273 50.6042 39.875H48.6042ZM6.10425 39.875V38.875C5.55196 38.875 5.10425 39.3227 5.10425 39.875H6.10425ZM53.2292 39.875H54.2292C54.2292 39.3227 53.7815 38.875 53.2292 38.875V39.875ZM6.10425 43.5H5.10425H6.10425ZM33.2917 20.9375C33.844 20.9375 34.2917 20.4898 34.2917 19.9375C34.2917 19.3852 33.844 18.9375 33.2917 18.9375V20.9375ZM26.0417 18.9375C25.4895 18.9375 25.0417 19.3852 25.0417 19.9375C25.0417 20.4898 25.4895 20.9375 26.0417 20.9375V18.9375ZM10.7292 39.875V16.3125H8.72925V39.875H10.7292ZM10.7292 16.3125C10.7292 15.6163 11.0058 14.9486 11.4981 14.4563L10.0839 13.0421C9.21652 13.9095 8.72925 15.0859 8.72925 16.3125H10.7292ZM11.4981 14.4563C11.9904 13.9641 12.6581 13.6875 13.3542 13.6875L13.3542 11.6875C12.1276 11.6875 10.9512 12.1748 10.0839 13.0421L11.4981 14.4563ZM13.3542 13.6875H45.9792V11.6875H13.3542V13.6875ZM45.9792 13.6875C46.6754 13.6875 47.3431 13.9641 47.8354 14.4563L49.2496 13.0421C48.3823 12.1748 47.2059 11.6875 45.9792 11.6875V13.6875ZM47.8354 14.4563C48.3277 14.9486 48.6042 15.6163 48.6042 16.3125H50.6042C50.6042 15.0859 50.117 13.9095 49.2496 13.0421L47.8354 14.4563ZM48.6042 16.3125V39.875H50.6042V16.3125H48.6042ZM6.10425 40.875H53.2292V38.875H6.10425V40.875ZM52.2292 39.875V43.5H54.2292V39.875H52.2292ZM52.2292 43.5C52.2292 44.1962 51.9527 44.8639 51.4604 45.3562L52.8746 46.7704C53.742 45.903 54.2292 44.7266 54.2292 43.5H52.2292ZM51.4604 45.3562C50.9681 45.8484 50.3004 46.125 49.6042 46.125V48.125C50.8309 48.125 52.0073 47.6377 52.8746 46.7704L51.4604 45.3562ZM49.6042 46.125H9.72925V48.125H49.6042V46.125ZM9.72925 46.125C9.03305 46.125 8.36538 45.8484 7.87309 45.3562L6.45888 46.7704C7.32623 47.6377 8.50262 48.125 9.72925 48.125V46.125ZM7.87309 45.3562C7.38081 44.8639 7.10425 44.1962 7.10425 43.5H5.10425C5.10425 44.7266 5.59152 45.903 6.45888 46.7704L7.87309 45.3562ZM7.10425 43.5V39.875H5.10425V43.5H7.10425ZM33.2917 18.9375H26.0417V20.9375H33.2917V18.9375Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.0 KiB |
8
public/images/svg/lightbulb.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="1em" height="1em" viewBox="0 0 58 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path d="M17.8304 37.8359C15.6726 36.1581 13.925 34.0112 12.7199 31.5579C11.5148 29.1045 10.8839 26.4091 10.8749 23.6757C10.8296 13.8429 18.7367 5.66403 28.5695 5.43747C32.375 5.34725 36.1123 6.45746 39.2514 8.61062C42.3904 10.7638 44.7719 13.8506 46.0581 17.4333C47.3442 21.016 47.4698 24.9127 46.4169 28.5707C45.364 32.2288 43.1861 35.4625 40.1921 37.8132C39.5308 38.3245 38.995 38.9802 38.6259 39.7302C38.2568 40.4802 38.0641 41.3047 38.0625 42.1406V43.5C38.0625 43.9807 37.8715 44.4417 37.5316 44.7816C37.1917 45.1215 36.7307 45.3125 36.25 45.3125H21.7499C21.2692 45.3125 20.8082 45.1215 20.4683 44.7816C20.1284 44.4417 19.9374 43.9807 19.9374 43.5V42.1406C19.9318 41.3109 19.7394 40.4932 19.3747 39.748C19.0099 39.0028 18.4821 38.3493 17.8304 37.8359Z" fill="#4B465C"/>
|
||||||
|
<path d="M17.8304 37.8359C15.6726 36.1581 13.925 34.0112 12.7199 31.5579C11.5148 29.1045 10.8839 26.4091 10.8749 23.6757C10.8296 13.8429 18.7367 5.66403 28.5695 5.43747C32.375 5.34725 36.1123 6.45746 39.2514 8.61062C42.3904 10.7638 44.7719 13.8506 46.0581 17.4333C47.3442 21.016 47.4698 24.9127 46.4169 28.5707C45.364 32.2288 43.1861 35.4625 40.1921 37.8132C39.5308 38.3245 38.995 38.9802 38.6259 39.7302C38.2568 40.4802 38.0641 41.3047 38.0625 42.1406V43.5C38.0625 43.9807 37.8715 44.4417 37.5316 44.7816C37.1917 45.1215 36.7307 45.3125 36.25 45.3125H21.7499C21.2692 45.3125 20.8082 45.1215 20.4683 44.7816C20.1284 44.4417 19.9374 43.9807 19.9374 43.5V42.1406C19.9318 41.3109 19.7394 40.4932 19.3747 39.748C19.0099 39.0028 18.4821 38.3493 17.8304 37.8359Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6857 9.43527C35.7198 7.4009 32.1887 6.35195 28.5932 6.43719L28.5925 6.4372C28.3515 6.44275 28.1116 6.45338 27.8731 6.46896L28.5464 4.43773C32.5617 4.34269 36.5049 5.51414 39.817 7.78597C43.1293 10.0579 45.6422 13.3151 46.9993 17.0954C48.3564 20.8758 48.4889 24.9875 47.3779 28.8473C46.2669 32.7072 43.9688 36.1193 40.8097 38.5998L40.8037 38.6045L40.8037 38.6044C40.263 39.0224 39.8249 39.5585 39.5232 40.1717C39.2215 40.7847 39.0639 41.4585 39.0625 42.1416V42.1425V43.5C39.0625 44.2459 38.7661 44.9613 38.2387 45.4887C37.7112 46.0162 36.9959 46.3125 36.25 46.3125H21.75C21.004 46.3125 20.2887 46.0162 19.7612 45.4887C19.2338 44.9613 18.9375 44.2459 18.9375 43.5V42.1441C18.9323 41.4657 18.7748 40.7971 18.4765 40.1877C18.1782 39.5781 17.7466 39.0434 17.2138 38.6231L17.8866 36.5936C18.069 36.7483 18.255 36.8993 18.4442 37.0465L17.8304 37.836L18.4492 37.0504C19.2189 37.6567 19.8421 38.4284 20.2729 39.3084C20.7036 40.1884 20.9307 41.154 20.9374 42.1338L20.9375 42.1406L20.9375 43.5C20.9375 43.7155 21.0231 43.9221 21.1754 44.0745C21.3278 44.2269 21.5345 44.3125 21.75 44.3125H36.25C36.4654 44.3125 36.6721 44.2269 36.8245 44.0745C36.9768 43.9221 37.0625 43.7155 37.0625 43.5V42.1406V42.1387C37.0644 41.1503 37.2923 40.1754 37.7287 39.2886C38.1646 38.4029 38.7969 37.6285 39.5775 37.0244C42.4048 34.8035 44.4614 31.7492 45.4559 28.2941C46.4507 24.8379 46.3321 21.1562 45.1169 17.7712C43.9017 14.3862 41.6516 11.4696 38.6857 9.43527ZM17.8865 36.5936L17.8866 36.5936L27.8731 6.46896L27.8724 6.469L28.5458 4.43775C18.1651 4.67729 9.8275 13.3058 9.87496 23.6797C9.88451 26.5645 10.5504 29.4094 11.8223 31.9987C13.0938 34.5872 14.9375 36.8525 17.2138 38.6231L17.8865 36.5936ZM17.8865 36.5936C16.1041 35.0827 14.6499 33.2189 13.6175 31.117C12.4793 28.7998 11.8834 26.254 11.8749 23.6725L11.8749 23.6711C11.8332 14.6214 18.9246 7.05389 27.8724 6.469L17.8865 36.5936ZM18.9376 52.5625C18.9376 52.0102 19.3853 51.5625 19.9376 51.5625H38.0626C38.6149 51.5625 39.0626 52.0102 39.0626 52.5625C39.0626 53.1148 38.6149 53.5625 38.0626 53.5625H19.9376C19.3853 53.5625 18.9376 53.1148 18.9376 52.5625ZM31.0024 11.8828C30.4579 11.7905 29.9416 12.1571 29.8493 12.7016C29.757 13.2461 30.1236 13.7624 30.6681 13.8547C32.6793 14.1956 34.535 15.1524 35.9792 16.5929C37.4235 18.0334 38.385 19.8867 38.731 21.897C38.8247 22.4413 39.3419 22.8066 39.8862 22.7129C40.4304 22.6192 40.7957 22.102 40.702 21.5577C40.2857 19.1394 39.129 16.9098 37.3916 15.1769C35.6543 13.4439 33.4218 12.293 31.0024 11.8828Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6857 9.43527C35.7198 7.4009 32.1887 6.35195 28.5932 6.43719L28.5925 6.4372C28.3515 6.44275 28.1116 6.45338 27.8731 6.46896L28.5464 4.43773C32.5617 4.34269 36.5049 5.51414 39.817 7.78597C43.1293 10.0579 45.6422 13.3151 46.9993 17.0954C48.3564 20.8758 48.4889 24.9875 47.3779 28.8473C46.2669 32.7072 43.9688 36.1193 40.8097 38.5998L40.8037 38.6045L40.8037 38.6044C40.263 39.0224 39.8249 39.5585 39.5232 40.1717C39.2215 40.7847 39.0639 41.4585 39.0625 42.1416V42.1425V43.5C39.0625 44.2459 38.7661 44.9613 38.2387 45.4887C37.7112 46.0162 36.9959 46.3125 36.25 46.3125H21.75C21.004 46.3125 20.2887 46.0162 19.7612 45.4887C19.2338 44.9613 18.9375 44.2459 18.9375 43.5V42.1441C18.9323 41.4657 18.7748 40.7971 18.4765 40.1877C18.1782 39.5781 17.7466 39.0434 17.2138 38.6231L17.8866 36.5936C18.069 36.7483 18.255 36.8993 18.4442 37.0465L17.8304 37.836L18.4492 37.0504C19.2189 37.6567 19.8421 38.4284 20.2729 39.3084C20.7036 40.1884 20.9307 41.154 20.9374 42.1338L20.9375 42.1406L20.9375 43.5C20.9375 43.7155 21.0231 43.9221 21.1754 44.0745C21.3278 44.2269 21.5345 44.3125 21.75 44.3125H36.25C36.4654 44.3125 36.6721 44.2269 36.8245 44.0745C36.9768 43.9221 37.0625 43.7155 37.0625 43.5V42.1406V42.1387C37.0644 41.1503 37.2923 40.1754 37.7287 39.2886C38.1646 38.4029 38.7969 37.6285 39.5775 37.0244C42.4048 34.8035 44.4614 31.7492 45.4559 28.2941C46.4507 24.8379 46.3321 21.1562 45.1169 17.7712C43.9017 14.3862 41.6516 11.4696 38.6857 9.43527ZM17.8865 36.5936L17.8866 36.5936L27.8731 6.46896L27.8724 6.469L28.5458 4.43775C18.1651 4.67729 9.8275 13.3058 9.87496 23.6797C9.88451 26.5645 10.5504 29.4094 11.8223 31.9987C13.0938 34.5872 14.9375 36.8525 17.2138 38.6231L17.8865 36.5936ZM17.8865 36.5936C16.1041 35.0827 14.6499 33.2189 13.6175 31.117C12.4793 28.7998 11.8834 26.254 11.8749 23.6725L11.8749 23.6711C11.8332 14.6214 18.9246 7.05389 27.8724 6.469L17.8865 36.5936ZM18.9376 52.5625C18.9376 52.0102 19.3853 51.5625 19.9376 51.5625H38.0626C38.6149 51.5625 39.0626 52.0102 39.0626 52.5625C39.0626 53.1148 38.6149 53.5625 38.0626 53.5625H19.9376C19.3853 53.5625 18.9376 53.1148 18.9376 52.5625ZM31.0024 11.8828C30.4579 11.7905 29.9416 12.1571 29.8493 12.7016C29.757 13.2461 30.1236 13.7624 30.6681 13.8547C32.6793 14.1956 34.535 15.1524 35.9792 16.5929C37.4235 18.0334 38.385 19.8867 38.731 21.897C38.8247 22.4413 39.3419 22.8066 39.8862 22.7129C40.4304 22.6192 40.7957 22.102 40.702 21.5577C40.2857 19.1394 39.129 16.9098 37.3916 15.1769C35.6543 13.4439 33.4218 12.293 31.0024 11.8828Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.6 KiB |
8
public/images/svg/rocket.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="1em" height="1em" viewBox="0 0 59 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.2">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.9019 33.6218L41.7878 25.0804C42.0597 30.314 40.7683 36.4086 36.7808 43.364L43.5777 48.8015C43.8194 48.9935 44.1061 49.1205 44.4106 49.1706C44.7151 49.2207 45.0274 49.1922 45.3178 49.0879C45.6083 48.9835 45.8673 48.8067 46.0702 48.5742C46.2732 48.3417 46.4134 48.0612 46.4777 47.7593L49.2644 35.1625C49.3316 34.8954 49.3337 34.6161 49.2706 34.348C49.2076 34.08 49.0811 33.8309 48.9019 33.6218ZM10.2956 33.7578L17.4097 25.239C17.1378 30.4726 18.4292 36.5672 22.4167 43.5L15.6198 48.9375C15.3797 49.1294 15.0947 49.257 14.7916 49.3084C14.4885 49.3598 14.1773 49.3333 13.8873 49.2314C13.5973 49.1294 13.338 48.9554 13.1338 48.7256C12.9295 48.4958 12.7871 48.2179 12.7198 47.9179L9.93313 35.2984C9.86594 35.0313 9.8638 34.7521 9.92688 34.484C9.98995 34.2159 10.1164 33.9669 10.2956 33.7578Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.9019 33.6218L41.7878 25.0804C42.0597 30.314 40.7683 36.4086 36.7808 43.364L43.5777 48.8015C43.8194 48.9935 44.1061 49.1205 44.4106 49.1706C44.7151 49.2207 45.0274 49.1922 45.3178 49.0879C45.6083 48.9835 45.8673 48.8067 46.0702 48.5742C46.2732 48.3417 46.4134 48.0612 46.4777 47.7593L49.2644 35.1625C49.3316 34.8954 49.3337 34.6161 49.2706 34.348C49.2076 34.08 49.0811 33.8309 48.9019 33.6218ZM10.2956 33.7578L17.4097 25.239C17.1378 30.4726 18.4292 36.5672 22.4167 43.5L15.6198 48.9375C15.3797 49.1294 15.0947 49.257 14.7916 49.3084C14.4885 49.3598 14.1773 49.3333 13.8873 49.2314C13.5973 49.1294 13.338 48.9554 13.1338 48.7256C12.9295 48.4958 12.7871 48.2179 12.7198 47.9179L9.93313 35.2984C9.86594 35.0313 9.8638 34.7521 9.92688 34.484C9.98995 34.2159 10.1164 33.9669 10.2956 33.7578Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</g>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.9017 3.71102C28.3979 3.30011 29.0221 3.07513 29.6666 3.07513C30.3127 3.07513 30.9383 3.30117 31.435 3.71394C33.6315 5.50224 38.386 9.93871 41.0105 16.7606C41.9219 19.1296 42.5713 21.7739 42.7735 24.6785L49.8022 33.113C50.0828 33.4423 50.2809 33.8338 50.38 34.255C50.4785 34.6735 50.4764 35.1093 50.374 35.5267L47.5901 48.1336L47.5894 48.1367C47.485 48.6022 47.264 49.0335 46.9471 49.39C46.6302 49.7465 46.2278 50.0166 45.7778 50.1748C45.3278 50.333 44.8449 50.3742 44.3746 50.2944C43.9043 50.2146 43.4621 50.0165 43.0894 49.7188L43.0889 49.7184L36.566 44.5H22.7675L16.2445 49.7184L16.2441 49.7188C15.8714 50.0165 15.4291 50.2146 14.9588 50.2944C14.4885 50.3742 14.0057 50.333 13.5556 50.1748C13.1056 50.0166 12.7032 49.7465 12.3863 49.39C12.0694 49.0335 11.8484 48.6022 11.7441 48.1367L11.7434 48.1336L8.95943 35.5267C8.85707 35.1093 8.85499 34.6735 8.95346 34.255C9.05262 33.8335 9.25088 33.4419 9.53173 33.1125L16.4274 24.8553C16.6112 21.877 17.2734 19.1695 18.2135 16.7491C20.8639 9.92541 25.6801 5.4896 27.9017 3.71102ZM40.8041 25.2385C40.7893 25.1573 40.7846 25.0748 40.7899 24.993C40.6159 22.2127 40.0004 19.7051 39.1438 17.4787C36.6951 11.1136 32.2331 6.94203 30.1682 5.26158L30.1583 5.25355L30.1584 5.25349C30.0204 5.13826 29.8464 5.07513 29.6666 5.07513C29.4869 5.07513 29.3128 5.13826 29.1748 5.25349L29.1585 5.26684C27.0721 6.93594 22.5504 11.1072 20.0778 17.4732C19.1887 19.7623 18.5587 22.3492 18.4096 25.2244C18.4102 25.2674 18.4081 25.3106 18.4032 25.3535C18.1745 30.253 19.3435 35.9842 22.9982 42.5H36.3292C39.938 35.9325 41.0647 30.1631 40.8041 25.2385ZM48.2696 34.398L42.8122 27.8492C42.6094 32.4348 41.2748 37.5835 38.2005 43.2464L44.3378 48.1563C44.4455 48.2423 44.5733 48.2995 44.7091 48.3226C44.845 48.3456 44.9845 48.3337 45.1145 48.288C45.2445 48.2423 45.3607 48.1643 45.4523 48.0613C45.5436 47.9586 45.6073 47.8344 45.6376 47.7004L45.6378 47.6992L48.4239 35.0828L48.4272 35.0682L48.4305 35.0545C48.4587 34.9425 48.4596 34.8255 48.4332 34.7131C48.4067 34.6007 48.3537 34.4963 48.2786 34.4086L48.2695 34.3981L48.2696 34.398ZM16.4139 27.9916L11.0632 34.3988L11.0549 34.4087L11.0549 34.4086C10.9798 34.4963 10.9267 34.6007 10.9003 34.7131C10.8738 34.8255 10.8747 34.9425 10.9029 35.0545C10.9053 35.0639 10.9075 35.0734 10.9096 35.0828L13.6956 47.6992L13.6959 47.7005C13.7262 47.8345 13.7899 47.9586 13.8812 48.0613C13.9727 48.1643 14.089 48.2423 14.219 48.288C14.349 48.3337 14.4885 48.3456 14.6243 48.3226C14.7602 48.2995 14.888 48.2423 14.9956 48.1563L21.1271 43.2511C18.0233 37.6471 16.6517 32.5443 16.4139 27.9916ZM25.0417 50.75C25.0417 50.1977 25.4895 49.75 26.0417 49.75H33.2917C33.844 49.75 34.2917 50.1977 34.2917 50.75C34.2917 51.3023 33.844 51.75 33.2917 51.75H26.0417C25.4895 51.75 25.0417 51.3023 25.0417 50.75ZM32.3855 21.75C32.3855 23.2515 31.1683 24.4688 29.6667 24.4688C28.1652 24.4688 26.948 23.2515 26.948 21.75C26.948 20.2485 28.1652 19.0313 29.6667 19.0313C31.1683 19.0313 32.3855 20.2485 32.3855 21.75Z" fill="#4B465C"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.9017 3.71102C28.3979 3.30011 29.0221 3.07513 29.6666 3.07513C30.3127 3.07513 30.9383 3.30117 31.435 3.71394C33.6315 5.50224 38.386 9.93871 41.0105 16.7606C41.9219 19.1296 42.5713 21.7739 42.7735 24.6785L49.8022 33.113C50.0828 33.4423 50.2809 33.8338 50.38 34.255C50.4785 34.6735 50.4764 35.1093 50.374 35.5267L47.5901 48.1336L47.5894 48.1367C47.485 48.6022 47.264 49.0335 46.9471 49.39C46.6302 49.7465 46.2278 50.0166 45.7778 50.1748C45.3278 50.333 44.8449 50.3742 44.3746 50.2944C43.9043 50.2146 43.4621 50.0165 43.0894 49.7188L43.0889 49.7184L36.566 44.5H22.7675L16.2445 49.7184L16.2441 49.7188C15.8714 50.0165 15.4291 50.2146 14.9588 50.2944C14.4885 50.3742 14.0057 50.333 13.5556 50.1748C13.1056 50.0166 12.7032 49.7465 12.3863 49.39C12.0694 49.0335 11.8484 48.6022 11.7441 48.1367L11.7434 48.1336L8.95943 35.5267C8.85707 35.1093 8.85499 34.6735 8.95346 34.255C9.05262 33.8335 9.25088 33.4419 9.53173 33.1125L16.4274 24.8553C16.6112 21.877 17.2734 19.1695 18.2135 16.7491C20.8639 9.92541 25.6801 5.4896 27.9017 3.71102ZM40.8041 25.2385C40.7893 25.1573 40.7846 25.0748 40.7899 24.993C40.6159 22.2127 40.0004 19.7051 39.1438 17.4787C36.6951 11.1136 32.2331 6.94203 30.1682 5.26158L30.1583 5.25355L30.1584 5.25349C30.0204 5.13826 29.8464 5.07513 29.6666 5.07513C29.4869 5.07513 29.3128 5.13826 29.1748 5.25349L29.1585 5.26684C27.0721 6.93594 22.5504 11.1072 20.0778 17.4732C19.1887 19.7623 18.5587 22.3492 18.4096 25.2244C18.4102 25.2674 18.4081 25.3106 18.4032 25.3535C18.1745 30.253 19.3435 35.9842 22.9982 42.5H36.3292C39.938 35.9325 41.0647 30.1631 40.8041 25.2385ZM48.2696 34.398L42.8122 27.8492C42.6094 32.4348 41.2748 37.5835 38.2005 43.2464L44.3378 48.1563C44.4455 48.2423 44.5733 48.2995 44.7091 48.3226C44.845 48.3456 44.9845 48.3337 45.1145 48.288C45.2445 48.2423 45.3607 48.1643 45.4523 48.0613C45.5436 47.9586 45.6073 47.8344 45.6376 47.7004L45.6378 47.6992L48.4239 35.0828L48.4272 35.0682L48.4305 35.0545C48.4587 34.9425 48.4596 34.8255 48.4332 34.7131C48.4067 34.6007 48.3537 34.4963 48.2786 34.4086L48.2695 34.3981L48.2696 34.398ZM16.4139 27.9916L11.0632 34.3988L11.0549 34.4087L11.0549 34.4086C10.9798 34.4963 10.9267 34.6007 10.9003 34.7131C10.8738 34.8255 10.8747 34.9425 10.9029 35.0545C10.9053 35.0639 10.9075 35.0734 10.9096 35.0828L13.6956 47.6992L13.6959 47.7005C13.7262 47.8345 13.7899 47.9586 13.8812 48.0613C13.9727 48.1643 14.089 48.2423 14.219 48.288C14.349 48.3337 14.4885 48.3456 14.6243 48.3226C14.7602 48.2995 14.888 48.2423 14.9956 48.1563L21.1271 43.2511C18.0233 37.6471 16.6517 32.5443 16.4139 27.9916ZM25.0417 50.75C25.0417 50.1977 25.4895 49.75 26.0417 49.75H33.2917C33.844 49.75 34.2917 50.1977 34.2917 50.75C34.2917 51.3023 33.844 51.75 33.2917 51.75H26.0417C25.4895 51.75 25.0417 51.3023 25.0417 50.75ZM32.3855 21.75C32.3855 23.2515 31.1683 24.4688 29.6667 24.4688C28.1652 24.4688 26.948 23.2515 26.948 21.75C26.948 20.2485 28.1652 19.0313 29.6667 19.0313C31.1683 19.0313 32.3855 20.2485 32.3855 21.75Z" fill="white" fill-opacity="0.2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.7 KiB |
78
public/loader.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
overflow: hidden scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading-bg {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--initial-loader-bg, #fff);
|
||||||
|
block-size: 100%;
|
||||||
|
gap: 1rem 0;
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 55px;
|
||||||
|
inline-size: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading .effect-1,
|
||||||
|
.loading .effect-2,
|
||||||
|
.loading .effect-3 {
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 100%;
|
||||||
|
border-inline-start: 3px solid var(--initial-loader-color, #eee);
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading .effect-1 {
|
||||||
|
animation: rotate 1s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading .effect-2 {
|
||||||
|
animation: rotate-opacity 1s ease infinite 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading .effect-3 {
|
||||||
|
animation: rotate-opacity 1s ease infinite 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading .effects {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate-opacity {
|
||||||
|
0% {
|
||||||
|
opacity: 0.1;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
284
public/mockServiceWorker.js
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* tslint:disable */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock Service Worker.
|
||||||
|
* @see https://github.com/mswjs/msw
|
||||||
|
* - Please do NOT modify this file.
|
||||||
|
* - Please do NOT serve this file on production.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const PACKAGE_VERSION = '2.3.4'
|
||||||
|
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
|
||||||
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
||||||
|
const activeClientIds = new Set()
|
||||||
|
|
||||||
|
self.addEventListener('install', function () {
|
||||||
|
self.skipWaiting()
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener('activate', function (event) {
|
||||||
|
event.waitUntil(self.clients.claim())
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener('message', async function (event) {
|
||||||
|
const clientId = event.source.id
|
||||||
|
|
||||||
|
if (!clientId || !self.clients) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = await self.clients.get(clientId)
|
||||||
|
|
||||||
|
if (!client) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const allClients = await self.clients.matchAll({
|
||||||
|
type: 'window',
|
||||||
|
})
|
||||||
|
|
||||||
|
switch (event.data) {
|
||||||
|
case 'KEEPALIVE_REQUEST': {
|
||||||
|
sendToClient(client, {
|
||||||
|
type: 'KEEPALIVE_RESPONSE',
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'INTEGRITY_CHECK_REQUEST': {
|
||||||
|
sendToClient(client, {
|
||||||
|
type: 'INTEGRITY_CHECK_RESPONSE',
|
||||||
|
payload: {
|
||||||
|
packageVersion: PACKAGE_VERSION,
|
||||||
|
checksum: INTEGRITY_CHECKSUM,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'MOCK_ACTIVATE': {
|
||||||
|
activeClientIds.add(clientId)
|
||||||
|
|
||||||
|
sendToClient(client, {
|
||||||
|
type: 'MOCKING_ENABLED',
|
||||||
|
payload: true,
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'MOCK_DEACTIVATE': {
|
||||||
|
activeClientIds.delete(clientId)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'CLIENT_CLOSED': {
|
||||||
|
activeClientIds.delete(clientId)
|
||||||
|
|
||||||
|
const remainingClients = allClients.filter((client) => {
|
||||||
|
return client.id !== clientId
|
||||||
|
})
|
||||||
|
|
||||||
|
// Unregister itself when there are no more clients
|
||||||
|
if (remainingClients.length === 0) {
|
||||||
|
self.registration.unregister()
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener('fetch', function (event) {
|
||||||
|
const { request } = event
|
||||||
|
|
||||||
|
// Bypass navigation requests.
|
||||||
|
if (request.mode === 'navigate') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opening the DevTools triggers the "only-if-cached" request
|
||||||
|
// that cannot be handled by the worker. Bypass such requests.
|
||||||
|
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass all requests when there are no active clients.
|
||||||
|
// Prevents the self-unregistered worked from handling requests
|
||||||
|
// after it's been deleted (still remains active until the next reload).
|
||||||
|
if (activeClientIds.size === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate unique request ID.
|
||||||
|
const requestId = crypto.randomUUID()
|
||||||
|
event.respondWith(handleRequest(event, requestId))
|
||||||
|
})
|
||||||
|
|
||||||
|
async function handleRequest(event, requestId) {
|
||||||
|
const client = await resolveMainClient(event)
|
||||||
|
const response = await getResponse(event, client, requestId)
|
||||||
|
|
||||||
|
// Send back the response clone for the "response:*" life-cycle events.
|
||||||
|
// Ensure MSW is active and ready to handle the message, otherwise
|
||||||
|
// this message will pend indefinitely.
|
||||||
|
if (client && activeClientIds.has(client.id)) {
|
||||||
|
;(async function () {
|
||||||
|
const responseClone = response.clone()
|
||||||
|
|
||||||
|
sendToClient(
|
||||||
|
client,
|
||||||
|
{
|
||||||
|
type: 'RESPONSE',
|
||||||
|
payload: {
|
||||||
|
requestId,
|
||||||
|
isMockedResponse: IS_MOCKED_RESPONSE in response,
|
||||||
|
type: responseClone.type,
|
||||||
|
status: responseClone.status,
|
||||||
|
statusText: responseClone.statusText,
|
||||||
|
body: responseClone.body,
|
||||||
|
headers: Object.fromEntries(responseClone.headers.entries()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[responseClone.body],
|
||||||
|
)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the main client for the given event.
|
||||||
|
// Client that issues a request doesn't necessarily equal the client
|
||||||
|
// that registered the worker. It's with the latter the worker should
|
||||||
|
// communicate with during the response resolving phase.
|
||||||
|
async function resolveMainClient(event) {
|
||||||
|
const client = await self.clients.get(event.clientId)
|
||||||
|
|
||||||
|
if (client?.frameType === 'top-level') {
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
const allClients = await self.clients.matchAll({
|
||||||
|
type: 'window',
|
||||||
|
})
|
||||||
|
|
||||||
|
return allClients
|
||||||
|
.filter((client) => {
|
||||||
|
// Get only those clients that are currently visible.
|
||||||
|
return client.visibilityState === 'visible'
|
||||||
|
})
|
||||||
|
.find((client) => {
|
||||||
|
// Find the client ID that's recorded in the
|
||||||
|
// set of clients that have registered the worker.
|
||||||
|
return activeClientIds.has(client.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResponse(event, client, requestId) {
|
||||||
|
const { request } = event
|
||||||
|
|
||||||
|
// Clone the request because it might've been already used
|
||||||
|
// (i.e. its body has been read and sent to the client).
|
||||||
|
const requestClone = request.clone()
|
||||||
|
|
||||||
|
function passthrough() {
|
||||||
|
const headers = Object.fromEntries(requestClone.headers.entries())
|
||||||
|
|
||||||
|
// Remove internal MSW request header so the passthrough request
|
||||||
|
// complies with any potential CORS preflight checks on the server.
|
||||||
|
// Some servers forbid unknown request headers.
|
||||||
|
delete headers['x-msw-intention']
|
||||||
|
|
||||||
|
return fetch(requestClone, { headers })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass mocking when the client is not active.
|
||||||
|
if (!client) {
|
||||||
|
return passthrough()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass initial page load requests (i.e. static assets).
|
||||||
|
// The absence of the immediate/parent client in the map of the active clients
|
||||||
|
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
||||||
|
// and is not ready to handle requests.
|
||||||
|
if (!activeClientIds.has(client.id)) {
|
||||||
|
return passthrough()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the client that a request has been intercepted.
|
||||||
|
const requestBuffer = await request.arrayBuffer()
|
||||||
|
const clientMessage = await sendToClient(
|
||||||
|
client,
|
||||||
|
{
|
||||||
|
type: 'REQUEST',
|
||||||
|
payload: {
|
||||||
|
id: requestId,
|
||||||
|
url: request.url,
|
||||||
|
mode: request.mode,
|
||||||
|
method: request.method,
|
||||||
|
headers: Object.fromEntries(request.headers.entries()),
|
||||||
|
cache: request.cache,
|
||||||
|
credentials: request.credentials,
|
||||||
|
destination: request.destination,
|
||||||
|
integrity: request.integrity,
|
||||||
|
redirect: request.redirect,
|
||||||
|
referrer: request.referrer,
|
||||||
|
referrerPolicy: request.referrerPolicy,
|
||||||
|
body: requestBuffer,
|
||||||
|
keepalive: request.keepalive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[requestBuffer],
|
||||||
|
)
|
||||||
|
|
||||||
|
switch (clientMessage.type) {
|
||||||
|
case 'MOCK_RESPONSE': {
|
||||||
|
return respondWithMock(clientMessage.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'PASSTHROUGH': {
|
||||||
|
return passthrough()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passthrough()
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendToClient(client, message, transferrables = []) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const channel = new MessageChannel()
|
||||||
|
|
||||||
|
channel.port1.onmessage = (event) => {
|
||||||
|
if (event.data && event.data.error) {
|
||||||
|
return reject(event.data.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(event.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.postMessage(
|
||||||
|
message,
|
||||||
|
[channel.port2].concat(transferrables.filter(Boolean)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function respondWithMock(response) {
|
||||||
|
// Setting response status code to 0 is a no-op.
|
||||||
|
// However, when responding with a "Response.error()", the produced Response
|
||||||
|
// instance will have status code set to 0. Since it's not possible to create
|
||||||
|
// a Response instance with status code 0, handle that use-case separately.
|
||||||
|
if (response.status === 0) {
|
||||||
|
return Response.error()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockedResponse = new Response(response.body, response)
|
||||||
|
|
||||||
|
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
|
||||||
|
value: true,
|
||||||
|
enumerable: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return mockedResponse
|
||||||
|
}
|
||||||
15
shims.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import type { DefineComponent } from 'vue'
|
||||||
|
|
||||||
|
const component: DefineComponent<{}, {}, any>
|
||||||
|
export default component
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare module 'vue-prism-component' {
|
||||||
|
import { ComponentOptions } from 'vue'
|
||||||
|
const component: ComponentOptions
|
||||||
|
export default component
|
||||||
|
}
|
||||||
|
declare module 'vue-shepherd';
|
||||||
|
declare module '@videojs-player/vue';
|
||||||
BIN
src/.DS_Store
vendored
Normal file
279
src/@core/components/AppBarSearch.vue
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
<script setup lang="ts" generic="T extends unknown">
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
|
||||||
|
import { VList, VListItem } from 'vuetify/components/VList'
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:isDialogVisible', value: boolean): void
|
||||||
|
(e: 'search', value: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isDialogVisible: boolean
|
||||||
|
searchResults: T[]
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
// 👉 Hotkey
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
const { ctrl_k, meta_k } = useMagicKeys({
|
||||||
|
passive: false,
|
||||||
|
onEventFired(e) {
|
||||||
|
if (e.ctrlKey && e.key === 'k' && e.type === 'keydown')
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const refSearchList = ref<VList>()
|
||||||
|
const refSearchInput = ref<HTMLInputElement>()
|
||||||
|
const searchQueryLocal = ref('')
|
||||||
|
|
||||||
|
// 👉 watching control + / to open dialog
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
watch([
|
||||||
|
ctrl_k, meta_k,
|
||||||
|
], () => {
|
||||||
|
emit('update:isDialogVisible', true)
|
||||||
|
})
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
|
// 👉 clear search result and close the dialog
|
||||||
|
const clearSearchAndCloseDialog = () => {
|
||||||
|
searchQueryLocal.value = ''
|
||||||
|
emit('update:isDialogVisible', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 get fucus on search list
|
||||||
|
const getFocusOnSearchList = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault()
|
||||||
|
refSearchList.value?.focus('next')
|
||||||
|
}
|
||||||
|
else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault()
|
||||||
|
refSearchList.value?.focus('prev')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogModelValueUpdate = (val: boolean) => {
|
||||||
|
searchQueryLocal.value = ''
|
||||||
|
emit('update:isDialogVisible', val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 clear search query when redirect to another page
|
||||||
|
watch(
|
||||||
|
() => props.isDialogVisible,
|
||||||
|
() => { searchQueryLocal.value = '' },
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VDialog
|
||||||
|
max-width="600"
|
||||||
|
:model-value="props.isDialogVisible"
|
||||||
|
:height="$vuetify.display.smAndUp ? '537' : '100%'"
|
||||||
|
:fullscreen="$vuetify.display.width < 600"
|
||||||
|
class="app-bar-search-dialog"
|
||||||
|
@update:model-value="dialogModelValueUpdate"
|
||||||
|
@keyup.esc="clearSearchAndCloseDialog"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
class="position-relative"
|
||||||
|
>
|
||||||
|
<VCardText class="py-3 px-4">
|
||||||
|
<!-- 👉 Search Input -->
|
||||||
|
<VTextField
|
||||||
|
ref="refSearchInput"
|
||||||
|
v-model="searchQueryLocal"
|
||||||
|
autofocus
|
||||||
|
density="compact"
|
||||||
|
variant="plain"
|
||||||
|
class="app-bar-search-input"
|
||||||
|
@keyup.esc="clearSearchAndCloseDialog"
|
||||||
|
@keydown="getFocusOnSearchList"
|
||||||
|
@update:model-value="$emit('search', searchQueryLocal)"
|
||||||
|
>
|
||||||
|
<!-- 👉 Prepend Inner -->
|
||||||
|
<template #prepend-inner>
|
||||||
|
<div class="d-flex align-center text-high-emphasis me-1">
|
||||||
|
<VIcon
|
||||||
|
size="24"
|
||||||
|
icon="ri-search-line"
|
||||||
|
style="opacity: 1;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 👉 Append Inner -->
|
||||||
|
<template #append-inner>
|
||||||
|
<div class="d-flex align-start">
|
||||||
|
<div
|
||||||
|
class="text-base text-disabled cursor-pointer me-2"
|
||||||
|
@click="clearSearchAndCloseDialog"
|
||||||
|
>
|
||||||
|
[esc]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<IconBtn
|
||||||
|
class="mt-n2"
|
||||||
|
color="medium-emphasis"
|
||||||
|
@click="clearSearchAndCloseDialog"
|
||||||
|
>
|
||||||
|
<VIcon icon="ri-close-line" />
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VTextField>
|
||||||
|
</VCardText>
|
||||||
|
|
||||||
|
<!-- 👉 Divider -->
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<!-- 👉 Perfect Scrollbar -->
|
||||||
|
<PerfectScrollbar
|
||||||
|
:options="{ wheelPropagation: false, suppressScrollX: true }"
|
||||||
|
class="h-100"
|
||||||
|
>
|
||||||
|
<template v-if="!isLoading">
|
||||||
|
<!-- 👉 Search List -->
|
||||||
|
<VList
|
||||||
|
v-show="searchQueryLocal.length && !!props.searchResults.length"
|
||||||
|
ref="refSearchList"
|
||||||
|
density="compact"
|
||||||
|
class="app-bar-search-list py-0"
|
||||||
|
>
|
||||||
|
<!-- 👉 list Item /List Sub header -->
|
||||||
|
<template
|
||||||
|
v-for="item in props.searchResults"
|
||||||
|
:key="item"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="searchResult"
|
||||||
|
:item="item"
|
||||||
|
>
|
||||||
|
<VListItem>
|
||||||
|
{{ item }}
|
||||||
|
</VListItem>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
</VList>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 👉 Suggestions -->
|
||||||
|
<div
|
||||||
|
v-show="!!props.searchResults && !searchQueryLocal && $slots.suggestions"
|
||||||
|
class="h-100"
|
||||||
|
>
|
||||||
|
<slot name="suggestions" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 No Data found -->
|
||||||
|
<div
|
||||||
|
v-show="!props.searchResults.length && searchQueryLocal.length"
|
||||||
|
class="h-100"
|
||||||
|
>
|
||||||
|
<slot name="noData">
|
||||||
|
<VCardText class="h-100">
|
||||||
|
<div class="app-bar-search-suggestions d-flex flex-column align-center justify-center text-high-emphasis px-12 pb-12 pt-16">
|
||||||
|
<VIcon
|
||||||
|
size="64"
|
||||||
|
icon="ri-file-forbid-line"
|
||||||
|
/>
|
||||||
|
<div class="d-flex align-center flex-wrap justify-center gap-2 text-h5 my-3">
|
||||||
|
<span>No Result For </span>
|
||||||
|
<span>"{{ searchQueryLocal }}"</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot name="noDataSuggestion" />
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Loading -->
|
||||||
|
<template v-if="isLoading">
|
||||||
|
<VSkeletonLoader
|
||||||
|
v-for="i in 3"
|
||||||
|
:key="i"
|
||||||
|
type="list-item-two-line"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</PerfectScrollbar>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.app-bar-search-suggestions {
|
||||||
|
.app-bar-search-suggestion {
|
||||||
|
&:hover {
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-bar-search-dialog {
|
||||||
|
.app-bar-search-input {
|
||||||
|
.v-field__input {
|
||||||
|
margin-block-start: -1px;
|
||||||
|
padding-block-start: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-overlay__scrim {
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-bar-search-list {
|
||||||
|
.v-list-item,
|
||||||
|
.v-list-subheader {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding-inline: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-item {
|
||||||
|
.v-list-item__append {
|
||||||
|
.enter-icon {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
.v-list-item__append {
|
||||||
|
.enter-icon {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-subheader {
|
||||||
|
line-height: 1;
|
||||||
|
min-block-size: auto;
|
||||||
|
padding-block: 16px 8px;
|
||||||
|
padding-inline-start: 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports selector(:focus-visible) {
|
||||||
|
.app-bar-search-dialog {
|
||||||
|
.v-list-item:focus-visible::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card-list {
|
||||||
|
--v-card-list-gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
31
src/@core/components/AppDrawerHeaderSection.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
title: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'cancel', el: MouseEvent): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="pa-5 d-flex align-center">
|
||||||
|
<h5 class="text-h5">
|
||||||
|
{{ props.title }}
|
||||||
|
</h5>
|
||||||
|
<VSpacer />
|
||||||
|
|
||||||
|
<slot name="beforeClose" />
|
||||||
|
|
||||||
|
<IconBtn
|
||||||
|
class="text-medium-emphasis ms-1"
|
||||||
|
size="x-small"
|
||||||
|
@click="$emit('cancel', $event)"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="24"
|
||||||
|
icon="ri-close-line"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
403
src/@core/components/AppStepper.vue
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import stepperCheck from '@images/svg/stepper-check.svg'
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
title: string
|
||||||
|
icon?: string | object
|
||||||
|
size?: string
|
||||||
|
subtitle?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Direction = 'vertical' | 'horizontal'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
items: Item[]
|
||||||
|
currentStep?: number
|
||||||
|
direction?: Direction
|
||||||
|
iconSize?: string | number
|
||||||
|
isActiveStepValid?: boolean
|
||||||
|
align?: 'start' | 'center' | 'end' | 'default'
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:currentStep', value: number): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
currentStep: 0,
|
||||||
|
direction: 'horizontal',
|
||||||
|
iconSize: 52,
|
||||||
|
isActiveStepValid: undefined,
|
||||||
|
align: 'default',
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const currentStep = ref(props.currentStep || 0)
|
||||||
|
|
||||||
|
// check if step is completed or active and return class name accordingly
|
||||||
|
const activeOrCompletedStepsClasses = computed(() => (index: number) => (
|
||||||
|
index < currentStep.value
|
||||||
|
? 'stepper-steps-completed'
|
||||||
|
: index === currentStep.value ? 'stepper-steps-active' : ''
|
||||||
|
))
|
||||||
|
|
||||||
|
// check if step is horizontal and not last step
|
||||||
|
const isHorizontalAndNotLastStep = computed(() => (index: number) => (
|
||||||
|
props.direction === 'horizontal'
|
||||||
|
&& props.items.length - 1 !== index
|
||||||
|
))
|
||||||
|
|
||||||
|
// check if validation is enabled
|
||||||
|
const isValidationEnabled = computed(() => {
|
||||||
|
return props.isActiveStepValid !== undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
// we need to check undefined because if we pass 0 as currentStep it will be falsy
|
||||||
|
if (
|
||||||
|
props.currentStep !== undefined
|
||||||
|
&& props.currentStep < props.items.length
|
||||||
|
&& props.currentStep >= 0
|
||||||
|
)
|
||||||
|
currentStep.value = props.currentStep
|
||||||
|
|
||||||
|
emit('update:currentStep', currentStep.value)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VSlideGroup
|
||||||
|
v-model="currentStep"
|
||||||
|
class="app-stepper"
|
||||||
|
show-arrows
|
||||||
|
:direction="props.direction"
|
||||||
|
:class="`app-stepper-${props.align} ${props.items[0].icon ? 'app-stepper-icons' : ''}`"
|
||||||
|
>
|
||||||
|
<VSlideGroupItem
|
||||||
|
v-for="(item, index) in props.items"
|
||||||
|
:key="item.title"
|
||||||
|
:value="index"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cursor-pointer app-stepper-step"
|
||||||
|
:class="[
|
||||||
|
(!props.isActiveStepValid && (isValidationEnabled)) && 'stepper-steps-invalid',
|
||||||
|
activeOrCompletedStepsClasses(index),
|
||||||
|
]"
|
||||||
|
@click="!isValidationEnabled && emit('update:currentStep', index)"
|
||||||
|
>
|
||||||
|
<!-- SECTION stepper step with icon -->
|
||||||
|
<template v-if="item.icon">
|
||||||
|
<div class="stepper-icon-step text-high-emphasis d-flex align-center gap-2">
|
||||||
|
<!-- 👉 icon and title -->
|
||||||
|
<div
|
||||||
|
class="d-flex align-center gap-2 step-wrapper"
|
||||||
|
:class="[props.direction === 'horizontal' && 'flex-column']"
|
||||||
|
>
|
||||||
|
<div class="stepper-icon">
|
||||||
|
<template v-if="typeof item.icon === 'object'">
|
||||||
|
<Component :is="item.icon" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<VIcon
|
||||||
|
v-else
|
||||||
|
:icon="item.icon"
|
||||||
|
:size="item.size || props.iconSize"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<p class="stepper-title font-weight-medium text-base mb-0">
|
||||||
|
{{ item.title }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="item.subtitle"
|
||||||
|
class="stepper-subtitle text-sm mb-0"
|
||||||
|
>
|
||||||
|
{{ item.subtitle }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 append chevron -->
|
||||||
|
<VIcon
|
||||||
|
v-if="isHorizontalAndNotLastStep(index)"
|
||||||
|
class="flip-in-rtl stepper-chevron-indicator mx-6"
|
||||||
|
size="20"
|
||||||
|
icon="ri-arrow-right-s-line"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- !SECTION -->
|
||||||
|
|
||||||
|
<!-- SECTION stepper step without icon -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="d-flex align-center gap-x-2 me-2">
|
||||||
|
<div class="d-flex align-center gap-2">
|
||||||
|
<div class="d-flex align-center justify-center">
|
||||||
|
<!-- 👉 custom circle icon -->
|
||||||
|
<template v-if="index >= currentStep">
|
||||||
|
<div
|
||||||
|
v-if="(!isValidationEnabled || props.isActiveStepValid || index !== currentStep)"
|
||||||
|
class="stepper-step-indicator"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VIcon
|
||||||
|
v-else
|
||||||
|
icon="ri-error-warning-line"
|
||||||
|
size="24"
|
||||||
|
color="error"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 👉 step completed icon -->
|
||||||
|
|
||||||
|
<component
|
||||||
|
:is="stepperCheck"
|
||||||
|
v-else
|
||||||
|
class="stepper-step-icon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Step Number -->
|
||||||
|
<h4 :class="`${!item.subtitle ? 'text-h6' : 'text-h4'} step-number`">
|
||||||
|
{{ (index + 1).toString().padStart(2, '0') }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 title and subtitle -->
|
||||||
|
<div
|
||||||
|
class="app-stepper-title-wrapper"
|
||||||
|
style="line-height: 0;"
|
||||||
|
>
|
||||||
|
<h6 class="text-base font-weight-medium step-title">
|
||||||
|
{{ item.title }}
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="item.subtitle"
|
||||||
|
class="text-sm step-subtitle mb-0"
|
||||||
|
>
|
||||||
|
{{ item.subtitle }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 stepper step line -->
|
||||||
|
<div
|
||||||
|
v-if="isHorizontalAndNotLastStep(index)"
|
||||||
|
class="stepper-step-line"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="props.direction === 'vertical' && props.items.length - 1 !== index"
|
||||||
|
class="stepper-step-line vertical"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<!-- !SECTION -->
|
||||||
|
</div>
|
||||||
|
</VSlideGroupItem>
|
||||||
|
</VSlideGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use "@core/scss/base/mixins.scss";
|
||||||
|
|
||||||
|
/* stylelint-disable no-descending-specificity */
|
||||||
|
.app-stepper {
|
||||||
|
&.app-stepper-default:not(.app-stepper-icons) .app-stepper-step:not(:last-child) {
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 stepper step with icon and default
|
||||||
|
.v-slide-group__content {
|
||||||
|
.stepper-step-indicator {
|
||||||
|
border: 0.1875rem solid rgb(var(--v-theme-primary));
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
block-size: 1.25rem;
|
||||||
|
inline-size: 1.25rem;
|
||||||
|
opacity: var(--v-activated-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-step-line {
|
||||||
|
border-radius: 0.1875rem;
|
||||||
|
background-color: rgb(var(--v-theme-primary));
|
||||||
|
block-size: 0.1875rem;
|
||||||
|
opacity: var(--v-activated-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-step-line:not(.vertical) {
|
||||||
|
inline-size: 100%;
|
||||||
|
min-inline-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-step-line.vertical {
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
block-size: 1.25rem;
|
||||||
|
inline-size: 0.1875rem;
|
||||||
|
margin-inline-start: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-chevron-indicator {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-steps-completed,
|
||||||
|
.stepper-steps-active {
|
||||||
|
.stepper-icon-step,
|
||||||
|
.stepper-step-icon {
|
||||||
|
color: rgb(var(--v-theme-primary)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-step-indicator {
|
||||||
|
border-width: 0.3125rem;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-steps-completed {
|
||||||
|
.stepper-step-line {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-chevron-indicator {
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-steps-invalid.stepper-steps-active {
|
||||||
|
.stepper-icon-step,
|
||||||
|
.step-number,
|
||||||
|
.step-title,
|
||||||
|
.step-subtitle {
|
||||||
|
color: rgb(var(--v-theme-error)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-stepper-step:not(.stepper-steps-active,.stepper-steps-completed) {
|
||||||
|
.step-number {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-subtitle {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-stepper-title-wrapper {
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 stepper step with bg color
|
||||||
|
&.stepper-icon-step-bg {
|
||||||
|
.v-slide-group__content {
|
||||||
|
row-gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-icon-step {
|
||||||
|
.step-wrapper {
|
||||||
|
flex-direction: row !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||||
|
block-size: 2.5rem;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
inline-size: 2.5rem;
|
||||||
|
margin-inline-end: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-title,
|
||||||
|
.stepper-subtitle {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-title {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-subtitle {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-steps-active {
|
||||||
|
.stepper-icon-step {
|
||||||
|
.stepper-icon {
|
||||||
|
background-color: rgb(var(--v-theme-primary));
|
||||||
|
color: rgba(var(--v-theme-on-primary));
|
||||||
|
|
||||||
|
@include mixins.elevation(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-steps-completed {
|
||||||
|
.stepper-icon-step {
|
||||||
|
.stepper-icon {
|
||||||
|
background: rgba(var(--v-theme-primary), 0.16);
|
||||||
|
color: rgba(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 stepper alignment
|
||||||
|
&.app-stepper-default {
|
||||||
|
.v-slide-group__content {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.app-stepper-center {
|
||||||
|
.v-slide-group__content {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.app-stepper- {
|
||||||
|
.v-slide-group__content {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.app-stepper-end {
|
||||||
|
.v-slide-group__content {
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.app-stepper-icons {
|
||||||
|
.app-stepper-step:not(.stepper-steps-active,.stepper-steps-completed) {
|
||||||
|
.stepper-title {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.stepper-icon-step-bg) {
|
||||||
|
.step-wrapper {
|
||||||
|
padding-block: 1.25rem;
|
||||||
|
padding-inline: 1.875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.v-slide-group--vertical {
|
||||||
|
.step-wrapper {
|
||||||
|
padding-inline: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
87
src/@core/components/BuyNow.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
const buyNowUrl = (typeof window !== 'undefined' && 'isMarketplace' in window && window.isMarketplace)
|
||||||
|
? 'https://store.vuetifyjs.com/products/materialize-vuejs-admin-template'
|
||||||
|
: 'https://1.envato.market/materialize_admin'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
class="buy-now-button d-print-none"
|
||||||
|
role="button"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
:href="buyNowUrl"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Buy Now
|
||||||
|
<span class="button-inner" />
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.buy-now-button,
|
||||||
|
.button-inner {
|
||||||
|
display: inline-flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin: 0;
|
||||||
|
animation: anime 12s linear infinite;
|
||||||
|
appearance: none;
|
||||||
|
background: linear-gradient(-45deg, #ffa63d, #ff3d77, #338aff, #3cf0c5);
|
||||||
|
background-size: 600%;
|
||||||
|
color: rgba(255, 255, 255, 90%);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.43px;
|
||||||
|
line-height: 1.2;
|
||||||
|
min-inline-size: 50px;
|
||||||
|
outline: 0;
|
||||||
|
padding-block: 0.625rem;
|
||||||
|
padding-inline: 1.25rem;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buy-now-button {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 999;
|
||||||
|
inset-block-end: 5%;
|
||||||
|
inset-inline-end: 87px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-inner {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
filter: blur(12px);
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 200ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:hover) .button-inner {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes anime {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/@core/components/CustomizerSection.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
divider?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
divider: true,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VDivider v-if="props.divider" />
|
||||||
|
<div
|
||||||
|
class="customizer-section"
|
||||||
|
v-bind="$attrs"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<VChip
|
||||||
|
label
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
rounded="sm"
|
||||||
|
>
|
||||||
|
{{ props.title }}
|
||||||
|
</VChip>
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
20
src/@core/components/DialogCloseBtn.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
icon?: string
|
||||||
|
iconSize?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
icon: 'ri-close-line',
|
||||||
|
iconSize: '22',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn class="v-dialog-close-btn">
|
||||||
|
<VIcon
|
||||||
|
:icon="props.icon"
|
||||||
|
:size="props.iconSize"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
134
src/@core/components/DropZone.vue
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useDropZone, useFileDialog, useObjectUrl } from '@vueuse/core'
|
||||||
|
|
||||||
|
const dropZoneRef = ref<HTMLDivElement>()
|
||||||
|
interface FileData {
|
||||||
|
file: File
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileData = ref<FileData[]>([])
|
||||||
|
const { open, onChange } = useFileDialog({ accept: 'image/*' })
|
||||||
|
|
||||||
|
function onDrop(DroppedFiles: File[] | null) {
|
||||||
|
DroppedFiles?.forEach(file => {
|
||||||
|
if (file.type.slice(0, 6) !== 'image/') {
|
||||||
|
// eslint-disable-next-line no-alert
|
||||||
|
alert('Only image files are allowed')
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileData.value.push({
|
||||||
|
file,
|
||||||
|
url: useObjectUrl(file).value ?? '',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange((selectedFiles: any) => {
|
||||||
|
if (!selectedFiles)
|
||||||
|
return
|
||||||
|
|
||||||
|
for (const file of selectedFiles) {
|
||||||
|
fileData.value.push({
|
||||||
|
file,
|
||||||
|
url: useObjectUrl(file).value ?? '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useDropZone(dropZoneRef, onDrop)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="w-full h-auto relative">
|
||||||
|
<div
|
||||||
|
ref="dropZoneRef"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="() => open()"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="fileData.length === 0"
|
||||||
|
class="d-flex flex-column justify-center align-center gap-y-2 pa-12 border-dashed drop-zone"
|
||||||
|
>
|
||||||
|
<VAvatar
|
||||||
|
variant="tonal"
|
||||||
|
color="secondary"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
<VIcon icon="ri-upload-2-line" />
|
||||||
|
</VAvatar>
|
||||||
|
<h4 class="text-h4 text-wrap">
|
||||||
|
Drag and Drop Your Image Here.
|
||||||
|
</h4>
|
||||||
|
<span class="text-disabled">or</span>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
Browse Images
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="d-flex justify-center align-center gap-3 pa-8 border-dashed drop-zone flex-wrap"
|
||||||
|
>
|
||||||
|
<VRow class="match-height w-100">
|
||||||
|
<template
|
||||||
|
v-for="(item, index) in fileData"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<VCol
|
||||||
|
cols="12"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
|
<VCard :ripple="false">
|
||||||
|
<VCardText
|
||||||
|
class="d-flex flex-column"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<VImg
|
||||||
|
:src="item.url"
|
||||||
|
width="200px"
|
||||||
|
height="150px"
|
||||||
|
class="w-100 mx-auto"
|
||||||
|
/>
|
||||||
|
<div class="mt-2">
|
||||||
|
<span class="clamp-text text-wrap">
|
||||||
|
{{ item.file.name }}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ item.file.size / 1000 }} KB
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
<VCardActions>
|
||||||
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
block
|
||||||
|
@click.stop="fileData.splice(index, 1)"
|
||||||
|
>
|
||||||
|
Remove File
|
||||||
|
</VBtn>
|
||||||
|
</VCardActions>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</template>
|
||||||
|
</VRow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.drop-zone {
|
||||||
|
border: 1px dashed rgba(var(--v-theme-on-surface), 0.12);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
src/@core/components/I18n.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { I18nLanguage } from '@layouts/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
languages: I18nLanguage[]
|
||||||
|
location?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
location: 'bottom end',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { locale } = useI18n({ useScope: 'global' })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon icon="ri-translate-2" />
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
:location="props.location"
|
||||||
|
offset="15px"
|
||||||
|
width="160"
|
||||||
|
>
|
||||||
|
<!-- List -->
|
||||||
|
<VList
|
||||||
|
:selected="[locale]"
|
||||||
|
color="primary"
|
||||||
|
mandatory
|
||||||
|
>
|
||||||
|
<!-- List item -->
|
||||||
|
<VListItem
|
||||||
|
v-for="lang in props.languages"
|
||||||
|
:key="lang.i18nLang"
|
||||||
|
class="px-4"
|
||||||
|
:value="lang.i18nLang"
|
||||||
|
@click="locale = lang.i18nLang"
|
||||||
|
>
|
||||||
|
<!-- Language label -->
|
||||||
|
<VListItemTitle>
|
||||||
|
{{ lang.label }}
|
||||||
|
</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
34
src/@core/components/MoreBtn.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
interface Props {
|
||||||
|
menuList?: unknown[]
|
||||||
|
itemProps?: boolean
|
||||||
|
iconSize?: string
|
||||||
|
class?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
class: 'text-disabled',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn
|
||||||
|
size="small"
|
||||||
|
:class="props.class"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:size="iconSize"
|
||||||
|
icon="ri-more-2-line"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VMenu
|
||||||
|
v-if="props.menuList"
|
||||||
|
activator="parent"
|
||||||
|
>
|
||||||
|
<VList
|
||||||
|
:items="props.menuList"
|
||||||
|
:item-props="props.itemProps"
|
||||||
|
/>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
235
src/@core/components/Notifications.vue
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
|
||||||
|
import type { Notification } from '@layouts/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
notifications: Notification[]
|
||||||
|
badgeProps?: object
|
||||||
|
location?: any
|
||||||
|
}
|
||||||
|
interface Emit {
|
||||||
|
(e: 'read', value: number[]): void
|
||||||
|
(e: 'unread', value: number[]): void
|
||||||
|
(e: 'remove', value: number): void
|
||||||
|
(e: 'click:notification', value: Notification): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
location: 'bottom end',
|
||||||
|
badgeProps: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const isAllMarkRead = computed(() => props.notifications.some(item => item.isSeen === false),
|
||||||
|
)
|
||||||
|
|
||||||
|
const markAllReadOrUnread = () => {
|
||||||
|
const allNotificationsIds = props.notifications.map(item => item.id)
|
||||||
|
|
||||||
|
if (!isAllMarkRead.value)
|
||||||
|
emit('unread', allNotificationsIds)
|
||||||
|
else
|
||||||
|
emit('read', allNotificationsIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalUnreadNotifications = computed(() => props.notifications.filter(item => !item.isSeen).length)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn id="notification-btn">
|
||||||
|
<VBadge
|
||||||
|
dot
|
||||||
|
v-bind="props.badgeProps"
|
||||||
|
:model-value="props.notifications.some(n => !n.isSeen)"
|
||||||
|
color="error"
|
||||||
|
bordered
|
||||||
|
offset-x="1"
|
||||||
|
offset-y="1"
|
||||||
|
class="notification-badge"
|
||||||
|
>
|
||||||
|
<VIcon icon="ri-notification-2-line" />
|
||||||
|
</VBadge>
|
||||||
|
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
width="380"
|
||||||
|
:location="props.location"
|
||||||
|
offset="15px"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
>
|
||||||
|
<VCard class="d-flex flex-column">
|
||||||
|
<!-- 👉 Header -->
|
||||||
|
<VCardItem class="notification-section">
|
||||||
|
<h6 class="text-h6 text-truncate">
|
||||||
|
Notifications
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<VChip
|
||||||
|
v-show="!!isAllMarkRead"
|
||||||
|
size="small"
|
||||||
|
class="me-2"
|
||||||
|
variant="tonal"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{{ totalUnreadNotifications }} new
|
||||||
|
</VChip>
|
||||||
|
|
||||||
|
<IconBtn
|
||||||
|
v-show="props.notifications.length"
|
||||||
|
size="small"
|
||||||
|
@click="markAllReadOrUnread"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
color="high-emphasis"
|
||||||
|
:icon="!isAllMarkRead ? 'ri-mail-line' : 'ri-mail-open-line' "
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VTooltip
|
||||||
|
activator="parent"
|
||||||
|
location="start"
|
||||||
|
>
|
||||||
|
{{ !isAllMarkRead ? 'Mark all as unread' : 'Mark all as read' }}
|
||||||
|
</VTooltip>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VCardItem>
|
||||||
|
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<!-- 👉 Notifications list -->
|
||||||
|
<PerfectScrollbar
|
||||||
|
:options="{ wheelPropagation: false }"
|
||||||
|
style="max-block-size: 27rem;"
|
||||||
|
>
|
||||||
|
<VList class="py-0">
|
||||||
|
<template
|
||||||
|
v-for="(notification, index) in props.notifications"
|
||||||
|
:key="notification.title"
|
||||||
|
>
|
||||||
|
<VDivider v-if="index > 0" />
|
||||||
|
<VListItem
|
||||||
|
link
|
||||||
|
lines="one"
|
||||||
|
min-height="66px"
|
||||||
|
class="list-item-hover-class py-3 px-4"
|
||||||
|
@click="$emit('click:notification', notification)"
|
||||||
|
>
|
||||||
|
<!-- Slot: Prepend -->
|
||||||
|
<!-- Handles Avatar: Image, Icon, Text -->
|
||||||
|
<div class="d-flex align-start gap-3">
|
||||||
|
<VAvatar
|
||||||
|
size="40"
|
||||||
|
:color="notification.color && !notification.img ? notification.color : undefined"
|
||||||
|
:variant="notification.img ? undefined : 'tonal' "
|
||||||
|
>
|
||||||
|
<span v-if="notification.text">{{ avatarText(notification.text) }}</span>
|
||||||
|
|
||||||
|
<VImg
|
||||||
|
v-if="notification.img"
|
||||||
|
:src="notification.img"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VIcon
|
||||||
|
v-if="notification.icon"
|
||||||
|
:icon="notification.icon"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="text-body-2 text-high-emphasis font-weight-medium mb-1">
|
||||||
|
{{ notification.title }}
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="text-caption mb-2 text-medium-emphasis"
|
||||||
|
style="letter-spacing: 0.4px !important; line-height: 18px;"
|
||||||
|
>
|
||||||
|
{{ notification.subtitle }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-caption mb-0"
|
||||||
|
style="letter-spacing: 0.4px !important; line-height: 18px;"
|
||||||
|
>
|
||||||
|
{{ notification.time }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<VSpacer />
|
||||||
|
|
||||||
|
<div class="d-flex flex-column align-end gap-2">
|
||||||
|
<VIcon
|
||||||
|
:color="!notification.isSeen ? 'primary' : 'secondary'"
|
||||||
|
:class="`${notification.isSeen ? 'visible-in-hover' : ''} ms-1`"
|
||||||
|
size="10"
|
||||||
|
icon="ri-circle-fill"
|
||||||
|
@click.stop="$emit(notification.isSeen ? 'unread' : 'read', [notification.id])"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div style="block-size: 20px; inline-size: 20px;">
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-close-line"
|
||||||
|
color="medium-emphasis"
|
||||||
|
class="visible-in-hover"
|
||||||
|
@click="$emit('remove', notification.id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VListItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<VListItem
|
||||||
|
v-show="!props.notifications.length"
|
||||||
|
class="text-center text-medium-emphasis"
|
||||||
|
style="block-size: 56px;"
|
||||||
|
>
|
||||||
|
<VListItemTitle>No Notification Found!</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</PerfectScrollbar>
|
||||||
|
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<!-- 👉 Footer -->
|
||||||
|
<VCardText
|
||||||
|
v-show="props.notifications.length"
|
||||||
|
class="pa-4"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
View All Notifications
|
||||||
|
</VBtn>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.notification-section {
|
||||||
|
padding-block: 12px !important;
|
||||||
|
padding-inline: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-hover-class {
|
||||||
|
.visible-in-hover {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.visible-in-hover {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-badge {
|
||||||
|
&.v-badge--bordered.v-badge--dot .v-badge__badge::after {
|
||||||
|
color: rgb(var(--v-theme-background));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
40
src/@core/components/ScrollToTop.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { y } = useWindowScroll()
|
||||||
|
|
||||||
|
const scrollToTop = () => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VScaleTransition
|
||||||
|
style="transform-origin: center;"
|
||||||
|
class="scroll-to-top d-print-none"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
v-show="y > 200"
|
||||||
|
icon
|
||||||
|
density="comfortable"
|
||||||
|
@click="scrollToTop"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="22"
|
||||||
|
icon="ri-arrow-up-line"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
</VScaleTransition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.scroll-to-top {
|
||||||
|
position: fixed !important;
|
||||||
|
|
||||||
|
// To keep button on top of v-layout. E.g. Email app
|
||||||
|
z-index: 999;
|
||||||
|
inset-block-end: 5%;
|
||||||
|
inset-inline-end: 25px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
99
src/@core/components/Shortcuts.vue
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
|
||||||
|
|
||||||
|
interface Shortcut {
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
subtitle: string
|
||||||
|
to: object | string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
togglerIcon?: string
|
||||||
|
shortcuts: Shortcut[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
togglerIcon: 'ri-star-smile-line',
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon :icon="props.togglerIcon" />
|
||||||
|
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
offset="15px"
|
||||||
|
location="bottom end"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
max-width="380"
|
||||||
|
max-height="560"
|
||||||
|
class="d-flex flex-column"
|
||||||
|
>
|
||||||
|
<VCardItem class="px-4 py-3">
|
||||||
|
<h6 class="text-h6">
|
||||||
|
Shortcuts
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<IconBtn size="small">
|
||||||
|
<VIcon
|
||||||
|
icon="ri-add-line"
|
||||||
|
color="high-emphasis"
|
||||||
|
/>
|
||||||
|
<VTooltip
|
||||||
|
activator="parent"
|
||||||
|
location="start"
|
||||||
|
>
|
||||||
|
Add Shortcut
|
||||||
|
</VTooltip>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VCardItem>
|
||||||
|
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<PerfectScrollbar :options="{ wheelPropagation: false }">
|
||||||
|
<VRow class="ma-0 mt-n1">
|
||||||
|
<VCol
|
||||||
|
v-for="(shortcut, index) in props.shortcuts"
|
||||||
|
:key="shortcut.title"
|
||||||
|
cols="6"
|
||||||
|
class="text-center border-t cursor-pointer pa-6 shortcut-icon"
|
||||||
|
:class="(index + 1) % 2 ? 'border-e' : ''"
|
||||||
|
@click="router.push(shortcut.to)"
|
||||||
|
>
|
||||||
|
<VAvatar
|
||||||
|
variant="tonal"
|
||||||
|
size="50"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
color="high-emphasis"
|
||||||
|
size="26"
|
||||||
|
:icon="shortcut.icon"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<h6 class="text-h6 mt-3">
|
||||||
|
{{ shortcut.title }}
|
||||||
|
</h6>
|
||||||
|
<p class="text-sm text-medium-emphasis mb-0">
|
||||||
|
{{ shortcut.subtitle }}
|
||||||
|
</p>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</PerfectScrollbar>
|
||||||
|
</VCard>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.shortcut-icon:hover {
|
||||||
|
background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
640
src/@core/components/TheCustomizer.vue
Normal file
@@ -0,0 +1,640 @@
|
|||||||
|
<script setup lang="tsx">
|
||||||
|
import { useStorage } from '@vueuse/core'
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
|
||||||
|
import { useTheme } from 'vuetify'
|
||||||
|
import { staticPrimaryColor, staticPrimaryDarkenColor } from '@/plugins/vuetify/theme'
|
||||||
|
import { Direction, Layout, Skins, Theme } from '@core/enums'
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
import { AppContentLayoutNav, ContentWidth } from '@layouts/enums'
|
||||||
|
import { cookieRef, namespaceConfig } from '@layouts/stores/config'
|
||||||
|
import { themeConfig } from '@themeConfig'
|
||||||
|
|
||||||
|
import borderSkinDark from '@images/customizer-icons/border-dark.svg'
|
||||||
|
import borderSkinLight from '@images/customizer-icons/border-light.svg'
|
||||||
|
import collapsedDark from '@images/customizer-icons/collapsed-dark.svg'
|
||||||
|
import collapsedLight from '@images/customizer-icons/collapsed-light.svg'
|
||||||
|
import compactDark from '@images/customizer-icons/compact-dark.svg'
|
||||||
|
import compactLight from '@images/customizer-icons/compact-light.svg'
|
||||||
|
import defaultSkinDark from '@images/customizer-icons/default-dark.svg'
|
||||||
|
import defaultSkinLight from '@images/customizer-icons/default-light.svg'
|
||||||
|
import horizontalDark from '@images/customizer-icons/horizontal-dark.svg'
|
||||||
|
import horizontalLight from '@images/customizer-icons/horizontal-light.svg'
|
||||||
|
import ltrDark from '@images/customizer-icons/ltr-dark.svg'
|
||||||
|
import ltrLight from '@images/customizer-icons/ltr-light.svg'
|
||||||
|
import rtlDark from '@images/customizer-icons/rtl-dark.svg'
|
||||||
|
import rtlLight from '@images/customizer-icons/rtl-light.svg'
|
||||||
|
import wideDark from '@images/customizer-icons/wide-dark.svg'
|
||||||
|
import wideLight from '@images/customizer-icons/wide-light.svg'
|
||||||
|
|
||||||
|
const isNavDrawerOpen = ref(false)
|
||||||
|
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
// 👉 Primary Color
|
||||||
|
const vuetifyTheme = useTheme()
|
||||||
|
|
||||||
|
const colors: { main: string; darken: string }[] = [
|
||||||
|
{ main: staticPrimaryColor, darken: staticPrimaryDarkenColor },
|
||||||
|
{ main: '#0D9394', darken: '#0C8485' },
|
||||||
|
{ main: '#FFB400', darken: '#E6A200' },
|
||||||
|
{ main: '#FF4C51', darken: '#E64449' },
|
||||||
|
{ main: '#16B1FF', darken: '#149FE6' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const customPrimaryColor = ref('#ffffff')
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => configStore.theme,
|
||||||
|
() => {
|
||||||
|
const cookiePrimaryColor = cookieRef(`${vuetifyTheme.name.value}ThemePrimaryColor`, null).value
|
||||||
|
|
||||||
|
if (cookiePrimaryColor && !colors.some(color => color.main === cookiePrimaryColor))
|
||||||
|
customPrimaryColor.value = cookiePrimaryColor
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
// ℹ️ It will set primary color for current theme only
|
||||||
|
const setPrimaryColor = useDebounceFn((color: { main: string; darken: string }) => {
|
||||||
|
vuetifyTheme.themes.value[vuetifyTheme.name.value].colors.primary = color.main
|
||||||
|
vuetifyTheme.themes.value[vuetifyTheme.name.value].colors['primary-darken-1'] = color.darken
|
||||||
|
|
||||||
|
// ℹ️ We need to store this color value in cookie so vuetify plugin can pick on next reload
|
||||||
|
cookieRef<string | null>(`${vuetifyTheme.name.value}ThemePrimaryColor`, null).value = color.main
|
||||||
|
cookieRef<string | null>(`${vuetifyTheme.name.value}ThemePrimaryDarkenColor`, null).value = color.darken
|
||||||
|
|
||||||
|
// ℹ️ Update initial loader color
|
||||||
|
useStorage<string | null>(namespaceConfig('initial-loader-color'), null).value = color.main
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
const defaultSkin = useGenerateImageVariant(defaultSkinLight, defaultSkinDark)
|
||||||
|
const borderSkin = useGenerateImageVariant(borderSkinLight, borderSkinDark)
|
||||||
|
const collapsed = useGenerateImageVariant(collapsedLight, collapsedDark)
|
||||||
|
const compactContent = useGenerateImageVariant(compactLight, compactDark)
|
||||||
|
const wideContent = useGenerateImageVariant(wideLight, wideDark)
|
||||||
|
const ltrImg = useGenerateImageVariant(ltrLight, ltrDark)
|
||||||
|
const rtlImg = useGenerateImageVariant(rtlLight, rtlDark)
|
||||||
|
const horizontalImg = useGenerateImageVariant(horizontalLight, horizontalDark)
|
||||||
|
|
||||||
|
// 👉 Mode
|
||||||
|
const themeMode = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
bgImage: 'ri-sun-line',
|
||||||
|
value: Theme.Light,
|
||||||
|
label: 'Light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: 'ri-moon-clear-line',
|
||||||
|
value: Theme.Dark,
|
||||||
|
label: 'Dark',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: 'ri-computer-line',
|
||||||
|
value: Theme.System,
|
||||||
|
label: 'System',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 👉 Skin
|
||||||
|
const themeSkin = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
bgImage: defaultSkin.value,
|
||||||
|
value: Skins.Default,
|
||||||
|
label: 'Default',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: borderSkin.value,
|
||||||
|
value: Skins.Bordered,
|
||||||
|
label: 'Bordered',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 👉 Layout
|
||||||
|
const currentLayout = ref<'vertical' | 'collapsed' | 'horizontal'>(configStore.isVerticalNavCollapsed ? 'collapsed' : configStore.appContentLayoutNav)
|
||||||
|
|
||||||
|
const layouts = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
bgImage: defaultSkin.value,
|
||||||
|
value: Layout.Vertical,
|
||||||
|
label: 'Vertical',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: collapsed.value,
|
||||||
|
value: Layout.Collapsed,
|
||||||
|
label: 'Collapsed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: horizontalImg.value,
|
||||||
|
value: Layout.Horizontal,
|
||||||
|
label: 'Horizontal',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(currentLayout, () => {
|
||||||
|
if (currentLayout.value === 'collapsed') {
|
||||||
|
configStore.isVerticalNavCollapsed = true
|
||||||
|
configStore.appContentLayoutNav = AppContentLayoutNav.Vertical
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
configStore.isVerticalNavCollapsed = false
|
||||||
|
configStore.appContentLayoutNav = currentLayout.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// watch vertical sidebar collapse state
|
||||||
|
watch(
|
||||||
|
() => configStore.isVerticalNavCollapsed,
|
||||||
|
() => {
|
||||||
|
currentLayout.value = configStore.isVerticalNavCollapsed
|
||||||
|
? 'collapsed'
|
||||||
|
: configStore.appContentLayoutNav
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 👉 Content Width
|
||||||
|
const contentWidth = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
bgImage: compactContent.value,
|
||||||
|
value: ContentWidth.Boxed,
|
||||||
|
label: 'Compact',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: wideContent.value,
|
||||||
|
value: ContentWidth.Fluid,
|
||||||
|
label: 'Wide',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 👉 Direction
|
||||||
|
const currentDir = ref(configStore.isAppRTL ? 'rtl' : 'ltr')
|
||||||
|
|
||||||
|
const direction = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
bgImage: ltrImg.value,
|
||||||
|
value: Direction.Ltr,
|
||||||
|
label: 'Left to right',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bgImage: rtlImg.value,
|
||||||
|
value: Direction.Rtl,
|
||||||
|
label: 'Right to left',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(currentDir, () => {
|
||||||
|
if (currentDir.value === 'rtl')
|
||||||
|
configStore.isAppRTL = true
|
||||||
|
|
||||||
|
else
|
||||||
|
configStore.isAppRTL = false
|
||||||
|
})
|
||||||
|
|
||||||
|
// check if any value set in cookie
|
||||||
|
const isCookieHasAnyValue = ref(false)
|
||||||
|
|
||||||
|
const { locale } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
|
const isActiveLangRTL = computed(() => {
|
||||||
|
const lang = themeConfig.app.i18n.langConfig.find(l => l.i18nLang === locale.value)
|
||||||
|
|
||||||
|
return lang?.isRTL ?? false
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([
|
||||||
|
() => vuetifyTheme.current.value.colors.primary,
|
||||||
|
configStore.$state,
|
||||||
|
locale,
|
||||||
|
], () => {
|
||||||
|
const initialConfigValue = [
|
||||||
|
staticPrimaryColor,
|
||||||
|
staticPrimaryColor,
|
||||||
|
themeConfig.app.theme,
|
||||||
|
themeConfig.app.skin,
|
||||||
|
themeConfig.verticalNav.isVerticalNavSemiDark,
|
||||||
|
themeConfig.verticalNav.isVerticalNavCollapsed,
|
||||||
|
themeConfig.app.contentWidth,
|
||||||
|
isActiveLangRTL.value,
|
||||||
|
themeConfig.app.contentLayoutNav,
|
||||||
|
]
|
||||||
|
|
||||||
|
const themeConfigValue = [
|
||||||
|
vuetifyTheme.themes.value.light.colors.primary,
|
||||||
|
vuetifyTheme.themes.value.dark.colors.primary,
|
||||||
|
configStore.theme,
|
||||||
|
configStore.skin,
|
||||||
|
configStore.isVerticalNavSemiDark,
|
||||||
|
configStore.isVerticalNavCollapsed,
|
||||||
|
configStore.appContentWidth,
|
||||||
|
configStore.isAppRTL,
|
||||||
|
configStore.appContentLayoutNav,
|
||||||
|
]
|
||||||
|
|
||||||
|
currentDir.value = configStore.isAppRTL ? 'rtl' : 'ltr'
|
||||||
|
|
||||||
|
isCookieHasAnyValue.value = JSON.stringify(themeConfigValue) !== JSON.stringify(initialConfigValue)
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
|
||||||
|
// remove all theme related values from localStorage
|
||||||
|
const resetCustomizer = async () => {
|
||||||
|
if (isCookieHasAnyValue.value) {
|
||||||
|
// reset themeConfig values
|
||||||
|
vuetifyTheme.themes.value.light.colors.primary = staticPrimaryColor
|
||||||
|
vuetifyTheme.themes.value.dark.colors.primary = staticPrimaryColor
|
||||||
|
vuetifyTheme.themes.value.light.colors['primary-darken-1'] = staticPrimaryDarkenColor
|
||||||
|
vuetifyTheme.themes.value.dark.colors['primary-darken-1'] = staticPrimaryDarkenColor
|
||||||
|
|
||||||
|
configStore.theme = themeConfig.app.theme
|
||||||
|
configStore.skin = themeConfig.app.skin
|
||||||
|
configStore.isVerticalNavSemiDark = themeConfig.verticalNav.isVerticalNavSemiDark
|
||||||
|
configStore.appContentLayoutNav = themeConfig.app.contentLayoutNav
|
||||||
|
configStore.appContentWidth = themeConfig.app.contentWidth
|
||||||
|
configStore.isAppRTL = isActiveLangRTL.value
|
||||||
|
configStore.isVerticalNavCollapsed = themeConfig.verticalNav.isVerticalNavCollapsed
|
||||||
|
useStorage<string | null>(namespaceConfig('initial-loader-color'), null).value = staticPrimaryColor
|
||||||
|
currentLayout.value = themeConfig.app.contentLayoutNav
|
||||||
|
configStore.theme = themeConfig.app.theme
|
||||||
|
configStore.skin = themeConfig.app.skin
|
||||||
|
configStore.isVerticalNavSemiDark = themeConfig.verticalNav.isVerticalNavSemiDark
|
||||||
|
configStore.appContentLayoutNav = themeConfig.app.contentLayoutNav
|
||||||
|
configStore.appContentWidth = themeConfig.app.contentWidth
|
||||||
|
configStore.isAppRTL = isActiveLangRTL.value
|
||||||
|
configStore.isVerticalNavCollapsed = themeConfig.verticalNav.isVerticalNavCollapsed
|
||||||
|
useStorage<string | null>(namespaceConfig('initial-loader-color'), null).value = staticPrimaryColor
|
||||||
|
currentLayout.value = themeConfig.app.contentLayoutNav
|
||||||
|
|
||||||
|
cookieRef('lightThemePrimaryColor', null).value = null
|
||||||
|
cookieRef('darkThemePrimaryColor', null).value = null
|
||||||
|
cookieRef('lightThemePrimaryDarkenColor', null).value = null
|
||||||
|
cookieRef('darkThemePrimaryDarkenColor', null).value = null
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
isCookieHasAnyValue.value = false
|
||||||
|
|
||||||
|
customPrimaryColor.value = '#ffffff'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="d-lg-block d-none">
|
||||||
|
<VBtn
|
||||||
|
icon
|
||||||
|
class="app-customizer-toggler rounded-s-pill rounded-0"
|
||||||
|
style="z-index: 1001;"
|
||||||
|
@click="isNavDrawerOpen = true"
|
||||||
|
>
|
||||||
|
<VIcon icon="ri-settings-3-line" />
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VNavigationDrawer
|
||||||
|
v-model="isNavDrawerOpen"
|
||||||
|
data-allow-mismatch
|
||||||
|
temporary
|
||||||
|
touchless
|
||||||
|
border="none"
|
||||||
|
location="end"
|
||||||
|
width="400"
|
||||||
|
:scrim="false"
|
||||||
|
class="app-customizer"
|
||||||
|
>
|
||||||
|
<!-- 👉 Header -->
|
||||||
|
<div class="customizer-heading d-flex align-center justify-space-between">
|
||||||
|
<div>
|
||||||
|
<h6 class="text-h6">
|
||||||
|
Theme Customizer
|
||||||
|
</h6>
|
||||||
|
<p class="text-body-2 mb-0">
|
||||||
|
Customize & Preview in Real Time
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<VBtn
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
color="medium-emphasis"
|
||||||
|
@click="resetCustomizer"
|
||||||
|
>
|
||||||
|
<VBadge
|
||||||
|
v-show="isCookieHasAnyValue"
|
||||||
|
dot
|
||||||
|
color="error"
|
||||||
|
offset-x="-30"
|
||||||
|
offset-y="-15"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VIcon
|
||||||
|
size="24"
|
||||||
|
icon="ri-refresh-line"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
color="medium-emphasis"
|
||||||
|
@click="isNavDrawerOpen = false"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
icon="ri-close-line"
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<PerfectScrollbar
|
||||||
|
tag="ul"
|
||||||
|
:options="{ wheelPropagation: false }"
|
||||||
|
>
|
||||||
|
<!-- SECTION Theming -->
|
||||||
|
<CustomizerSection
|
||||||
|
title="Theming"
|
||||||
|
:divider="false"
|
||||||
|
class="pb-6"
|
||||||
|
>
|
||||||
|
<!-- 👉 Primary Color -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-h6">
|
||||||
|
Primary Color
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="d-flex app-customizer-primary-colors"
|
||||||
|
style="column-gap: 0.75rem; margin-block-start: 2px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="color in colors"
|
||||||
|
:key="color.main"
|
||||||
|
style="
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
outline: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
padding-block: 0.5rem;
|
||||||
|
padding-inline: 0.625rem;"
|
||||||
|
class="primary-color-wrapper cursor-pointer"
|
||||||
|
:class="vuetifyTheme.current.value.colors.primary === color.main ? 'active' : ''"
|
||||||
|
:style="vuetifyTheme.current.value.colors.primary === color.main ? `outline-color: ${color.main}; outline-width:2px;` : `--v-color:${color.main}`"
|
||||||
|
@click="setPrimaryColor(color)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="border-radius: 0.5rem;block-size: 2.125rem; inline-size: 1.9375rem;"
|
||||||
|
:style="{ backgroundColor: color.main }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="primary-color-wrapper cursor-pointer"
|
||||||
|
style="
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
outline: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
padding-block: 0.5rem;
|
||||||
|
padding-inline: 0.625rem;"
|
||||||
|
:class="vuetifyTheme.current.value.colors.primary === customPrimaryColor ? 'active' : ''"
|
||||||
|
:style="vuetifyTheme.current.value.colors.primary === customPrimaryColor ? `outline-color: ${customPrimaryColor}; outline-width:2px;` : ''"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
icon
|
||||||
|
size="small"
|
||||||
|
:color="vuetifyTheme.current.value.colors.primary === customPrimaryColor ? customPrimaryColor : $vuetify.theme.current.dark ? '#8692d029' : '#4b465c29'"
|
||||||
|
variant="flat"
|
||||||
|
style="border-radius: 0.5rem;"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-palette-line"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
>
|
||||||
|
<VList>
|
||||||
|
<VListItem>
|
||||||
|
<VColorPicker
|
||||||
|
v-model="customPrimaryColor"
|
||||||
|
mode="hex"
|
||||||
|
:modes="['hex']"
|
||||||
|
@update:model-value="setPrimaryColor({ main: customPrimaryColor, darken: customPrimaryColor })"
|
||||||
|
/>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Mode -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-h6">
|
||||||
|
Mode
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<CustomRadiosWithImage
|
||||||
|
:key="configStore.theme"
|
||||||
|
v-model:selected-radio="configStore.theme"
|
||||||
|
:radio-content="themeMode"
|
||||||
|
:grid-column="{ cols: '4' }"
|
||||||
|
class="customizer-skins"
|
||||||
|
>
|
||||||
|
<template #label="item">
|
||||||
|
<span class="text-sm text-medium-emphasis">{{ item?.label }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #content="{ item }">
|
||||||
|
<div
|
||||||
|
class="customizer-skins-icon-wrapper d-flex align-center justify-center py-3 w-100"
|
||||||
|
style="min-inline-size: 100%;"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="30"
|
||||||
|
:icon="item.bgImage"
|
||||||
|
color="high-emphasis"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CustomRadiosWithImage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Skin -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-h6">
|
||||||
|
Skin
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<CustomRadiosWithImage
|
||||||
|
:key="configStore.skin"
|
||||||
|
v-model:selected-radio="configStore.skin"
|
||||||
|
:radio-content="themeSkin"
|
||||||
|
:grid-column="{ cols: '4' }"
|
||||||
|
>
|
||||||
|
<template #label="item">
|
||||||
|
<span class="text-sm text-medium-emphasis">{{ item?.label }}</span>
|
||||||
|
</template>
|
||||||
|
</CustomRadiosWithImage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Semi Dark -->
|
||||||
|
<div
|
||||||
|
class="align-center justify-space-between"
|
||||||
|
:class="vuetifyTheme.global.name.value === 'light' && configStore.appContentLayoutNav === AppContentLayoutNav.Vertical ? 'd-flex' : 'd-none'"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
for="customizer-semi-dark"
|
||||||
|
class="text-h6 text-high-emphasis"
|
||||||
|
>
|
||||||
|
Semi Dark Menu
|
||||||
|
</VLabel>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<VSwitch
|
||||||
|
id="customizer-semi-dark"
|
||||||
|
v-model="configStore.isVerticalNavSemiDark"
|
||||||
|
class="ms-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CustomizerSection>
|
||||||
|
<!-- !SECTION -->
|
||||||
|
|
||||||
|
<!-- SECTION LAYOUT -->
|
||||||
|
<CustomizerSection
|
||||||
|
title="Layout"
|
||||||
|
class="pt-6"
|
||||||
|
>
|
||||||
|
<!-- 👉 Layouts -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-base font-weight-medium">
|
||||||
|
Layout
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<CustomRadiosWithImage
|
||||||
|
:key="currentLayout"
|
||||||
|
v-model:selected-radio="currentLayout"
|
||||||
|
:radio-content="layouts"
|
||||||
|
:grid-column="{ cols: '4' }"
|
||||||
|
>
|
||||||
|
<template #label="item">
|
||||||
|
<span class="text-sm text-medium-emphasis">{{ item.label }}</span>
|
||||||
|
</template>
|
||||||
|
</CustomRadiosWithImage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Content Width -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-base font-weight-medium">
|
||||||
|
Content
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<CustomRadiosWithImage
|
||||||
|
:key="configStore.appContentWidth"
|
||||||
|
v-model:selected-radio="configStore.appContentWidth"
|
||||||
|
:radio-content="contentWidth"
|
||||||
|
:grid-column="{ cols: '4' }"
|
||||||
|
>
|
||||||
|
<template #label="item">
|
||||||
|
<span class="text-sm text-medium-emphasis">{{ item.label }}</span>
|
||||||
|
</template>
|
||||||
|
</CustomRadiosWithImage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 👉 Direction -->
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<h6 class="text-base font-weight-medium">
|
||||||
|
Direction
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<CustomRadiosWithImage
|
||||||
|
:key="currentDir"
|
||||||
|
v-model:selected-radio="currentDir"
|
||||||
|
:radio-content="direction"
|
||||||
|
:grid-column="{ cols: '4' }"
|
||||||
|
>
|
||||||
|
<template #label="item">
|
||||||
|
<span class="text-sm text-medium-emphasis">{{ item?.label }}</span>
|
||||||
|
</template>
|
||||||
|
</CustomRadiosWithImage>
|
||||||
|
</div>
|
||||||
|
</CustomizerSection>
|
||||||
|
<!-- !SECTION -->
|
||||||
|
</PerfectScrollbar>
|
||||||
|
</VNavigationDrawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.app-customizer {
|
||||||
|
.customizer-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1.25rem;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer-heading {
|
||||||
|
padding-block: 1rem;
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
|
||||||
|
.v-badge--dot {
|
||||||
|
.v-badge__badge {
|
||||||
|
block-size: 6px;
|
||||||
|
inline-size: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-navigation-drawer__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-label.custom-input {
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: transparent;
|
||||||
|
outline: 2px solid rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-label.custom-input:not(.active):hover {
|
||||||
|
border-color: rgba(var(--v-border-color), 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer-skins {
|
||||||
|
.custom-input.active {
|
||||||
|
.customizer-skins-icon-wrapper {
|
||||||
|
background-color: rgba(var(--v-global-theme-primary), var(--v-selected-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-customizer-primary-colors {
|
||||||
|
.primary-color-wrapper:not(.active) {
|
||||||
|
&:hover {
|
||||||
|
outline-color: rgba(var(--v-border-color), 0.22) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-customizer-toggler {
|
||||||
|
position: fixed !important;
|
||||||
|
inset-block-start: 20%;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
59
src/@core/components/ThemeSwitcher.vue
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
import type { ThemeSwitcherTheme } from '@layouts/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
themes: ThemeSwitcherTheme[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
const selectedItem = ref([configStore.theme])
|
||||||
|
|
||||||
|
// Update icon if theme is changed from other sources
|
||||||
|
watch(
|
||||||
|
() => configStore.theme,
|
||||||
|
() => {
|
||||||
|
selectedItem.value = [configStore.theme]
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon :icon="props.themes.find(t => t.name === configStore.theme)?.icon" />
|
||||||
|
|
||||||
|
<VTooltip
|
||||||
|
activator="parent"
|
||||||
|
open-delay="1000"
|
||||||
|
scroll-strategy="close"
|
||||||
|
>
|
||||||
|
<span class="text-capitalize">{{ configStore.theme }}</span>
|
||||||
|
</VTooltip>
|
||||||
|
<VMenu
|
||||||
|
activator="parent"
|
||||||
|
offset="15px"
|
||||||
|
width="160"
|
||||||
|
>
|
||||||
|
<VList
|
||||||
|
v-model:selected="selectedItem"
|
||||||
|
mandatory
|
||||||
|
>
|
||||||
|
<VListItem
|
||||||
|
v-for="{ name, icon } in props.themes"
|
||||||
|
:key="name"
|
||||||
|
:value="name"
|
||||||
|
:prepend-icon="icon"
|
||||||
|
color="primary"
|
||||||
|
class="text-capitalize px-4"
|
||||||
|
@click="() => { configStore.theme = name }"
|
||||||
|
>
|
||||||
|
<VListItemTitle class="text-capitalize">
|
||||||
|
{{ name }}
|
||||||
|
</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
160
src/@core/components/TiptapEditor.vue
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Placeholder } from '@tiptap/extension-placeholder'
|
||||||
|
import { TextAlign } from '@tiptap/extension-text-align'
|
||||||
|
import { Underline } from '@tiptap/extension-underline'
|
||||||
|
import { StarterKit } from '@tiptap/starter-kit'
|
||||||
|
import { EditorContent, useEditor } from '@tiptap/vue-3'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: string): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const editorRef = ref()
|
||||||
|
|
||||||
|
const editor = useEditor({
|
||||||
|
content: props.modelValue,
|
||||||
|
extensions: [
|
||||||
|
StarterKit,
|
||||||
|
TextAlign.configure({
|
||||||
|
types: ['heading', 'paragraph'],
|
||||||
|
}),
|
||||||
|
Placeholder.configure({
|
||||||
|
placeholder: 'Write something here...',
|
||||||
|
}),
|
||||||
|
Underline,
|
||||||
|
],
|
||||||
|
onUpdate() {
|
||||||
|
if (!editor.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
emit('update:modelValue', editor.value.getHTML())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, () => {
|
||||||
|
const isSame = editor.value?.getHTML() === props.modelValue
|
||||||
|
|
||||||
|
if (isSame)
|
||||||
|
return
|
||||||
|
|
||||||
|
editor.value?.commands.setContent(props.modelValue)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="pa-5">
|
||||||
|
<div
|
||||||
|
v-if="editor"
|
||||||
|
class="d-flex flex-wrap"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
:class="{ 'is-active': editor.isActive('bold') }"
|
||||||
|
icon="ri-bold"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
@click="editor.chain().focus().toggleBold().run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
:class="{ 'is-active': editor.isActive('underline') }"
|
||||||
|
icon="ri-underline"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
@click="editor.commands.toggleUnderline()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-italic"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive('italic') }"
|
||||||
|
@click="editor.chain().focus().toggleItalic().run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-strikethrough"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive('strike') }"
|
||||||
|
@click="editor.chain().focus().toggleStrike().run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-align-left"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }"
|
||||||
|
@click="editor.chain().focus().setTextAlign('left').run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-align-center"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }"
|
||||||
|
@click="editor.chain().focus().setTextAlign('center').run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-align-right"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }"
|
||||||
|
@click="editor.chain().focus().setTextAlign('right').run()"
|
||||||
|
/>
|
||||||
|
<VBtn
|
||||||
|
icon="ri-align-justify"
|
||||||
|
class="rounded"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="default"
|
||||||
|
:class="{ 'is-active': editor.isActive({ textAlign: 'justify' }) }"
|
||||||
|
@click="editor.chain().focus().setTextAlign('justify').run()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<VDivider class="mt-4 mb-2" />
|
||||||
|
<EditorContent
|
||||||
|
ref="editorRef"
|
||||||
|
:editor="editor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.ProseMirror {
|
||||||
|
padding: 0.5rem;
|
||||||
|
min-block-size: 15vh;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.is-editor-empty:first-child::before {
|
||||||
|
block-size: 0;
|
||||||
|
color: #adb5bd;
|
||||||
|
content: attr(data-placeholder);
|
||||||
|
float: inline-start;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.is-active {
|
||||||
|
border-color: rgba(var(--v-theme-primary), var(--v-border-opacity)) !important;
|
||||||
|
background-color: rgba(var(--v-theme-primary), var(--v-activated-opacity));
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
471
src/@core/components/app-form-elements/AppDateTimePicker.vue
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import FlatPickr from 'vue-flatpickr-component'
|
||||||
|
import { useTheme } from 'vuetify'
|
||||||
|
|
||||||
|
// @ts-expect-error There won't be declaration file for it
|
||||||
|
import { VField, filterFieldProps, makeVFieldProps } from 'vuetify/lib/components/VField/VField'
|
||||||
|
|
||||||
|
// @ts-expect-error There won't be declaration file for it
|
||||||
|
import { VInput, makeVInputProps } from 'vuetify/lib/components/VInput/VInput'
|
||||||
|
|
||||||
|
// @ts-expect-error There won't be declaration file for it
|
||||||
|
import { filterInputAttrs } from 'vuetify/lib/util/helpers'
|
||||||
|
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
|
||||||
|
// inherit Attribute make false
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
autofocus: Boolean,
|
||||||
|
counter: [Boolean, Number, String] as PropType<true | number | string>,
|
||||||
|
counterValue: Function as PropType<(value: any) => number>,
|
||||||
|
prefix: String,
|
||||||
|
placeholder: String,
|
||||||
|
persistentPlaceholder: Boolean,
|
||||||
|
persistentCounter: Boolean,
|
||||||
|
suffix: String,
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text',
|
||||||
|
},
|
||||||
|
modelModifiers: Object as PropType<Record<string, boolean>>,
|
||||||
|
...makeVInputProps({
|
||||||
|
density: 'comfortable',
|
||||||
|
hideDetails: 'auto',
|
||||||
|
}),
|
||||||
|
...makeVFieldProps({
|
||||||
|
variant: 'outlined',
|
||||||
|
color: 'primary',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'click:control', val: MouseEvent): true
|
||||||
|
(e: 'mousedown:control', val: MouseEvent): true
|
||||||
|
(e: 'update:focused', val: MouseEvent): true
|
||||||
|
(e: 'update:modelValue', val: string): void
|
||||||
|
(e: 'click:clear', el: MouseEvent): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const [rootAttrs, compAttrs] = filterInputAttrs(attrs)
|
||||||
|
|
||||||
|
const { modelValue: _, ...inputProps } = VInput.filterProps(props)
|
||||||
|
const fieldProps = filterFieldProps(props)
|
||||||
|
|
||||||
|
const refFlatPicker = ref()
|
||||||
|
const { focused } = useFocus(refFlatPicker)
|
||||||
|
const isCalendarOpen = ref(false)
|
||||||
|
const isInlinePicker = ref(false)
|
||||||
|
|
||||||
|
// flat picker prop manipulation
|
||||||
|
if (compAttrs.config && compAttrs.config.inline) {
|
||||||
|
isInlinePicker.value = compAttrs.config.inline
|
||||||
|
Object.assign(compAttrs, { altInputClass: 'inlinePicker' })
|
||||||
|
}
|
||||||
|
|
||||||
|
compAttrs.config = {
|
||||||
|
...compAttrs.config,
|
||||||
|
prevArrow: '<i class="ri-arrow-left-s-line v-icon" style="font-size: 22px; height: 22px; width: 22px;"></i>',
|
||||||
|
nextArrow: '<i class="ri-arrow-right-s-line v-icon" style="font-size: 22px; height: 22px; width: 22px;"></i>',
|
||||||
|
}
|
||||||
|
|
||||||
|
// v-field clear prop
|
||||||
|
const onClear = (el: MouseEvent) => {
|
||||||
|
el.stopPropagation()
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
emit('update:modelValue', '')
|
||||||
|
|
||||||
|
emit('click:clear', el)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const vuetifyTheme = useTheme()
|
||||||
|
|
||||||
|
const vuetifyThemesName = Object.keys(vuetifyTheme.themes.value)
|
||||||
|
|
||||||
|
// Themes class added to flat-picker component for light and dark support
|
||||||
|
const updateThemeClassInCalendar = () => {
|
||||||
|
// ℹ️ Flatpickr don't render it's instance in mobile and device simulator
|
||||||
|
if (!refFlatPicker.value.fp.calendarContainer)
|
||||||
|
return
|
||||||
|
|
||||||
|
vuetifyThemesName.forEach(t => {
|
||||||
|
refFlatPicker.value.fp.calendarContainer.classList.remove(`v-theme--${t}`)
|
||||||
|
})
|
||||||
|
refFlatPicker.value.fp.calendarContainer.classList.add(`v-theme--${vuetifyTheme.global.name.value}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => configStore.theme, updateThemeClassInCalendar)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
updateThemeClassInCalendar()
|
||||||
|
})
|
||||||
|
|
||||||
|
const emitModelValue = (val: string) => {
|
||||||
|
emit('update:modelValue', val)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="app-picker-field">
|
||||||
|
<VInput
|
||||||
|
v-bind="{ ...inputProps, ...rootAttrs }"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:hide-details="props.hideDetails"
|
||||||
|
:class="[{
|
||||||
|
'v-text-field--prefixed': props.prefix,
|
||||||
|
'v-text-field--suffixed': props.suffix,
|
||||||
|
'v-text-field--flush-details': ['plain', 'underlined'].includes(props.variant),
|
||||||
|
}, props.class]"
|
||||||
|
class="position-relative v-text-field"
|
||||||
|
:style="props.style"
|
||||||
|
>
|
||||||
|
<template #default="{ id, isDirty, isValid, isDisabled, isReadonly, validate }">
|
||||||
|
<!-- v-field -->
|
||||||
|
<VField
|
||||||
|
v-bind="{ ...fieldProps }"
|
||||||
|
:id="id.value"
|
||||||
|
role="textbox"
|
||||||
|
:active="focused || isDirty.value || isCalendarOpen"
|
||||||
|
:focused="focused || isCalendarOpen"
|
||||||
|
:dirty="isDirty.value || props.dirty"
|
||||||
|
:error="isValid.value === false"
|
||||||
|
:disabled="isDisabled.value"
|
||||||
|
@click:clear="onClear"
|
||||||
|
>
|
||||||
|
<template #default="{ props: vFieldProps }">
|
||||||
|
<div v-bind="vFieldProps">
|
||||||
|
<!-- flat-picker -->
|
||||||
|
<FlatPickr
|
||||||
|
v-if="!isInlinePicker"
|
||||||
|
v-bind="compAttrs"
|
||||||
|
ref="refFlatPicker"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:placeholder="props.placeholder"
|
||||||
|
:readonly="isReadonly.value"
|
||||||
|
class="flat-picker-custom-style"
|
||||||
|
:disabled="isReadonly.value"
|
||||||
|
@on-open="isCalendarOpen = true"
|
||||||
|
@on-close="isCalendarOpen = false; validate()"
|
||||||
|
@update:model-value="emitModelValue"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- simple input for inline prop -->
|
||||||
|
<input
|
||||||
|
v-if="isInlinePicker"
|
||||||
|
:value="modelValue"
|
||||||
|
:placeholder="props.placeholder"
|
||||||
|
:readonly="isReadonly.value"
|
||||||
|
class="flat-picker-custom-style"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VField>
|
||||||
|
</template>
|
||||||
|
</VInput>
|
||||||
|
|
||||||
|
<!-- flat picker for inline props -->
|
||||||
|
<FlatPickr
|
||||||
|
v-if="isInlinePicker"
|
||||||
|
v-bind="compAttrs"
|
||||||
|
ref="refFlatPicker"
|
||||||
|
:model-value="modelValue"
|
||||||
|
@update:model-value="emitModelValue"
|
||||||
|
@on-open="isCalendarOpen = true"
|
||||||
|
@on-close="isCalendarOpen = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
/* stylelint-disable no-descending-specificity */
|
||||||
|
@use "flatpickr/dist/flatpickr.css";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
.flat-picker-custom-style {
|
||||||
|
position: absolute;
|
||||||
|
color: inherit;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset: 0;
|
||||||
|
outline: none;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: var(--v-field-padding-start);
|
||||||
|
}
|
||||||
|
|
||||||
|
$heading-color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity));
|
||||||
|
$body-color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
|
||||||
|
// hide the input when your picker is inline
|
||||||
|
input[altinputclass="inlinePicker"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-calendar {
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
inline-size: 16.875rem;
|
||||||
|
|
||||||
|
@include mixins.elevation(6);
|
||||||
|
|
||||||
|
.flatpickr-day:focus {
|
||||||
|
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
background: rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-rContainer {
|
||||||
|
inline-size: 16.875rem;
|
||||||
|
|
||||||
|
.flatpickr-weekdays {
|
||||||
|
padding-inline: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-days {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
min-inline-size: 16.875rem;
|
||||||
|
|
||||||
|
.dayContainer {
|
||||||
|
justify-content: center !important;
|
||||||
|
inline-size: 16.875rem !important;
|
||||||
|
min-inline-size: 16.875rem !important;
|
||||||
|
padding-block: 0.75rem 0.5rem;
|
||||||
|
|
||||||
|
.flatpickr-day {
|
||||||
|
block-size: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
margin-block-start: 0 !important;
|
||||||
|
max-inline-size: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day {
|
||||||
|
color: $heading-color;
|
||||||
|
|
||||||
|
&.today {
|
||||||
|
&,
|
||||||
|
&:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: rgb(var(--v-theme-primary), 0.24);
|
||||||
|
color: rgba(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected,
|
||||||
|
&.selected:hover {
|
||||||
|
border-color: rgb(var(--v-theme-primary));
|
||||||
|
background: rgb(var(--v-theme-primary));
|
||||||
|
color: rgb(var(--v-theme-on-primary)) !important;
|
||||||
|
|
||||||
|
@include mixins.elevation(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inRange,
|
||||||
|
&.inRange:hover {
|
||||||
|
border: none;
|
||||||
|
background: rgba(var(--v-theme-primary), 0.1) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inRange.today {
|
||||||
|
background: rgba(var(--v-theme-primary), 0.24) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.startRange {
|
||||||
|
@include mixins.elevation(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.endRange {
|
||||||
|
@include mixins.elevation(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.startRange,
|
||||||
|
&.endRange,
|
||||||
|
&.startRange:hover,
|
||||||
|
&.endRange:hover {
|
||||||
|
border-color: rgb(var(--v-theme-primary));
|
||||||
|
background: rgb(var(--v-theme-primary));
|
||||||
|
color: rgb(var(--v-theme-on-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||||
|
&.startRange.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||||
|
&.endRange.startRange + .endRange:not(:nth-child(7n + 1)) {
|
||||||
|
box-shadow: -10px 0 0 rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flatpickr-disabled,
|
||||||
|
&.prevMonthDay:not(.startRange,.inRange),
|
||||||
|
&.nextMonthDay:not(.endRange,.inRange) {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-disabled-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
background: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-weekday {
|
||||||
|
color: $heading-color;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after,
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-months {
|
||||||
|
padding-block: 0.25rem;
|
||||||
|
padding-inline: 2px;
|
||||||
|
|
||||||
|
.flatpickr-prev-month,
|
||||||
|
.flatpickr-next-month {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
block-size: 38px;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
inline-size: 38px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
block-size: 13px;
|
||||||
|
inline-size: 13px;
|
||||||
|
stroke: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover i,
|
||||||
|
&:hover svg {
|
||||||
|
fill: $body-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-current-month {
|
||||||
|
padding-block: 6px 0;
|
||||||
|
padding-inline: 0;
|
||||||
|
|
||||||
|
span.cur-month {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
// Open calendar above overlay
|
||||||
|
z-index: 2401;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hasTime.open {
|
||||||
|
.flatpickr-time {
|
||||||
|
border: none;
|
||||||
|
block-size: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hasTime .flatpickr-time:first-child {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time picker hover & focus bg color
|
||||||
|
.flatpickr-time input:hover,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:hover,
|
||||||
|
.flatpickr-time input:focus,
|
||||||
|
.flatpickr-time .flatpickr-am-pm:focus {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time picker
|
||||||
|
.flatpickr-time {
|
||||||
|
input.flatpickr-hour {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-am-pm,
|
||||||
|
.flatpickr-time-separator,
|
||||||
|
input {
|
||||||
|
color: $heading-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numInputWrapper {
|
||||||
|
span {
|
||||||
|
&.arrowUp {
|
||||||
|
&::after {
|
||||||
|
border-block-end-color: rgb(var(--v-border-color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.arrowDown {
|
||||||
|
&::after {
|
||||||
|
border-block-start-color: rgb(var(--v-border-color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added bg color for flatpickr input only as it has default readonly attribute
|
||||||
|
.flatpickr-input[readonly],
|
||||||
|
.flatpickr-input ~ .form-control[readonly],
|
||||||
|
.flatpickr-human-friendly[readonly] {
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// week sections
|
||||||
|
.flatpickr-weekdays {
|
||||||
|
block-size: auto;
|
||||||
|
margin-block: 0.375rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month and year section
|
||||||
|
.flatpickr-current-month {
|
||||||
|
.flatpickr-monthDropdown-months {
|
||||||
|
appearance: none;
|
||||||
|
block-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-monthDropdown-months,
|
||||||
|
.numInputWrapper {
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: $heading-color;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 400;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.cur-year {
|
||||||
|
font-weight: 400 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-monthDropdown-month {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day.flatpickr-disabled,
|
||||||
|
.flatpickr-day.flatpickr-disabled:hover {
|
||||||
|
color: $body-color;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
77
src/@core/components/app-form-elements/CustomCheckboxes.vue
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { CustomInputContent, GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedCheckbox: string[]
|
||||||
|
checkboxContent: CustomInputContent[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedCheckbox', value: string[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string[] | null) => {
|
||||||
|
if (typeof value !== 'boolean' && value !== null)
|
||||||
|
emit('update:selectedCheckbox', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRow v-if="props.checkboxContent && props.selectedCheckbox">
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.checkboxContent"
|
||||||
|
:key="item.title"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-checkbox rounded-xl cursor-pointer"
|
||||||
|
:class="props.selectedCheckbox.includes(item.value) ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<VCheckbox
|
||||||
|
:model-value="props.selectedCheckbox"
|
||||||
|
:value="item.value"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<slot :item="item">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<div class="d-flex align-center mb-2">
|
||||||
|
<h6 class="cr-title text-base">
|
||||||
|
{{ item.title }}
|
||||||
|
</h6>
|
||||||
|
<VSpacer />
|
||||||
|
<span
|
||||||
|
v-if="item.subtitle"
|
||||||
|
class="text-sm text-disabled"
|
||||||
|
>{{ item.subtitle }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-medium-emphasis mb-0">
|
||||||
|
{{ item.desc }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</VLabel>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
|
.v-checkbox {
|
||||||
|
margin-block-start: -0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr-title {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { CustomInputContent, GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedCheckbox: string[]
|
||||||
|
checkboxContent: CustomInputContent[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedCheckbox', value: string[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string[] | null) => {
|
||||||
|
if (typeof value !== 'boolean' && value !== null)
|
||||||
|
emit('update:selectedCheckbox', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRow v-if="props.checkboxContent && props.selectedCheckbox">
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.checkboxContent"
|
||||||
|
:key="item.title"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-checkbox-icon rounded-xl cursor-pointer"
|
||||||
|
:class="props.selectedCheckbox.includes(item.value) ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<slot :item="item">
|
||||||
|
<div class="d-flex flex-column align-center text-center gap-2">
|
||||||
|
<VIcon
|
||||||
|
size="28"
|
||||||
|
:icon="item.icon"
|
||||||
|
class="text-high-emphasis"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h6 class="cr-title text-base">
|
||||||
|
{{ item.title }}
|
||||||
|
</h6>
|
||||||
|
<p class="text-sm text-medium-emphasis clamp-text mb-0">
|
||||||
|
{{ item.desc }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
<div>
|
||||||
|
<VCheckbox
|
||||||
|
:model-value="props.selectedCheckbox"
|
||||||
|
:value="item.value"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VLabel>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-checkbox-icon {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.v-checkbox {
|
||||||
|
margin-block-end: -0.375rem;
|
||||||
|
|
||||||
|
.v-selection-control__wrapper {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr-title {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.custom-checkbox-icon {
|
||||||
|
.v-checkbox {
|
||||||
|
margin-block-end: -0.375rem;
|
||||||
|
|
||||||
|
.v-selection-control__wrapper {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedCheckbox: string[]
|
||||||
|
checkboxContent: { bgImage: string; value: string; label?: string }[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedCheckbox', value: string[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string[] | null) => {
|
||||||
|
if (typeof value !== 'boolean' && value !== null)
|
||||||
|
emit('update:selectedCheckbox', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRow v-if="props.checkboxContent && props.selectedCheckbox">
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.checkboxContent"
|
||||||
|
:key="item.value"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-checkbox rounded-xl cursor-pointer w-100"
|
||||||
|
:class="props.selectedCheckbox.includes(item.value) ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<VCheckbox
|
||||||
|
:id="`custom-checkbox-with-img-${item.value}`"
|
||||||
|
:model-value="props.selectedCheckbox"
|
||||||
|
:value="item.value"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
:src="item.bgImage"
|
||||||
|
alt="bg-img"
|
||||||
|
class="custom-checkbox-image"
|
||||||
|
>
|
||||||
|
</VLabel>
|
||||||
|
|
||||||
|
<VLabel
|
||||||
|
v-if="item.label || $slots.label"
|
||||||
|
:for="`custom-checkbox-with-img-${item.value}`"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="label"
|
||||||
|
:label="item.label"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</slot>
|
||||||
|
</VLabel>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-checkbox {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.custom-checkbox-image {
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
min-inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-checkbox {
|
||||||
|
position: absolute;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
.v-checkbox {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
82
src/@core/components/app-form-elements/CustomRadios.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { CustomInputContent, GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedRadio: string
|
||||||
|
radioContent: CustomInputContent[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedRadio', value: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string | null) => {
|
||||||
|
if (value !== null)
|
||||||
|
emit('update:selectedRadio', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRadioGroup
|
||||||
|
v-if="props.radioContent"
|
||||||
|
:model-value="props.selectedRadio"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
>
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.radioContent"
|
||||||
|
:key="item.title"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-radio rounded-xl cursor-pointer"
|
||||||
|
:class="props.selectedRadio === item.value ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<VRadio
|
||||||
|
:name="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<slot :item="item">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<div class="d-flex align-center mb-2">
|
||||||
|
<h6 class="cr-title text-base">
|
||||||
|
{{ item.title }}
|
||||||
|
</h6>
|
||||||
|
<VSpacer />
|
||||||
|
<span
|
||||||
|
v-if="item.subtitle"
|
||||||
|
class="text-disabled text-sm"
|
||||||
|
>{{ item.subtitle }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-medium-emphasis mb-0">
|
||||||
|
{{ item.desc }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</VLabel>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VRadioGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-radio {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
|
.v-radio {
|
||||||
|
margin-block-start: -0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr-title {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { CustomInputContent, GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedRadio: string
|
||||||
|
radioContent: CustomInputContent[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedRadio', value: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string | null) => {
|
||||||
|
if (value !== null)
|
||||||
|
emit('update:selectedRadio', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRadioGroup
|
||||||
|
v-if="props.radioContent"
|
||||||
|
:model-value="props.selectedRadio"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
>
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.radioContent"
|
||||||
|
:key="item.title"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-radio-icon rounded-xl cursor-pointer"
|
||||||
|
:class="props.selectedRadio === item.value ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<slot :item="item">
|
||||||
|
<div class="d-flex flex-column align-center text-center gap-2">
|
||||||
|
<VIcon
|
||||||
|
size="28"
|
||||||
|
:icon="item.icon"
|
||||||
|
class="text-high-emphasis"
|
||||||
|
/>
|
||||||
|
<h6 class="cr-title text-base">
|
||||||
|
{{ item.title }}
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<p class="text-sm text-medium-emphasis mb-0 clamp-text">
|
||||||
|
{{ item.desc }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<VRadio :value="item.value" />
|
||||||
|
</div>
|
||||||
|
</VLabel>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VRadioGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-radio-icon {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.v-radio {
|
||||||
|
margin-block-end: -0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cr-title {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.custom-radio-icon {
|
||||||
|
.v-radio {
|
||||||
|
margin-block-end: -0.25rem;
|
||||||
|
|
||||||
|
.v-selection-control__wrapper {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
102
src/@core/components/app-form-elements/CustomRadiosWithImage.vue
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { GridColumn } from '@core/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedRadio: string
|
||||||
|
radioContent: { bgImage: string | undefined; value: string; label?: string }[]
|
||||||
|
gridColumn?: GridColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:selectedRadio', value: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const updateSelectedOption = (value: string | null) => {
|
||||||
|
if (value !== null)
|
||||||
|
emit('update:selectedRadio', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRadioGroup
|
||||||
|
v-if="props.radioContent"
|
||||||
|
:model-value="props.selectedRadio"
|
||||||
|
@update:model-value="updateSelectedOption"
|
||||||
|
>
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="item in props.radioContent"
|
||||||
|
:key="item.bgImage"
|
||||||
|
v-bind="gridColumn"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="d-flex flex-column"
|
||||||
|
style="gap: 2px;"
|
||||||
|
>
|
||||||
|
<VLabel
|
||||||
|
class="custom-input custom-radio rounded-xl cursor-pointer w-100"
|
||||||
|
:class="props.selectedRadio === item.value ? 'active' : ''"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="content"
|
||||||
|
:item="item"
|
||||||
|
>
|
||||||
|
<template v-if="typeof item.bgImage === 'object'">
|
||||||
|
<Component
|
||||||
|
:is="item.bgImage"
|
||||||
|
class="custom-radio-image"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
:src="item.bgImage"
|
||||||
|
alt="bg-img"
|
||||||
|
class="custom-radio-image"
|
||||||
|
>
|
||||||
|
</slot>
|
||||||
|
<VRadio
|
||||||
|
:id="`custom-radio-with-img-${item.value}`"
|
||||||
|
:name="`custom-radio-with-img-${item.value}`"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</VLabel>
|
||||||
|
<VLabel
|
||||||
|
v-if="item.label || $slots.label"
|
||||||
|
:for="`custom-radio-with-img-${item.value}`"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="label"
|
||||||
|
:label="item.label"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</slot>
|
||||||
|
</VLabel>
|
||||||
|
</div>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VRadioGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.custom-radio {
|
||||||
|
padding: 0 !important;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-radio-image {
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
min-inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-radio {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
167
src/@core/components/cards/AppCardActions.vue
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
collapsed?: boolean
|
||||||
|
noActions?: boolean
|
||||||
|
actionCollapsed?: boolean
|
||||||
|
actionRefresh?: boolean
|
||||||
|
actionRemove?: boolean
|
||||||
|
loading?: boolean | undefined
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'collapsed', isContentCollapsed: boolean): void
|
||||||
|
(e: 'refresh', stopLoading: () => void): void
|
||||||
|
(e: 'trash'): void
|
||||||
|
(e: 'initialLoad'): void
|
||||||
|
(e: 'update:loading', loading: boolean): void
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
collapsed: false,
|
||||||
|
noActions: false,
|
||||||
|
actionCollapsed: false,
|
||||||
|
actionRefresh: false,
|
||||||
|
actionRemove: false,
|
||||||
|
loading: undefined,
|
||||||
|
title: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const _loading = ref(false)
|
||||||
|
|
||||||
|
const $loading = computed({
|
||||||
|
get() {
|
||||||
|
return props.loading !== undefined ? props.loading : _loading.value
|
||||||
|
},
|
||||||
|
|
||||||
|
set(value: boolean) {
|
||||||
|
props.loading !== undefined ? emit('update:loading', value) : _loading.value = value
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const isContentCollapsed = ref(props.collapsed)
|
||||||
|
const isCardRemoved = ref(false)
|
||||||
|
|
||||||
|
// stop loading
|
||||||
|
const stopLoading = () => {
|
||||||
|
$loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger collapse
|
||||||
|
const triggerCollapse = () => {
|
||||||
|
isContentCollapsed.value = !isContentCollapsed.value
|
||||||
|
emit('collapsed', isContentCollapsed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger refresh
|
||||||
|
const triggerRefresh = () => {
|
||||||
|
$loading.value = true
|
||||||
|
emit('refresh', stopLoading)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger removal
|
||||||
|
const triggeredRemove = () => {
|
||||||
|
isCardRemoved.value = true
|
||||||
|
emit('trash')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VExpandTransition>
|
||||||
|
<!-- TODO remove div when transition work with v-card components: https://github.com/vuetifyjs/vuetify/issues/15111 -->
|
||||||
|
<div v-if="!isCardRemoved">
|
||||||
|
<VCard v-bind="$attrs">
|
||||||
|
<VCardItem>
|
||||||
|
<VCardTitle v-if="props.title || $slots.title">
|
||||||
|
<!-- 👉 Title slot and prop -->
|
||||||
|
<slot name="title">
|
||||||
|
{{ props.title }}
|
||||||
|
</slot>
|
||||||
|
</VCardTitle>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<!-- 👉 Before actions slot -->
|
||||||
|
<div>
|
||||||
|
<slot name="before-actions" />
|
||||||
|
|
||||||
|
<!-- SECTION Actions buttons -->
|
||||||
|
|
||||||
|
<!-- 👉 Collapse button -->
|
||||||
|
<IconBtn
|
||||||
|
v-if="(!(actionRemove || actionRefresh) || actionCollapsed) && !noActions"
|
||||||
|
@click="triggerCollapse"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-arrow-up-s-line"
|
||||||
|
:style="{ transform: isContentCollapsed ? 'rotate(-180deg)' : undefined }"
|
||||||
|
style="transition-duration: 0.28s;"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
|
||||||
|
<!-- 👉 Overlay button -->
|
||||||
|
<IconBtn
|
||||||
|
v-if="(!(actionRemove || actionCollapsed) || actionRefresh) && !noActions"
|
||||||
|
@click="triggerRefresh"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-refresh-line"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
|
||||||
|
<!-- 👉 Close button -->
|
||||||
|
<IconBtn
|
||||||
|
v-if="(!(actionRefresh || actionCollapsed) || actionRemove) && !noActions"
|
||||||
|
@click="triggeredRemove"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-close-line"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
<!-- !SECTION -->
|
||||||
|
</template>
|
||||||
|
</VCardItem>
|
||||||
|
|
||||||
|
<!-- 👉 card content -->
|
||||||
|
<VExpandTransition>
|
||||||
|
<div
|
||||||
|
v-show="!isContentCollapsed"
|
||||||
|
class="v-card-content"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</VExpandTransition>
|
||||||
|
|
||||||
|
<!-- 👉 Overlay -->
|
||||||
|
<VOverlay
|
||||||
|
v-model="$loading"
|
||||||
|
contained
|
||||||
|
persistent
|
||||||
|
scroll-strategy="none"
|
||||||
|
class="align-center justify-center"
|
||||||
|
>
|
||||||
|
<VProgressCircular indeterminate />
|
||||||
|
</VOverlay>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</VExpandTransition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.v-card-item {
|
||||||
|
+.v-card-content {
|
||||||
|
.v-card-text:first-child {
|
||||||
|
padding-block-start: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
151
src/@core/components/cards/AppCardCode.vue
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { getSingletonHighlighter } from 'shiki'
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
|
||||||
|
|
||||||
|
type CodeLanguages = 'ts' | 'js'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
code: CodeProp
|
||||||
|
codeLanguage?: string
|
||||||
|
noPadding?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodeProp = Record<CodeLanguages, string>
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
codeLanguage: 'markup',
|
||||||
|
noPadding: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const preferredCodeLanguage = useCookie<CodeLanguages>('preferredCodeLanguage', {
|
||||||
|
default: () => 'ts',
|
||||||
|
maxAge: COOKIE_MAX_AGE_1_YEAR,
|
||||||
|
})
|
||||||
|
|
||||||
|
const isCodeShown = ref(false)
|
||||||
|
|
||||||
|
const { copy, copied } = useClipboard({ source: computed(() => props.code[preferredCodeLanguage.value]) })
|
||||||
|
|
||||||
|
const highlighter = await getSingletonHighlighter({
|
||||||
|
themes: ['dracula', 'dracula-soft'],
|
||||||
|
langs: ['vue'],
|
||||||
|
})
|
||||||
|
|
||||||
|
const codeSnippet = highlighter.codeToHtml(props.code[preferredCodeLanguage.value], {
|
||||||
|
lang: 'vue',
|
||||||
|
theme: 'dracula',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- eslint-disable regex/invalid -->
|
||||||
|
<VCard class="app-card-code">
|
||||||
|
<VCardItem>
|
||||||
|
<VCardTitle>{{ props.title }}</VCardTitle>
|
||||||
|
<template #append>
|
||||||
|
<IconBtn
|
||||||
|
:color="isCodeShown ? 'primary' : 'default'"
|
||||||
|
:class="isCodeShown ? '' : 'text-disabled'"
|
||||||
|
@click="isCodeShown = !isCodeShown"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="20"
|
||||||
|
icon="ri-code-s-line"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VCardItem>
|
||||||
|
<slot v-if="noPadding" />
|
||||||
|
<VCardText v-else>
|
||||||
|
<slot />
|
||||||
|
</VCardText>
|
||||||
|
<VExpandTransition>
|
||||||
|
<div v-show="isCodeShown">
|
||||||
|
<VDivider />
|
||||||
|
|
||||||
|
<VCardText class="d-flex gap-y-3 flex-column">
|
||||||
|
<div class="d-flex justify-end">
|
||||||
|
<VBtnToggle
|
||||||
|
v-model="preferredCodeLanguage"
|
||||||
|
mandatory
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
value="ts"
|
||||||
|
icon
|
||||||
|
:variant="preferredCodeLanguage === 'ts' ? 'tonal' : 'text'"
|
||||||
|
:color="preferredCodeLanguage === 'ts' ? 'primary' : ''"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
icon="mdi-language-typescript"
|
||||||
|
:color="preferredCodeLanguage === 'ts' ? 'primary' : 'secondary'"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
value="js"
|
||||||
|
icon
|
||||||
|
:variant="preferredCodeLanguage === 'js' ? 'tonal' : 'text'"
|
||||||
|
:color="preferredCodeLanguage === 'js' ? 'primary' : ''"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
icon="mdi-language-javascript"
|
||||||
|
:color="preferredCodeLanguage === 'js' ? 'primary' : 'secondary'"
|
||||||
|
/>
|
||||||
|
</VBtn>
|
||||||
|
</VBtnToggle>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="position-relative">
|
||||||
|
<PerfectScrollbar
|
||||||
|
style="border-radius: 6px;max-block-size: 500px;"
|
||||||
|
:options="{ wheelPropagation: false, suppressScrollX: false }"
|
||||||
|
>
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
|
<span v-html="codeSnippet" />
|
||||||
|
</PerfectScrollbar>
|
||||||
|
<IconBtn
|
||||||
|
class="position-absolute app-card-code-copy-icon"
|
||||||
|
color="white"
|
||||||
|
@click="() => { copy() }"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="copied ? 'ri-check-line' : 'ri-file-copy-line'"
|
||||||
|
size="20"
|
||||||
|
/>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</div>
|
||||||
|
</VExpandTransition>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use "@styles/variables/vuetify";
|
||||||
|
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre) > code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
border-radius: vuetify.$card-border-radius;
|
||||||
|
max-block-size: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-card-code-copy-icon {
|
||||||
|
inset-block-start: 1.2em;
|
||||||
|
inset-inline-end: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-card-code {
|
||||||
|
.shiki {
|
||||||
|
padding: 0.75rem;
|
||||||
|
text-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
60
src/@core/components/cards/CardStatisticsHorizontal.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { kFormatter } from '@core/utils/formatters'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
color?: string
|
||||||
|
icon: string
|
||||||
|
stats: number
|
||||||
|
change: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
color: 'primary',
|
||||||
|
})
|
||||||
|
|
||||||
|
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<VAvatar
|
||||||
|
size="40"
|
||||||
|
rounded="lg"
|
||||||
|
:color="props.color"
|
||||||
|
variant="tonal"
|
||||||
|
class="me-4"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="props.icon"
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<div class="d-flex align-center flex-wrap gap-x-2">
|
||||||
|
<h5 class="text-h5">
|
||||||
|
${{ kFormatter(props.stats) }}
|
||||||
|
</h5>
|
||||||
|
<div
|
||||||
|
v-if="props.change"
|
||||||
|
class="d-flex align-center"
|
||||||
|
:class="`${isPositive ? 'text-success' : 'text-error'}`"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
size="24"
|
||||||
|
:icon="isPositive ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'"
|
||||||
|
/>
|
||||||
|
<div class="text-base">
|
||||||
|
{{ Math.abs(props.change) }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1">
|
||||||
|
{{ props.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
65
src/@core/components/cards/CardStatisticsVertical.vue
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
color?: string
|
||||||
|
icon: string
|
||||||
|
stats: string
|
||||||
|
change: number
|
||||||
|
subtitle: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
color: 'primary',
|
||||||
|
})
|
||||||
|
|
||||||
|
const isPositive = computed(() => Math.sign(props.change) === 1)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<VAvatar
|
||||||
|
v-if="props.icon"
|
||||||
|
rounded="lg"
|
||||||
|
variant="tonal"
|
||||||
|
:color="props.color"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="props.icon"
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<VSpacer />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="props.change"
|
||||||
|
:class="isPositive ? 'text-success' : 'text-error'"
|
||||||
|
class="d-flex align-center text-base mt-n4"
|
||||||
|
>
|
||||||
|
<span>{{ isPositive ? `+${props.change}` : props.change }}%</span>
|
||||||
|
|
||||||
|
<VIcon
|
||||||
|
:icon="isPositive ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'"
|
||||||
|
size="18"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
|
||||||
|
<VCardText>
|
||||||
|
<h5 class="text-h5 mb-1">
|
||||||
|
{{ props.stats }}
|
||||||
|
</h5>
|
||||||
|
<p>
|
||||||
|
{{ props.title }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<VChip
|
||||||
|
size="small"
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
<span class="text-truncate">{{ props.subtitle }}</span>
|
||||||
|
</VChip>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
47
src/@core/components/cards/CardStatisticsWithIcon.vue
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
title: string
|
||||||
|
value: string
|
||||||
|
change: number
|
||||||
|
desc: string
|
||||||
|
icon: string
|
||||||
|
iconColor: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VCard>
|
||||||
|
<VCardText>
|
||||||
|
<div class="d-flex justify-space-between">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<div class="text-body-1 text-high-emphasis">
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center gap-x-2">
|
||||||
|
<h4 class="text-h4">
|
||||||
|
{{ value }}
|
||||||
|
</h4>
|
||||||
|
<span
|
||||||
|
class="text-base"
|
||||||
|
:class="change > 0 ? 'text-success' : 'text-error'"
|
||||||
|
>({{ prefixWithPlus(change) }}%)</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-body-2">
|
||||||
|
{{ desc }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<VAvatar
|
||||||
|
:color="iconColor"
|
||||||
|
variant="tonal"
|
||||||
|
rounded="lg"
|
||||||
|
size="42"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="icon"
|
||||||
|
size="26"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
64
src/@core/components/cards/CardStatisticsWithImages.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
subtitle: string
|
||||||
|
stats: string
|
||||||
|
change: number
|
||||||
|
image: string
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
color: 'primary',
|
||||||
|
})
|
||||||
|
|
||||||
|
const isPositive = computed(() => Math.sign(props.change) === 1)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VCard class="position-relative">
|
||||||
|
<VCardText>
|
||||||
|
<h6 class="text-h6 mb-2">
|
||||||
|
{{ props.title }}
|
||||||
|
</h6>
|
||||||
|
<VChip
|
||||||
|
v-if="props.subtitle"
|
||||||
|
size="small"
|
||||||
|
:color="props.color"
|
||||||
|
class="mb-5"
|
||||||
|
>
|
||||||
|
{{ props.subtitle }}
|
||||||
|
</VChip>
|
||||||
|
|
||||||
|
<div class="d-flex align-center flex-wrap">
|
||||||
|
<h4 class="text-h4 me-2">
|
||||||
|
{{ props.stats }}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="text-body-1"
|
||||||
|
:class="isPositive ? 'text-success' : 'text-error'"
|
||||||
|
>
|
||||||
|
{{ isPositive ? `+${props.change}` : props.change }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
|
||||||
|
<VSpacer />
|
||||||
|
|
||||||
|
<div class="illustrator-img">
|
||||||
|
<img
|
||||||
|
v-if="props.image"
|
||||||
|
:src="props.image"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.illustrator-img {
|
||||||
|
position: absolute;
|
||||||
|
inset-block-end: -5%;
|
||||||
|
inset-inline-end: 5%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
src/@core/composable/createUrl.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { stringifyQuery } from 'ufo'
|
||||||
|
import type { MaybeRefOrGetter } from 'vue'
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
query: MaybeRefOrGetter<Record<string, any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createUrl = (url: MaybeRefOrGetter<string>, options?: Options) => computed(() => {
|
||||||
|
if (!options?.query)
|
||||||
|
return toValue(url)
|
||||||
|
|
||||||
|
const _url = toValue(url)
|
||||||
|
const _query = toValue(options?.query)
|
||||||
|
|
||||||
|
const queryObj = Object.fromEntries(
|
||||||
|
Object.entries(_query).map(([key, val]) => [key, toValue(val)]),
|
||||||
|
)
|
||||||
|
|
||||||
|
return `${_url}${queryObj ? `?${stringifyQuery(queryObj)}` : ''}`
|
||||||
|
})
|
||||||
43
src/@core/composable/useCookie.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Ported from [Nuxt](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts)
|
||||||
|
|
||||||
|
import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
||||||
|
import { parse, serialize } from 'cookie-es'
|
||||||
|
import { destr } from 'destr'
|
||||||
|
|
||||||
|
type _CookieOptions = Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'>
|
||||||
|
|
||||||
|
export interface CookieOptions<T = any> extends _CookieOptions {
|
||||||
|
decode?(value: string): T
|
||||||
|
encode?(value: T): string
|
||||||
|
default?: () => T | Ref<T>
|
||||||
|
watch?: boolean | 'shallow'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CookieRef<T> = Ref<T>
|
||||||
|
|
||||||
|
const CookieDefaults: CookieOptions<any> = {
|
||||||
|
path: '/',
|
||||||
|
watch: true,
|
||||||
|
decode: val => destr(decodeURIComponent(val)),
|
||||||
|
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val)),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCookie = <T = string | null | undefined>(name: string, _opts?: CookieOptions<T>): CookieRef<T> => {
|
||||||
|
const opts = { ...CookieDefaults, ..._opts || {} }
|
||||||
|
const cookies = parse(document.cookie, opts)
|
||||||
|
|
||||||
|
const cookie = ref<T | undefined>(cookies[name] as any ?? opts.default?.())
|
||||||
|
|
||||||
|
watch(cookie, () => {
|
||||||
|
document.cookie = serializeCookie(name, cookie.value, opts)
|
||||||
|
})
|
||||||
|
|
||||||
|
return cookie as CookieRef<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeCookie(name: string, value: any, opts: CookieSerializeOptions = {}) {
|
||||||
|
if (value === null || value === undefined)
|
||||||
|
return serialize(name, value, { ...opts, maxAge: -1 })
|
||||||
|
|
||||||
|
return serialize(name, value, { ...opts, maxAge: 60 * 60 * 24 * 30 })
|
||||||
|
}
|
||||||
28
src/@core/composable/useGenerateImageVariant.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { useTheme } from 'vuetify'
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
|
||||||
|
// composable function to return the image variant as per the current theme and skin
|
||||||
|
export const useGenerateImageVariant = (imgLight: string, imgDark: string, imgLightBordered?: string, imgDarkBordered?: string, bordered = false) => {
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
const { global } = useTheme()
|
||||||
|
|
||||||
|
return computed(() => {
|
||||||
|
if (global.name.value === 'light') {
|
||||||
|
if (configStore.skin === 'bordered' && bordered)
|
||||||
|
return imgLightBordered
|
||||||
|
|
||||||
|
else
|
||||||
|
return imgLight
|
||||||
|
}
|
||||||
|
if (global.name.value === 'dark') {
|
||||||
|
if (configStore.skin === 'bordered' && bordered)
|
||||||
|
return imgDarkBordered
|
||||||
|
|
||||||
|
else
|
||||||
|
return imgDark
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a default return statement
|
||||||
|
return imgLight
|
||||||
|
})
|
||||||
|
}
|
||||||
29
src/@core/composable/useResponsiveSidebar.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
export const useResponsiveLeftSidebar = (mobileBreakpoint: Ref<boolean> | undefined = undefined) => {
|
||||||
|
const { mdAndDown, name: currentBreakpoint } = useDisplay()
|
||||||
|
|
||||||
|
const _mobileBreakpoint = mobileBreakpoint || mdAndDown
|
||||||
|
|
||||||
|
const isLeftSidebarOpen = ref(true)
|
||||||
|
|
||||||
|
const setInitialValue = () => {
|
||||||
|
isLeftSidebarOpen.value = !_mobileBreakpoint.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the initial value of sidebar
|
||||||
|
setInitialValue()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
currentBreakpoint,
|
||||||
|
() => {
|
||||||
|
// Reset left sidebar
|
||||||
|
isLeftSidebarOpen.value = !_mobileBreakpoint.value
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLeftSidebarOpen,
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/@core/composable/useSkins.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { VThemeProvider } from 'vuetify/components/VThemeProvider'
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
import { AppContentLayoutNav } from '@layouts/enums'
|
||||||
|
|
||||||
|
// TODO: Use `VThemeProvider` from dist instead of lib (Using this component from dist causes navbar to loose sticky positioning)
|
||||||
|
|
||||||
|
export const useSkins = () => {
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
const layoutAttrs = computed(() => ({
|
||||||
|
verticalNavAttrs: {
|
||||||
|
wrapper: h(VThemeProvider, { tag: 'div' }),
|
||||||
|
wrapperProps: {
|
||||||
|
withBackground: true,
|
||||||
|
theme: (configStore.isVerticalNavSemiDark && configStore.appContentLayoutNav === AppContentLayoutNav.Vertical)
|
||||||
|
? 'dark'
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const injectSkinClasses = () => {
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
const bodyClasses = document.body.classList
|
||||||
|
const genSkinClass = (_skin?: string) => `skin--${_skin}`
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => configStore.skin,
|
||||||
|
(val, oldVal) => {
|
||||||
|
bodyClasses.remove(genSkinClass(oldVal))
|
||||||
|
bodyClasses.add(genSkinClass(val))
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
injectSkinClasses,
|
||||||
|
layoutAttrs,
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/@core/enums.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export const Skins = {
|
||||||
|
Default: 'default',
|
||||||
|
Bordered: 'bordered',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const Theme = {
|
||||||
|
Light: 'light',
|
||||||
|
Dark: 'dark',
|
||||||
|
System: 'system',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const Layout = {
|
||||||
|
Vertical: 'vertical',
|
||||||
|
Horizontal: 'horizontal',
|
||||||
|
Collapsed: 'collapsed',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const Direction = {
|
||||||
|
Ltr: 'ltr',
|
||||||
|
Rtl: 'rtl',
|
||||||
|
} as const
|
||||||
43
src/@core/index.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type { UserThemeConfig } from './types'
|
||||||
|
import type { LayoutConfig } from '@layouts/types'
|
||||||
|
|
||||||
|
export const defineThemeConfig = (userConfig: UserThemeConfig): { themeConfig: UserThemeConfig; layoutConfig: LayoutConfig } => {
|
||||||
|
return {
|
||||||
|
themeConfig: userConfig,
|
||||||
|
layoutConfig: {
|
||||||
|
app: {
|
||||||
|
title: userConfig.app.title,
|
||||||
|
logo: userConfig.app.logo,
|
||||||
|
contentWidth: userConfig.app.contentWidth,
|
||||||
|
contentLayoutNav: userConfig.app.contentLayoutNav,
|
||||||
|
overlayNavFromBreakpoint: userConfig.app.overlayNavFromBreakpoint,
|
||||||
|
i18n: {
|
||||||
|
enable: userConfig.app.i18n.enable,
|
||||||
|
},
|
||||||
|
iconRenderer: userConfig.app.iconRenderer,
|
||||||
|
},
|
||||||
|
navbar: {
|
||||||
|
type: userConfig.navbar.type,
|
||||||
|
navbarBlur: userConfig.navbar.navbarBlur,
|
||||||
|
},
|
||||||
|
footer: { type: userConfig.footer.type },
|
||||||
|
verticalNav: {
|
||||||
|
isVerticalNavCollapsed: userConfig.verticalNav.isVerticalNavCollapsed,
|
||||||
|
defaultNavItemIconProps: userConfig.verticalNav.defaultNavItemIconProps,
|
||||||
|
},
|
||||||
|
horizontalNav: {
|
||||||
|
type: userConfig.horizontalNav.type,
|
||||||
|
transition: userConfig.horizontalNav.transition,
|
||||||
|
popoverOffset: userConfig.horizontalNav.popoverOffset,
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
chevronDown: userConfig.icons.chevronDown,
|
||||||
|
chevronRight: userConfig.icons.chevronRight,
|
||||||
|
close: userConfig.icons.close,
|
||||||
|
verticalNavPinned: userConfig.icons.verticalNavPinned,
|
||||||
|
verticalNavUnPinned: userConfig.icons.verticalNavUnPinned,
|
||||||
|
sectionTitlePlaceholder: userConfig.icons.sectionTitlePlaceholder,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/@core/initCore.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { useStorage } from '@vueuse/core'
|
||||||
|
import { useTheme } from 'vuetify'
|
||||||
|
import { useConfigStore } from '@core/stores/config'
|
||||||
|
import { cookieRef, namespaceConfig } from '@layouts/stores/config'
|
||||||
|
import { themeConfig } from '@themeConfig'
|
||||||
|
|
||||||
|
const _syncAppRtl = () => {
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
const storedLang = cookieRef<string | null>('language', null)
|
||||||
|
|
||||||
|
const { locale } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
|
// TODO: Handle case where i18n can't read persisted value
|
||||||
|
if (locale.value !== storedLang.value && storedLang.value)
|
||||||
|
locale.value = storedLang.value
|
||||||
|
|
||||||
|
// watch and change lang attribute of html on language change
|
||||||
|
watch(
|
||||||
|
locale,
|
||||||
|
val => {
|
||||||
|
// Update lang attribute of html tag
|
||||||
|
if (typeof document !== 'undefined')
|
||||||
|
document.documentElement.setAttribute('lang', val as string)
|
||||||
|
|
||||||
|
// Store selected language in cookie
|
||||||
|
storedLang.value = val as string
|
||||||
|
|
||||||
|
// set isAppRtl value based on selected language
|
||||||
|
if (themeConfig.app.i18n.langConfig && themeConfig.app.i18n.langConfig.length) {
|
||||||
|
themeConfig.app.i18n.langConfig.forEach(lang => {
|
||||||
|
if (lang.i18nLang === storedLang.value)
|
||||||
|
configStore.isAppRTL = lang.isRTL
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const _handleSkinChanges = () => {
|
||||||
|
const { themes } = useTheme()
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
// Create skin default color so that we can revert back to original (default skin) color when switch to default skin from bordered skin
|
||||||
|
Object.values(themes.value).forEach(t => {
|
||||||
|
t.colors['skin-default-background'] = t.colors.background
|
||||||
|
t.colors['skin-default-surface'] = t.colors.surface
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => configStore.skin,
|
||||||
|
val => {
|
||||||
|
Object.values(themes.value).forEach(t => {
|
||||||
|
t.colors.background = t.colors[`skin-${val}-background`]
|
||||||
|
t.colors.surface = t.colors[`skin-${val}-surface`]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ Set current theme's surface color in localStorage
|
||||||
|
|
||||||
|
Why? Because when initial loader is shown (before vue is ready) we need to what's the current theme's surface color.
|
||||||
|
We will use color stored in localStorage to set the initial loader's background color.
|
||||||
|
|
||||||
|
With this we will be able to show correct background color for the initial loader even before vue identify the current theme.
|
||||||
|
*/
|
||||||
|
const _syncInitialLoaderTheme = () => {
|
||||||
|
const vuetifyTheme = useTheme()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => useConfigStore().theme,
|
||||||
|
() => {
|
||||||
|
// ℹ️ We are not using theme.current.colors.surface because watcher is independent and when this watcher is ran `theme` computed is not updated
|
||||||
|
useStorage<string | null>(namespaceConfig('initial-loader-bg'), null).value = vuetifyTheme.current.value.colors.surface
|
||||||
|
useStorage<string | null>(namespaceConfig('initial-loader-color'), null).value = vuetifyTheme.current.value.colors.primary
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCore = () => {
|
||||||
|
_syncInitialLoaderTheme()
|
||||||
|
_handleSkinChanges()
|
||||||
|
|
||||||
|
// ℹ️ We don't want to trigger i18n in SK
|
||||||
|
if (themeConfig.app.i18n.enable)
|
||||||
|
_syncAppRtl()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default initCore
|
||||||
701
src/@core/libs/apex-chart/apexCharConfig.ts
Normal file
@@ -0,0 +1,701 @@
|
|||||||
|
import type { ThemeInstance } from 'vuetify'
|
||||||
|
import { hexToRgb } from '@core/utils/colorConverter'
|
||||||
|
|
||||||
|
// 👉 Colors variables
|
||||||
|
const colorVariables = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const themeSecondaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['medium-emphasis-opacity']})`
|
||||||
|
const themeDisabledTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['disabled-opacity']})`
|
||||||
|
const themeBorderColor = `rgba(${hexToRgb(String(themeColors.variables['border-color']))},${themeColors.variables['border-opacity']})`
|
||||||
|
const themePrimaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['high-emphasis-opacity']})`
|
||||||
|
|
||||||
|
return { themeSecondaryTextColor, themeDisabledTextColor, themeBorderColor, themePrimaryTextColor }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const scatterColors = {
|
||||||
|
series1: '#ff9f43',
|
||||||
|
series2: '#7367f0',
|
||||||
|
series3: '#28c76f',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
zoom: {
|
||||||
|
type: 'xy',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
horizontalAlign: 'left',
|
||||||
|
markers: { offsetX: -3 },
|
||||||
|
|
||||||
|
labels: { colors: themeSecondaryTextColor },
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colors: [scatterColors.series1, scatterColors.series2, scatterColors.series3],
|
||||||
|
grid: {
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
tickAmount: 10,
|
||||||
|
axisBorder: { show: false },
|
||||||
|
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
formatter: (val: string) => Number.parseFloat(val).toFixed(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const getLineChartSimpleConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
zoom: { enabled: false },
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
colors: ['#ff9f43'],
|
||||||
|
stroke: { curve: 'straight' },
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
markers: {
|
||||||
|
strokeWidth: 7,
|
||||||
|
strokeOpacity: 1,
|
||||||
|
colors: ['#ff9f43'],
|
||||||
|
strokeColors: ['#fff'],
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
padding: { top: -10 },
|
||||||
|
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
custom(data: any) {
|
||||||
|
return `<div class='bar-chart pa-2'>
|
||||||
|
<span>${data.series[data.seriesIndex][data.dataPointIndex]}%</span>
|
||||||
|
</div>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
axisBorder: { show: false },
|
||||||
|
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
categories: [
|
||||||
|
'7/12',
|
||||||
|
'8/12',
|
||||||
|
'9/12',
|
||||||
|
'10/12',
|
||||||
|
'11/12',
|
||||||
|
'12/12',
|
||||||
|
'13/12',
|
||||||
|
'14/12',
|
||||||
|
'15/12',
|
||||||
|
'16/12',
|
||||||
|
'17/12',
|
||||||
|
'18/12',
|
||||||
|
'19/12',
|
||||||
|
'20/12',
|
||||||
|
'21/12',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
colors: ['#00cfe8'],
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
borderRadius: 8,
|
||||||
|
barHeight: '30%',
|
||||||
|
horizontal: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: false },
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
top: -10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
axisBorder: { show: false },
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
categories: ['MON, 11', 'THU, 14', 'FRI, 15', 'MON, 18', 'WED, 20', 'FRI, 21', 'MON, 23'],
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCandlestickChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const candlestickColors = {
|
||||||
|
series1: '#28c76f',
|
||||||
|
series2: '#ea5455',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: { columnWidth: '40%' },
|
||||||
|
candlestick: {
|
||||||
|
colors: {
|
||||||
|
upward: candlestickColors.series1,
|
||||||
|
downward: candlestickColors.series2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
padding: { top: -10 },
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
tooltip: { enabled: true },
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
type: 'datetime',
|
||||||
|
axisBorder: { show: false },
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const getRadialBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const radialBarColors = {
|
||||||
|
series1: '#fdd835',
|
||||||
|
series2: '#32baff',
|
||||||
|
series3: '#00d4bd',
|
||||||
|
series4: '#7367f0',
|
||||||
|
series5: '#FFA1A1',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
stroke: { lineCap: 'round' },
|
||||||
|
labels: ['Comments', 'Replies', 'Shares'],
|
||||||
|
legend: {
|
||||||
|
show: true,
|
||||||
|
position: 'bottom',
|
||||||
|
labels: {
|
||||||
|
colors: themeSecondaryTextColor,
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
offsetX: -3,
|
||||||
|
},
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colors: [radialBarColors.series1, radialBarColors.series2, radialBarColors.series4],
|
||||||
|
plotOptions: {
|
||||||
|
radialBar: {
|
||||||
|
hollow: { size: '30%' },
|
||||||
|
track: {
|
||||||
|
margin: 15,
|
||||||
|
background: themeColors.colors['grey-100'],
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
name: {
|
||||||
|
fontSize: '2rem',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
color: themeSecondaryTextColor,
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
show: true,
|
||||||
|
fontWeight: 400,
|
||||||
|
label: 'Comments',
|
||||||
|
fontSize: '1.125rem',
|
||||||
|
|
||||||
|
color: themePrimaryTextColor,
|
||||||
|
|
||||||
|
formatter(w: { globals: { seriesTotals: any[]; series: string | any[] } }) {
|
||||||
|
const totalValue
|
||||||
|
= w.globals.seriesTotals.reduce((a: number, b: number) => {
|
||||||
|
return a + b
|
||||||
|
}, 0) / w.globals.series.length
|
||||||
|
|
||||||
|
if (totalValue % 1 === 0)
|
||||||
|
return `${totalValue}%`
|
||||||
|
else
|
||||||
|
return `${totalValue.toFixed(2)}%`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
padding: {
|
||||||
|
top: -30,
|
||||||
|
bottom: -25,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDonutChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const donutColors = {
|
||||||
|
series1: '#fdd835',
|
||||||
|
series2: '#00d4bd',
|
||||||
|
series3: '#826bf8',
|
||||||
|
series4: '#32baff',
|
||||||
|
series5: '#ffa1a1',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themePrimaryTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
stroke: { width: 0 },
|
||||||
|
labels: ['Operational', 'Networking', 'Hiring', 'R&D'],
|
||||||
|
colors: [donutColors.series1, donutColors.series5, donutColors.series3, donutColors.series2],
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
formatter: (val: string) => `${Number.parseInt(val, 10)}%`,
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'bottom',
|
||||||
|
markers: { offsetX: -3 },
|
||||||
|
labels: { colors: themeSecondaryTextColor },
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
pie: {
|
||||||
|
donut: {
|
||||||
|
labels: {
|
||||||
|
show: true,
|
||||||
|
name: {
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
color: themeSecondaryTextColor,
|
||||||
|
formatter: (val: string) => `${Number.parseInt(val, 10)}`,
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
label: 'Operational',
|
||||||
|
formatter: () => '31%',
|
||||||
|
color: themePrimaryTextColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responsive: [
|
||||||
|
{
|
||||||
|
breakpoint: 992,
|
||||||
|
options: {
|
||||||
|
chart: {
|
||||||
|
height: 380,
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'bottom',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
breakpoint: 576,
|
||||||
|
options: {
|
||||||
|
chart: {
|
||||||
|
height: 320,
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
pie: {
|
||||||
|
donut: {
|
||||||
|
labels: {
|
||||||
|
show: true,
|
||||||
|
name: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAreaChartSplineConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const areaColors = {
|
||||||
|
series3: '#e0cffe',
|
||||||
|
series2: '#b992fe',
|
||||||
|
series1: '#ab7efd',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
tooltip: { shared: false },
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
stroke: {
|
||||||
|
show: false,
|
||||||
|
curve: 'straight',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
horizontalAlign: 'left',
|
||||||
|
|
||||||
|
labels: { colors: themeSecondaryTextColor },
|
||||||
|
markers: {
|
||||||
|
offsetY: 1,
|
||||||
|
offsetX: -3,
|
||||||
|
},
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
colors: [areaColors.series3, areaColors.series2, areaColors.series1],
|
||||||
|
fill: {
|
||||||
|
opacity: 1,
|
||||||
|
type: 'solid',
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
show: true,
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
axisBorder: { show: false },
|
||||||
|
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
categories: [
|
||||||
|
'7/12',
|
||||||
|
'8/12',
|
||||||
|
'9/12',
|
||||||
|
'10/12',
|
||||||
|
'11/12',
|
||||||
|
'12/12',
|
||||||
|
'13/12',
|
||||||
|
'14/12',
|
||||||
|
'15/12',
|
||||||
|
'16/12',
|
||||||
|
'17/12',
|
||||||
|
'18/12',
|
||||||
|
'19/12',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getColumnChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const columnColors = {
|
||||||
|
series1: '#826af9',
|
||||||
|
series2: '#d2b0ff',
|
||||||
|
bg: '#f8d3ff',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
offsetX: -10,
|
||||||
|
stacked: true,
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
fill: { opacity: 1 },
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
|
||||||
|
colors: [columnColors.series1, columnColors.series2],
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
horizontalAlign: 'left',
|
||||||
|
|
||||||
|
labels: { colors: themeSecondaryTextColor },
|
||||||
|
markers: {
|
||||||
|
offsetY: 1,
|
||||||
|
offsetX: -3,
|
||||||
|
},
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
show: true,
|
||||||
|
colors: ['transparent'],
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
columnWidth: '15%',
|
||||||
|
colors: {
|
||||||
|
backgroundBarRadius: 10,
|
||||||
|
|
||||||
|
backgroundBarColors: [columnColors.bg, columnColors.bg, columnColors.bg, columnColors.bg, columnColors.bg],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: themeBorderColor,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
axisBorder: { show: false },
|
||||||
|
|
||||||
|
axisTicks: { color: themeBorderColor },
|
||||||
|
categories: ['7/12', '8/12', '9/12', '10/12', '11/12', '12/12', '13/12', '14/12', '15/12'],
|
||||||
|
crosshairs: {
|
||||||
|
stroke: { color: themeBorderColor },
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: { colors: themeDisabledTextColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responsive: [
|
||||||
|
{
|
||||||
|
breakpoint: 600,
|
||||||
|
options: {
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
columnWidth: '35%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHeatMapChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { themeSecondaryTextColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
stroke: {
|
||||||
|
colors: [themeColors.colors.surface],
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'bottom',
|
||||||
|
labels: {
|
||||||
|
colors: themeSecondaryTextColor,
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
offsetY: 0,
|
||||||
|
offsetX: -3,
|
||||||
|
},
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
heatmap: {
|
||||||
|
enableShades: false,
|
||||||
|
colorScale: {
|
||||||
|
ranges: [
|
||||||
|
{ to: 10, from: 0, name: '0-10', color: '#b9b3f8' },
|
||||||
|
{ to: 20, from: 11, name: '10-20', color: '#aba4f6' },
|
||||||
|
{ to: 30, from: 21, name: '20-30', color: '#9d95f5' },
|
||||||
|
{ to: 40, from: 31, name: '30-40', color: '#8f85f3' },
|
||||||
|
{ to: 50, from: 41, name: '40-50', color: '#8176f2' },
|
||||||
|
{ to: 60, from: 51, name: '50-60', color: '#7367f0' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
padding: { top: -20 },
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
colors: themeDisabledTextColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
labels: { show: false },
|
||||||
|
axisTicks: { show: false },
|
||||||
|
axisBorder: { show: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const radarColors = {
|
||||||
|
series1: '#9b88fa',
|
||||||
|
series2: '#ffa1a1',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { themeSecondaryTextColor, themeBorderColor, themeDisabledTextColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
dropShadow: {
|
||||||
|
top: 1,
|
||||||
|
blur: 8,
|
||||||
|
left: 1,
|
||||||
|
opacity: 0.2,
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
markers: { size: 0 },
|
||||||
|
fill: { opacity: [1, 0.8] },
|
||||||
|
colors: [radarColors.series1, radarColors.series2],
|
||||||
|
stroke: {
|
||||||
|
width: 0,
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
labels: {
|
||||||
|
colors: themeSecondaryTextColor,
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
offsetX: -3,
|
||||||
|
},
|
||||||
|
itemMargin: {
|
||||||
|
vertical: 3,
|
||||||
|
horizontal: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
radar: {
|
||||||
|
polygons: {
|
||||||
|
strokeColors: themeBorderColor,
|
||||||
|
connectorColors: themeBorderColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
show: false,
|
||||||
|
padding: {
|
||||||
|
top: -20,
|
||||||
|
bottom: -20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: { show: false },
|
||||||
|
xaxis: {
|
||||||
|
categories: ['Battery', 'Brand', 'Camera', 'Memory', 'Storage', 'Display', 'OS', 'Price'],
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
colors: [
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
themeDisabledTextColor,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
372
src/@core/libs/chartjs/chartjsConfig.ts
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
import type { ThemeInstance } from 'vuetify'
|
||||||
|
import { hexToRgb } from '@core/utils/colorConverter'
|
||||||
|
|
||||||
|
// 👉 Colors variables
|
||||||
|
const colorVariables = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const themeSecondaryTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['medium-emphasis-opacity']})`
|
||||||
|
const themeDisabledTextColor = `rgba(${hexToRgb(themeColors.colors['on-surface'])},${themeColors.variables['disabled-opacity']})`
|
||||||
|
const themeBorderColor = `rgba(${hexToRgb(String(themeColors.variables['border-color']))},${themeColors.variables['border-opacity']})`
|
||||||
|
|
||||||
|
return { labelColor: themeDisabledTextColor, borderColor: themeBorderColor, legendColor: themeSecondaryTextColor }
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECTION config
|
||||||
|
|
||||||
|
// 👉 Latest Bar Chart Config
|
||||||
|
export const getLatestBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: { color: labelColor },
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 400,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 100,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Horizontal Bar Chart Config
|
||||||
|
export const getHorizontalBarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor, legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
indexAxis: 'y',
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
elements: {
|
||||||
|
bar: {
|
||||||
|
borderRadius: {
|
||||||
|
topRight: 15,
|
||||||
|
bottomRight: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
padding: { top: -4 },
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
min: 0,
|
||||||
|
grid: {
|
||||||
|
drawTicks: false,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: { color: labelColor },
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
display: false,
|
||||||
|
drawBorder: false,
|
||||||
|
},
|
||||||
|
ticks: { color: labelColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
align: 'end',
|
||||||
|
position: 'top',
|
||||||
|
labels: { color: legendColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Line Chart Config
|
||||||
|
export const getLineChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor, legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
ticks: { color: labelColor },
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 400,
|
||||||
|
ticks: {
|
||||||
|
stepSize: 100,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
align: 'end',
|
||||||
|
position: 'top',
|
||||||
|
labels: {
|
||||||
|
padding: 25,
|
||||||
|
boxWidth: 10,
|
||||||
|
color: legendColor,
|
||||||
|
usePointStyle: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Radar Chart Config
|
||||||
|
export const getRadarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor, legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
layout: {
|
||||||
|
padding: { top: -20 },
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
r: {
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
maxTicksLimit: 1,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
grid: { color: borderColor },
|
||||||
|
pointLabels: { color: labelColor },
|
||||||
|
angleLines: { color: borderColor },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
labels: {
|
||||||
|
padding: 25,
|
||||||
|
color: legendColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Polar Chart Config
|
||||||
|
export const getPolarChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
layout: {
|
||||||
|
padding: {
|
||||||
|
top: -5,
|
||||||
|
bottom: -45,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
r: {
|
||||||
|
grid: { display: false },
|
||||||
|
ticks: { display: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
padding: 25,
|
||||||
|
boxWidth: 9,
|
||||||
|
color: legendColor,
|
||||||
|
usePointStyle: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Bubble Chart Config
|
||||||
|
export const getBubbleChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
min: 0,
|
||||||
|
max: 140,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 10,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 400,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 100,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Doughnut Chart Config
|
||||||
|
export const getDoughnutChartConfig = () => {
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 500 },
|
||||||
|
cutout: 80,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Scatter Chart Config
|
||||||
|
export const getScatterChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor, legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: { duration: 800 },
|
||||||
|
layout: {
|
||||||
|
padding: { top: -20 },
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
min: 0,
|
||||||
|
max: 140,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawTicks: false,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 10,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 400,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
drawTicks: false,
|
||||||
|
drawBorder: false,
|
||||||
|
color: borderColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 100,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
align: 'start',
|
||||||
|
position: 'top',
|
||||||
|
labels: {
|
||||||
|
padding: 25,
|
||||||
|
boxWidth: 9,
|
||||||
|
color: legendColor,
|
||||||
|
usePointStyle: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Line Area Chart Config
|
||||||
|
export const getLineAreaChartConfig = (themeColors: ThemeInstance['themes']['value']['colors']) => {
|
||||||
|
const { borderColor, labelColor, legendColor } = colorVariables(themeColors)
|
||||||
|
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
layout: {
|
||||||
|
padding: { top: -20 },
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
color: 'transparent',
|
||||||
|
},
|
||||||
|
ticks: { color: labelColor },
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
min: 0,
|
||||||
|
max: 400,
|
||||||
|
grid: {
|
||||||
|
borderColor,
|
||||||
|
color: 'transparent',
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
stepSize: 100,
|
||||||
|
color: labelColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
align: 'start',
|
||||||
|
position: 'top',
|
||||||
|
labels: {
|
||||||
|
padding: 25,
|
||||||
|
boxWidth: 9,
|
||||||
|
color: legendColor,
|
||||||
|
usePointStyle: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// !SECTION
|
||||||
58
src/@core/libs/chartjs/components/BarChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Bar } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BarChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'bar-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'bar'>[]>,
|
||||||
|
default: () => ([]),
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Bar), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/BubbleChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { Chart as ChartJS, Legend, LinearScale, PointElement, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Bubble } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, PointElement, LinearScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BubbleChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'bubble-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'bubble'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Bubble), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/DoughnutChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { ArcElement, CategoryScale, Chart as ChartJS, Legend, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Doughnut } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DoughnutChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'doughnut-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'doughnut'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Doughnut), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/LineChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { CategoryScale, Chart as ChartJS, Legend, LineElement, LinearScale, PointElement, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Line } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'LineChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'line-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'line'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Line), {
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
options: props.chartOptions,
|
||||||
|
data: props.chartData,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/PolarAreaChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { ArcElement, Chart as ChartJS, Legend, RadialLinearScale, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { PolarArea } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, ArcElement, RadialLinearScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'PolarAreaChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'line-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'polarArea'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(PolarArea), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/RadarChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { Chart as ChartJS, Filler, Legend, LineElement, PointElement, RadialLinearScale, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Radar } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, PointElement, RadialLinearScale, LineElement, Filler)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RadarChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'radar-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'radar'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Radar), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
58
src/@core/libs/chartjs/components/ScatterChart.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { PluginOptionsByType } from 'chart.js'
|
||||||
|
import { CategoryScale, Chart as ChartJS, Legend, LineElement, LinearScale, PointElement, Title, Tooltip } from 'chart.js'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Scatter } from 'vue-chartjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, PointElement, LineElement, CategoryScale, LinearScale)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ScatterChart',
|
||||||
|
props: {
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: 'scatter-chart',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 400,
|
||||||
|
},
|
||||||
|
cssClasses: {
|
||||||
|
default: '',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object as PropType<Partial<CSSStyleDeclaration>>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: Array as PropType<PluginOptionsByType<'scatter'>[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
chartOptions: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
return () =>
|
||||||
|
h(h(Scatter), {
|
||||||
|
data: props.chartData,
|
||||||
|
options: props.chartOptions,
|
||||||
|
chartId: props.chartId,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
cssClasses: props.cssClasses,
|
||||||
|
styles: props.styles,
|
||||||
|
plugins: props.plugins,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
191
src/@core/scss/base/_components.scss
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
@use "mixins";
|
||||||
|
@use "@layouts/styles/placeholders";
|
||||||
|
@use "@layouts/styles/mixins" as layoutMixins;
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "@styles/variables/_vuetify.scss" as vuetify;
|
||||||
|
|
||||||
|
// 👉 Avatar group
|
||||||
|
.v-avatar-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-inline-start: -0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
transition: transform 0.25s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
z-index: 2;
|
||||||
|
transform: translateY(-5px) scale(1.05);
|
||||||
|
|
||||||
|
@include mixins.elevation(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .v-avatar {
|
||||||
|
border: 2px solid rgb(var(--v-theme-surface));
|
||||||
|
transition: transform 0.15s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Button outline with default color border color
|
||||||
|
.v-alert--variant-outlined,
|
||||||
|
.v-avatar--variant-outlined,
|
||||||
|
.v-btn.v-btn--variant-outlined,
|
||||||
|
.v-card--variant-outlined,
|
||||||
|
.v-chip--variant-outlined,
|
||||||
|
.v-list-item--variant-outlined {
|
||||||
|
&:not([class*="text-"]) {
|
||||||
|
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-default {
|
||||||
|
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Custom Input
|
||||||
|
.v-label.custom-input {
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
opacity: 1;
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(var(--v-border-color), 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: rgb(var(--v-theme-primary));
|
||||||
|
|
||||||
|
.v-icon {
|
||||||
|
color: rgb(var(--v-theme-primary)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.custom-checkbox,
|
||||||
|
&.custom-radio {
|
||||||
|
.v-input__control {
|
||||||
|
grid-area: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Datatable
|
||||||
|
.v-data-table-footer__pagination {
|
||||||
|
@include layoutMixins.rtl {
|
||||||
|
.v-btn {
|
||||||
|
.v-icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dialog responsive width
|
||||||
|
.v-dialog {
|
||||||
|
// dialog custom close btn
|
||||||
|
.v-dialog-close-btn {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)) !important;
|
||||||
|
inset-block-start: 0.5rem;
|
||||||
|
inset-inline-end: 0.5rem;
|
||||||
|
|
||||||
|
.v-btn__overlay {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card {
|
||||||
|
@extend %style-scroll-bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.v-dialog {
|
||||||
|
&.v-dialog-sm,
|
||||||
|
&.v-dialog-lg,
|
||||||
|
&.v-dialog-xl {
|
||||||
|
.v-overlay__content {
|
||||||
|
inline-size: 565px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.v-dialog {
|
||||||
|
&.v-dialog-lg,
|
||||||
|
&.v-dialog-xl {
|
||||||
|
.v-overlay__content {
|
||||||
|
inline-size: 865px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1264px) {
|
||||||
|
.v-dialog.v-dialog-xl {
|
||||||
|
.v-overlay__content {
|
||||||
|
inline-size: 1165px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Expansion panel
|
||||||
|
.v-expansion-panels.customized-panels {
|
||||||
|
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
border-radius: vuetify.$border-radius-root;
|
||||||
|
|
||||||
|
.v-expansion-panel-title {
|
||||||
|
background-color: rgb(var(--v-theme-expansion-panel-text-custom-bg));
|
||||||
|
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
margin-block-end: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-expansion-panel-text__wrapper {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// v-tab with pill support
|
||||||
|
.v-tabs.v-tabs-pill {
|
||||||
|
.v-tab.v-btn {
|
||||||
|
border-radius: 0.25rem !important;
|
||||||
|
transition: none;
|
||||||
|
|
||||||
|
.v-tab__slider {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for all colors bg
|
||||||
|
@each $color-name in variables.$theme-colors-name {
|
||||||
|
body .v-tabs.v-tabs-pill {
|
||||||
|
.v-slide-group__content {
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
.v-tab--selected.text-#{$color-name} {
|
||||||
|
background-color: rgb(var(--v-theme-#{$color-name}));
|
||||||
|
color: rgb(var(--v-theme-on-#{$color-name})) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ We are make even width of all v-timeline body
|
||||||
|
.v-timeline--vertical.v-timeline {
|
||||||
|
.v-timeline-item {
|
||||||
|
.v-timeline-item__body {
|
||||||
|
justify-self: stretch !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Switch
|
||||||
|
.v-switch .v-selection-control:not(.v-selection-control--dirty) .v-switch__thumb {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
16
src/@core/scss/base/_dark.scss
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
|
||||||
|
// ————————————————————————————————————
|
||||||
|
// * ——— Perfect Scrollbar
|
||||||
|
// ————————————————————————————————————
|
||||||
|
|
||||||
|
body.v-theme--dark {
|
||||||
|
.ps__rail-y,
|
||||||
|
.ps__rail-x {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__thumb-y {
|
||||||
|
background-color: variables.$plugin-ps-thumb-y-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/@core/scss/base/_default-layout-w-horizontal-nav.scss
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
@use "@core/scss/base/placeholders" as *;
|
||||||
|
@use "@core/scss/template/placeholders" as *;
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-horizontal {
|
||||||
|
.layout-navbar-and-nav-container {
|
||||||
|
@extend %default-layout-horizontal-nav-navbar-and-nav-container;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Navbar
|
||||||
|
.layout-navbar {
|
||||||
|
@extend %default-layout-horizontal-nav-navbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Layout content container
|
||||||
|
.navbar-content-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-horizontal-nav {
|
||||||
|
@extend %default-layout-horizontal-nav-nav;
|
||||||
|
|
||||||
|
.nav-items {
|
||||||
|
@extend %default-layout-horizontal-nav-nav-items-list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 App footer
|
||||||
|
.layout-footer {
|
||||||
|
@at-root {
|
||||||
|
.layout-footer-sticky#{&} {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
|
||||||
|
@include mixins.elevation(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use Vuetify grid sass variable here
|
||||||
|
.layout-page-content {
|
||||||
|
padding-block: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/@core/scss/base/_default-layout-w-vertical-nav.scss
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "@core/scss/base/placeholders" as *;
|
||||||
|
@use "@core/scss/template/placeholders" as *;
|
||||||
|
@use "misc";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
$header: ".layout-navbar";
|
||||||
|
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
$header: ".layout-navbar .navbar-content-container";
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical {
|
||||||
|
// SECTION Layout Navbar
|
||||||
|
// 👉 Elevated navbar
|
||||||
|
@if variables.$vertical-nav-navbar-style == "elevated" {
|
||||||
|
// Add transition
|
||||||
|
#{$header} {
|
||||||
|
transition: padding 0.2s ease, background-color 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If navbar is contained => Add border radius to header
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
#{$header} {
|
||||||
|
border-radius: 0 0 variables.$default-layout-with-vertical-nav-navbar-footer-roundness variables.$default-layout-with-vertical-nav-navbar-footer-roundness;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scrolled styles for sticky navbar
|
||||||
|
@at-root {
|
||||||
|
/* ℹ️ This html selector with not selector is required when:
|
||||||
|
dialog is opened and window don't have any scroll. This removes window-scrolled class from layout and our style broke
|
||||||
|
*/
|
||||||
|
html.v-overlay-scroll-blocked:not([style*="--v-body-scroll-y: 0px;"]) .layout-navbar-sticky,
|
||||||
|
&.window-scrolled.layout-navbar-sticky {
|
||||||
|
|
||||||
|
#{$header} {
|
||||||
|
@extend %default-layout-vertical-nav-scrolled-sticky-elevated-nav;
|
||||||
|
@extend %default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-blur#{$header} {
|
||||||
|
@extend %blurry-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Floating navbar
|
||||||
|
@else if variables.$vertical-nav-navbar-style == "floating" {
|
||||||
|
// ℹ️ Regardless of navbar is contained or not => Apply overlay to .layout-navbar
|
||||||
|
.layout-navbar {
|
||||||
|
&.navbar-blur {
|
||||||
|
@extend %default-layout-vertical-nav-floating-navbar-overlay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.layout-navbar-sticky) {
|
||||||
|
#{$header} {
|
||||||
|
margin-block-start: variables.$vertical-nav-floating-navbar-top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#{$header} {
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
border-radius: variables.$default-layout-with-vertical-nav-navbar-footer-roundness;
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
|
||||||
|
@extend %default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-blur#{$header} {
|
||||||
|
@extend %blurry-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// !SECTION
|
||||||
|
|
||||||
|
// 👉 Layout footer
|
||||||
|
.layout-footer {
|
||||||
|
$ele-layout-footer: &;
|
||||||
|
|
||||||
|
.footer-content-container {
|
||||||
|
border-radius: variables.$default-layout-with-vertical-nav-navbar-footer-roundness variables.$default-layout-with-vertical-nav-navbar-footer-roundness 0 0;
|
||||||
|
|
||||||
|
// Sticky footer
|
||||||
|
@at-root {
|
||||||
|
// ℹ️ .layout-footer-sticky#{$ele-layout-footer} => .layout-footer-sticky.layout-wrapper.layout-nav-type-vertical .layout-footer
|
||||||
|
.layout-footer-sticky#{$ele-layout-footer} {
|
||||||
|
.footer-content-container {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 1.2rem;
|
||||||
|
|
||||||
|
@include mixins.elevation(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/@core/scss/base/_default-layout.scss
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@use "@core/scss/base/placeholders";
|
||||||
|
@use "@core/scss/base/variables";
|
||||||
|
|
||||||
|
.layout-vertical-nav,
|
||||||
|
.layout-horizontal-nav {
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-navbar {
|
||||||
|
@if variables.$navbar-high-emphasis-text {
|
||||||
|
@extend %layout-navbar;
|
||||||
|
}
|
||||||
|
}
|
||||||
194
src/@core/scss/base/_horizontal-nav.scss
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
@use "@core/scss/base/placeholders" as *;
|
||||||
|
@use "@core/scss/template/placeholders" as *;
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
@use "vuetify/lib/styles/tools/states" as vuetifyStates;
|
||||||
|
|
||||||
|
.layout-horizontal-nav {
|
||||||
|
@extend %nav;
|
||||||
|
|
||||||
|
// 👉 Icon styles
|
||||||
|
.nav-item-icon {
|
||||||
|
@extend %horizontal-nav-item-icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Common styles for nav group & nav link
|
||||||
|
.nav-link,
|
||||||
|
.nav-group {
|
||||||
|
// 👉 Disabled nav items
|
||||||
|
&.disabled {
|
||||||
|
@extend %horizontal-nav-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set width of inner nav group and link
|
||||||
|
&.sub-item {
|
||||||
|
@extend %horizontal-nav-subitem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECTION Nav Link
|
||||||
|
.nav-link {
|
||||||
|
@extend %nav-link;
|
||||||
|
|
||||||
|
a {
|
||||||
|
@extend %horizontal-nav-item;
|
||||||
|
|
||||||
|
// Adds before psudo element to style hover state
|
||||||
|
@include mixins.before-pseudo;
|
||||||
|
|
||||||
|
// Adds vuetify states
|
||||||
|
@include vuetifyStates.states($active: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Top level nav link
|
||||||
|
&:not(.sub-item) {
|
||||||
|
a {
|
||||||
|
@extend %horizontal-nav-top-level-item;
|
||||||
|
|
||||||
|
&.router-link-active {
|
||||||
|
@extend %nav-link-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Sub link
|
||||||
|
&.sub-item {
|
||||||
|
a {
|
||||||
|
&.router-link-active {
|
||||||
|
// ℹ️ We will not use active styles from material here because we want to use primary color for active link
|
||||||
|
@extend %horizontal-nav-sub-nav-link-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// !SECTION
|
||||||
|
|
||||||
|
// SECTION Nav Group
|
||||||
|
.nav-group {
|
||||||
|
.popper-triggerer {
|
||||||
|
.nav-group-label {
|
||||||
|
@extend %horizontal-nav-item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .popper-triggerer > .nav-group-label {
|
||||||
|
// Adds before psudo element to style hover state
|
||||||
|
@include mixins.before-pseudo;
|
||||||
|
|
||||||
|
// Adds vuetify states
|
||||||
|
@include vuetifyStates.states($active: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popper-content {
|
||||||
|
@extend %horizontal-nav-popper-content-hidden;
|
||||||
|
@extend %horizontal-nav-popper-content;
|
||||||
|
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
|
||||||
|
// Set max-height for the popper content
|
||||||
|
> div {
|
||||||
|
max-block-size: variables.$horizontal-nav-popper-content-max-height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Top level group
|
||||||
|
&:not(.sub-item) {
|
||||||
|
> .popper-triggerer {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ The Bridge
|
||||||
|
This after pseudo will work as bridge when we have space between popper triggerer and popper content
|
||||||
|
Initially it will have pointer events none for normal behavior and once the content is shown it will
|
||||||
|
work as bridge by setting pointer events to `auto`
|
||||||
|
*/
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
block-size: variables.$horizontal-nav-popper-content-top;
|
||||||
|
content: "";
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 100%;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the pseudo bridge when content is shown by setting pointer events to `auto`
|
||||||
|
&.show-content > .popper-triggerer::after {
|
||||||
|
/*
|
||||||
|
ℹ️ We have added `z-index: 2` because when there is horizontal nav item below the popper trigger (group)
|
||||||
|
without this style nav item below popper trigger (group) gets focus hence closes the popper content
|
||||||
|
*/
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .popper-triggerer > .nav-group-label {
|
||||||
|
@extend %horizontal-nav-top-level-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
> .popper-triggerer > .nav-group-label {
|
||||||
|
@extend %nav-link-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ Add space between popper wrapper & content
|
||||||
|
> .popper-content {
|
||||||
|
margin-block-start: variables.$horizontal-nav-popper-content-top !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Sub group
|
||||||
|
&.sub-item {
|
||||||
|
&.active {
|
||||||
|
@include mixins.selected-states("> .popper-triggerer > .nav-group-label::before");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the icon's size of nested group's nav links (Top level group > Sub group > [Nav links])
|
||||||
|
.sub-item {
|
||||||
|
.nav-item-icon {
|
||||||
|
@extend %third-level-nav-item-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-arrow {
|
||||||
|
font-size: variables.$horizontal-nav-group-arrow-icon-size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ ml-auto won't matter in top level group (because we haven't specified fixed width for top level groups)
|
||||||
|
but we wrote generally because we don't want to become so specific
|
||||||
|
*/
|
||||||
|
margin-inline-start: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.popper-inline-end {
|
||||||
|
.nav-group-arrow {
|
||||||
|
transform: rotateZ(270deg);
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: rotateZ(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-title {
|
||||||
|
@extend %horizontal-nav-item-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show-content {
|
||||||
|
> .popper-content {
|
||||||
|
@extend %horizontal-nav-popper-content-visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.active) {
|
||||||
|
@include mixins.selected-states("> .popper-triggerer > .nav-group-label::before");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// !SECTION
|
||||||
|
}
|
||||||
48
src/@core/scss/base/_index.scss
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
@use "sass:map";
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
@use "vertical-nav";
|
||||||
|
@use "horizontal-nav";
|
||||||
|
@use "default-layout";
|
||||||
|
@use "default-layout-w-vertical-nav";
|
||||||
|
@use "default-layout-w-horizontal-nav";
|
||||||
|
|
||||||
|
// Layouts package
|
||||||
|
@use "layouts";
|
||||||
|
|
||||||
|
// Skins
|
||||||
|
@use "skins";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
@use "components";
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
@use "utilities";
|
||||||
|
|
||||||
|
// Route Transitions
|
||||||
|
@use "route-transitions";
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
@use "misc";
|
||||||
|
|
||||||
|
// Dark
|
||||||
|
@use "dark";
|
||||||
|
|
||||||
|
// libs
|
||||||
|
@use "libs/perfect-scrollbar";
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vuetify 3 don't provide margin bottom style like vuetify 2
|
||||||
|
p {
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iconify icon size
|
||||||
|
svg.iconify {
|
||||||
|
block-size: 1em;
|
||||||
|
inline-size: 1em;
|
||||||
|
}
|
||||||
63
src/@core/scss/base/_layouts.scss
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
|
||||||
|
/* ℹ️ This styles extends the existing layout package's styles for handling cases that aren't related to layouts package */
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ When we use v-layout as immediate first child of `.page-content-container`, it adds display:flex and page doesn't get contained height
|
||||||
|
*/
|
||||||
|
// .layout-wrapper.layout-nav-type-vertical {
|
||||||
|
// &.layout-content-height-fixed {
|
||||||
|
// .page-content-container {
|
||||||
|
// > .v-layout:first-child > :not(.v-navigation-drawer):first-child {
|
||||||
|
// flex-grow: 1;
|
||||||
|
// block-size: 100%;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
.layout-wrapper.layout-nav-type-vertical {
|
||||||
|
&.layout-content-height-fixed {
|
||||||
|
.page-content-container {
|
||||||
|
> .v-layout:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
min-block-size: 100%;
|
||||||
|
|
||||||
|
> .v-main {
|
||||||
|
// overflow-y: auto;
|
||||||
|
|
||||||
|
.v-main__wrap > :first-child {
|
||||||
|
block-size: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ Let div/v-layout take full height. E.g. Email App
|
||||||
|
.layout-wrapper.layout-nav-type-horizontal {
|
||||||
|
&.layout-content-height-fixed {
|
||||||
|
> .layout-page-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Floating navbar styles
|
||||||
|
@if variables.$vertical-nav-navbar-style == "floating" {
|
||||||
|
// ℹ️ Add spacing above navbar if navbar is floating (was in %layout-navbar-sticky placeholder)
|
||||||
|
body .layout-wrapper.layout-nav-type-vertical.layout-navbar-sticky {
|
||||||
|
.layout-navbar {
|
||||||
|
inset-block-start: variables.$vertical-nav-floating-navbar-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ If it's floating navbar
|
||||||
|
Add `vertical-nav-floating-navbar-top` as margin top to .layout-page-content
|
||||||
|
*/
|
||||||
|
.layout-page-content {
|
||||||
|
margin-block-start: variables.$vertical-nav-floating-navbar-top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/@core/scss/base/_misc.scss
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// ℹ️ scrollable-content allows creating fixed header and scrollable content for VNavigationDrawer (Used when perfect scrollbar is used)
|
||||||
|
.scrollable-content {
|
||||||
|
&.v-navigation-drawer {
|
||||||
|
.v-navigation-drawer__content {
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ adding styling for code tag
|
||||||
|
code {
|
||||||
|
border-radius: 3px;
|
||||||
|
color: rgb(var(--v-code-color));
|
||||||
|
font-size: 90%;
|
||||||
|
font-weight: 400;
|
||||||
|
padding-block: 0.2em;
|
||||||
|
padding-inline: 0.4em;
|
||||||
|
}
|
||||||
63
src/@core/scss/base/_mixins.scss
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
@use "sass:map";
|
||||||
|
@use "@styles/variables/vuetify.scss";
|
||||||
|
|
||||||
|
@mixin elevation($z, $important: false) {
|
||||||
|
box-shadow: map.get(vuetify.$shadow-key-umbra, $z), map.get(vuetify.$shadow-key-penumbra, $z), map.get(vuetify.$shadow-key-ambient, $z) if($important, !important, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region before-pseudo
|
||||||
|
// ℹ️ This mixin is inspired from vuetify for adding hover styles via before pseudo element
|
||||||
|
@mixin before-pseudo() {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: currentcolor;
|
||||||
|
block-size: 100%;
|
||||||
|
content: "";
|
||||||
|
inline-size: 100%;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion before-pseudo
|
||||||
|
|
||||||
|
@mixin bordered-skin($component, $border-property: "border", $important: false) {
|
||||||
|
#{$component} {
|
||||||
|
box-shadow: none !important;
|
||||||
|
// stylelint-disable-next-line annotation-no-unknown
|
||||||
|
#{$border-property}: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)) if($important, !important, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region selected-states
|
||||||
|
// ℹ️ Inspired from vuetify's active-states mixin
|
||||||
|
// focus => 0.12 & selected => 0.08
|
||||||
|
@mixin selected-states($selector) {
|
||||||
|
#{$selector} {
|
||||||
|
opacity: calc(var(--v-selected-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
#{$selector} {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-hover-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible
|
||||||
|
#{$selector} {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports not selector(:focus-visible) {
|
||||||
|
&:focus {
|
||||||
|
#{$selector} {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion selected-states
|
||||||
70
src/@core/scss/base/_route-transitions.scss
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// 👉 Zoom fade
|
||||||
|
.app-transition-zoom-fade-enter-active,
|
||||||
|
.app-transition-zoom-fade-leave-active {
|
||||||
|
transition: transform 0.35s, opacity 0.28s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-zoom-fade-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-zoom-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Fade
|
||||||
|
.app-transition-fade-enter-active,
|
||||||
|
.app-transition-fade-leave-active {
|
||||||
|
transition: opacity 0.25s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-fade-enter-from,
|
||||||
|
.app-transition-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Fade bottom
|
||||||
|
.app-transition-fade-bottom-enter-active,
|
||||||
|
.app-transition-fade-bottom-leave-active {
|
||||||
|
transition: opacity 0.3s, transform 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-fade-bottom-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-0.6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-fade-bottom-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(0.6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Slide fade
|
||||||
|
.app-transition-slide-fade-enter-active,
|
||||||
|
.app-transition-slide-fade-leave-active {
|
||||||
|
transition: opacity 0.3s, transform 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-slide-fade-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-0.6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-slide-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(0.6rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Zoom out
|
||||||
|
.app-transition-zoom-out-enter-active,
|
||||||
|
.app-transition-zoom-out-leave-active {
|
||||||
|
transition: opacity 0.26s ease-in-out, transform 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-transition-zoom-out-enter-from,
|
||||||
|
.app-transition-zoom-out-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
183
src/@core/scss/base/_utilities.scss
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||||
|
|
||||||
|
/* 👉 Demo spacers */
|
||||||
|
|
||||||
|
/* TODO: Use vuetify SCSS variable here; */
|
||||||
|
$card-spacer-content: 16px;
|
||||||
|
|
||||||
|
.demo-space-x {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
margin-block-start: -$card-spacer-content;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
margin-block-start: $card-spacer-content;
|
||||||
|
margin-inline-end: $card-spacer-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-space-y {
|
||||||
|
& > * {
|
||||||
|
margin-block-end: $card-spacer-content;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Card match height
|
||||||
|
.match-height.v-row {
|
||||||
|
.v-card {
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Whitespace
|
||||||
|
.whitespace-no-wrap {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Colors
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ Vuetify is applying `.text-white` class to badge icon but don't provide its styles
|
||||||
|
Moreover, we also use this class in some places
|
||||||
|
|
||||||
|
ℹ️ In vuetify 2 with `$color-pack: false` SCSS var config this class was getting generated but this is not the case in v3
|
||||||
|
|
||||||
|
ℹ️ We also need !important to get correct color in badge icon
|
||||||
|
*/
|
||||||
|
.text-white {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-white-variant {
|
||||||
|
color: rgba(255, 255, 255, var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-link {
|
||||||
|
&:not(:hover) {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-var-theme-background {
|
||||||
|
background-color: rgba(var(--v-theme-on-background), var(--v-hover-opacity)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-global-primary {
|
||||||
|
background-color: rgb(var(--v-global-theme-primary)) !important;
|
||||||
|
color: rgb(var(--v-theme-on-primary)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [/^bg-light-(\w+)$/, ([, w]) => ({ backgroundColor: `rgba(var(--v-theme-${w}), var(--v-activated-opacity))` })],
|
||||||
|
@each $color-name in variables.$theme-colors-name {
|
||||||
|
.bg-light-#{$color-name} {
|
||||||
|
background-color: rgba(var(--v-theme-#{$color-name}), var(--v-activated-opacity)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 clamp text
|
||||||
|
.clamp-text {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-badge {
|
||||||
|
.v-badge__badge {
|
||||||
|
border-radius: 6px !important;
|
||||||
|
block-size: 12px !important;
|
||||||
|
inline-size: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.leading-normal {
|
||||||
|
line-height: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 for rtl only
|
||||||
|
.flip-in-rtl {
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Carousel
|
||||||
|
.carousel-delimiter-top-end {
|
||||||
|
.v-carousel__controls {
|
||||||
|
justify-content: end;
|
||||||
|
block-size: 40px;
|
||||||
|
inset-block-start: 0;
|
||||||
|
padding-inline: 1rem;
|
||||||
|
|
||||||
|
.v-btn--icon.v-btn--density-default {
|
||||||
|
block-size: calc(var(--v-btn-height) + -10px);
|
||||||
|
inline-size: calc(var(--v-btn-height) + -8px);
|
||||||
|
|
||||||
|
&.v-btn--active {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn__overlay {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-ripple__container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn__content {
|
||||||
|
.v-icon {
|
||||||
|
block-size: 8px !important;
|
||||||
|
font-size: 8px !important;
|
||||||
|
inline-size: 8px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $color-name in variables.$theme-colors-name {
|
||||||
|
|
||||||
|
&.dots-active-#{$color-name} {
|
||||||
|
.v-carousel__controls {
|
||||||
|
.v-btn--active {
|
||||||
|
color: rgb(var(--v-theme-#{$color-name})) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-timeline-item {
|
||||||
|
.app-timeline-title {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.3125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-timeline-meta {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-timeline-text {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-chip {
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||||
|
padding-block: 5px;
|
||||||
|
padding-inline: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/@core/scss/base/_utils.scss
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@use "sass:map";
|
||||||
|
@use "sass:list";
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
|
||||||
|
// Thanks: https://css-tricks.com/snippets/sass/deep-getset-maps/
|
||||||
|
@function map-deep-get($map, $keys...) {
|
||||||
|
@each $key in $keys {
|
||||||
|
$map: map.get($map, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@function map-deep-set($map, $keys, $value) {
|
||||||
|
$maps: ($map,);
|
||||||
|
$result: null;
|
||||||
|
|
||||||
|
// If the last key is a map already
|
||||||
|
// Warn the user we will be overriding it with $value
|
||||||
|
@if type-of(nth($keys, -1)) == "map" {
|
||||||
|
@warn "The last key you specified is a map; it will be overrided with `#{$value}`.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If $keys is a single key
|
||||||
|
// Just merge and return
|
||||||
|
@if length($keys) == 1 {
|
||||||
|
@return map-merge($map, ($keys: $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop from the first to the second to last key from $keys
|
||||||
|
// Store the associated map to this key in the $maps list
|
||||||
|
// If the key doesn't exist, throw an error
|
||||||
|
@for $i from 1 through length($keys) - 1 {
|
||||||
|
$current-key: list.nth($keys, $i);
|
||||||
|
$current-map: list.nth($maps, -1);
|
||||||
|
$current-get: map.get($current-map, $current-key);
|
||||||
|
|
||||||
|
@if not $current-get {
|
||||||
|
@error "Key `#{$key}` doesn't exist at current level in map.";
|
||||||
|
}
|
||||||
|
|
||||||
|
$maps: list.append($maps, $current-get);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop from the last map to the first one
|
||||||
|
// Merge it with the previous one
|
||||||
|
@for $i from length($maps) through 1 {
|
||||||
|
$current-map: list.nth($maps, $i);
|
||||||
|
$current-key: list.nth($keys, $i);
|
||||||
|
$current-val: if($i == list.length($maps), $value, $result);
|
||||||
|
$result: map.map-merge($current-map, ($current-key: $current-val));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
@return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// font size utility classes
|
||||||
|
@each $name, $size in variables.$font-sizes {
|
||||||
|
.text-#{$name} {
|
||||||
|
font-size: $size;
|
||||||
|
line-height: map.get(variables.$font-line-height, $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate utility class
|
||||||
|
.truncate {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gap utility class
|
||||||
|
@each $name, $size in variables.$gap {
|
||||||
|
.gap-#{$name} {
|
||||||
|
gap: $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-#{$name} {
|
||||||
|
column-gap: $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-#{$name} {
|
||||||
|
row-gap: $size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-none {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
198
src/@core/scss/base/_variables.scss
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
@use "vuetify/lib/styles/tools/functions" as *;
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Add docs on when to use placeholder vs when to use SASS variable
|
||||||
|
|
||||||
|
Placeholder
|
||||||
|
- When we want to keep customization to our self between templates use it
|
||||||
|
|
||||||
|
Variables
|
||||||
|
- When we want to allow customization from both user and our side
|
||||||
|
- You can also use variable for consistency (e.g. mx 1 rem should be applied to both vertical nav items and vertical nav header)
|
||||||
|
*/
|
||||||
|
|
||||||
|
@forward "@layouts/styles/variables" with (
|
||||||
|
// Adjust z-index so vertical nav & overlay stays on top of v-layout in v-main. E.g. Email app
|
||||||
|
$layout-vertical-nav-z-index: 1003,
|
||||||
|
$layout-overlay-z-index: 1002,
|
||||||
|
);
|
||||||
|
@use "@layouts/styles/variables" as *;
|
||||||
|
|
||||||
|
// 👉 Default layout
|
||||||
|
|
||||||
|
$navbar-high-emphasis-text: true !default;
|
||||||
|
|
||||||
|
// @forward "@layouts/styles/variables" with (
|
||||||
|
// $layout-vertical-nav-width: 350px !default,
|
||||||
|
// );
|
||||||
|
|
||||||
|
$theme-colors-name: (
|
||||||
|
"primary",
|
||||||
|
"secondary",
|
||||||
|
"error",
|
||||||
|
"info",
|
||||||
|
"success",
|
||||||
|
"warning"
|
||||||
|
) !default;
|
||||||
|
|
||||||
|
// 👉 Default layout with vertical nav
|
||||||
|
|
||||||
|
$default-layout-with-vertical-nav-navbar-footer-roundness: 10px !default;
|
||||||
|
|
||||||
|
// 👉 Vertical nav
|
||||||
|
$vertical-nav-background-color-rgb: var(--v-theme-background) !default;
|
||||||
|
$vertical-nav-background-color: rgb(#{$vertical-nav-background-color-rgb}) !default;
|
||||||
|
|
||||||
|
// ℹ️ This is used to keep consistency between nav items and nav header left & right margin
|
||||||
|
// This is used by nav items & nav header
|
||||||
|
$vertical-nav-horizontal-spacing: 1rem !default;
|
||||||
|
$vertical-nav-horizontal-padding: 0.75rem !default;
|
||||||
|
|
||||||
|
// Vertical nav header height. Mostly we will align it with navbar height;
|
||||||
|
$vertical-nav-header-height: $layout-vertical-nav-navbar-height !default;
|
||||||
|
$vertical-nav-navbar-elevation: 3 !default;
|
||||||
|
$vertical-nav-navbar-style: "elevated" !default; // options: elevated, floating
|
||||||
|
$vertical-nav-floating-navbar-top: 1rem !default;
|
||||||
|
|
||||||
|
// Vertical nav header padding
|
||||||
|
$vertical-nav-header-padding: 1rem $vertical-nav-horizontal-padding !default;
|
||||||
|
$vertical-nav-header-inline-spacing: $vertical-nav-horizontal-spacing !default;
|
||||||
|
|
||||||
|
// Move logo when vertical nav is mini (collapsed but not hovered)
|
||||||
|
$vertical-nav-header-logo-translate-x-when-vertical-nav-mini: -4px !default;
|
||||||
|
|
||||||
|
// Space between logo and title
|
||||||
|
$vertical-nav-header-logo-title-spacing: 0.9rem !default;
|
||||||
|
|
||||||
|
// Section title margin top (when its not first child)
|
||||||
|
$vertical-nav-section-title-mt: 1.5rem !default;
|
||||||
|
|
||||||
|
// Section title margin bottom
|
||||||
|
$vertical-nav-section-title-mb: 0.5rem !default;
|
||||||
|
|
||||||
|
// Vertical nav icons
|
||||||
|
$vertical-nav-items-icon-size: 1.5rem !default;
|
||||||
|
$vertical-nav-items-nested-icon-size: 0.9rem !default;
|
||||||
|
$vertical-nav-items-icon-margin-inline-end: 0.5rem !default;
|
||||||
|
|
||||||
|
// Transition duration for nav group arrow
|
||||||
|
$vertical-nav-nav-group-arrow-transition-duration: 0.15s !default;
|
||||||
|
|
||||||
|
// Timing function for nav group arrow
|
||||||
|
$vertical-nav-nav-group-arrow-transition-timing-function: ease-in-out !default;
|
||||||
|
|
||||||
|
// 👉 Horizontal nav
|
||||||
|
|
||||||
|
/*
|
||||||
|
❗ Heads up
|
||||||
|
==================
|
||||||
|
Here we assume we will always use shorthand property which will apply same padding on four side
|
||||||
|
This is because this have been used as value of top property by `.popper-content`
|
||||||
|
*/
|
||||||
|
$horizontal-nav-padding: 0.6875rem !default;
|
||||||
|
|
||||||
|
// Gap between top level horizontal nav items
|
||||||
|
$horizontal-nav-top-level-items-gap: 4px !default;
|
||||||
|
|
||||||
|
// Horizontal nav icons
|
||||||
|
$horizontal-nav-items-icon-size: 1.5rem !default;
|
||||||
|
$horizontal-nav-third-level-icon-size: 0.9rem !default;
|
||||||
|
$horizontal-nav-items-icon-margin-inline-end: 0.625rem !default;
|
||||||
|
$horizontal-nav-group-arrow-icon-size: 1.375rem !default;
|
||||||
|
|
||||||
|
// ℹ️ We used SCSS variable because we want to allow users to update max height of popper content
|
||||||
|
// 120px is combined height of navbar & horizontal nav
|
||||||
|
$horizontal-nav-popper-content-max-height: calc(100dvh - 120px - 4rem) !default;
|
||||||
|
|
||||||
|
// ℹ️ This variable is used for horizontal nav popper content's `margin-top` and "The bridge"'s height. We need to sync both values.
|
||||||
|
$horizontal-nav-popper-content-top: calc($horizontal-nav-padding + 0.375rem) !default;
|
||||||
|
|
||||||
|
// 👉 Plugins
|
||||||
|
|
||||||
|
$plugin-ps-thumb-y-dark: rgba(var(--v-theme-surface-variant), 0.35) !default;
|
||||||
|
|
||||||
|
// 👉 Vuetify
|
||||||
|
|
||||||
|
// Used in src/@core/scss/base/libs/vuetify/_overrides.scss
|
||||||
|
$vuetify-reduce-default-compact-button-icon-size: true !default;
|
||||||
|
|
||||||
|
// 👉 Custom variables
|
||||||
|
// for utility classes
|
||||||
|
$font-sizes: () !default;
|
||||||
|
$font-sizes: map-deep-merge(
|
||||||
|
(
|
||||||
|
"xs": 0.75rem,
|
||||||
|
"sm": 0.875rem,
|
||||||
|
"base": 1rem,
|
||||||
|
"lg": 1.125rem,
|
||||||
|
"xl": 1.25rem,
|
||||||
|
"2xl": 1.5rem,
|
||||||
|
"3xl": 1.875rem,
|
||||||
|
"4xl": 2.25rem,
|
||||||
|
"5xl": 3rem,
|
||||||
|
"6xl": 3.75rem,
|
||||||
|
"7xl": 4.5rem,
|
||||||
|
"8xl": 6rem,
|
||||||
|
"9xl": 8rem
|
||||||
|
),
|
||||||
|
$font-sizes
|
||||||
|
);
|
||||||
|
|
||||||
|
// line height
|
||||||
|
$font-line-height: () !default;
|
||||||
|
$font-line-height: map-deep-merge(
|
||||||
|
(
|
||||||
|
"xs": 1rem,
|
||||||
|
"sm": 1.25rem,
|
||||||
|
"base": 1.5rem,
|
||||||
|
"lg": 1.75rem,
|
||||||
|
"xl": 1.75rem,
|
||||||
|
"2xl": 2rem,
|
||||||
|
"3xl": 2.25rem,
|
||||||
|
"4xl": 2.5rem,
|
||||||
|
"5xl": 1,
|
||||||
|
"6xl": 1,
|
||||||
|
"7xl": 1,
|
||||||
|
"8xl": 1,
|
||||||
|
"9xl": 1
|
||||||
|
),
|
||||||
|
$font-line-height
|
||||||
|
);
|
||||||
|
|
||||||
|
// gap utility class
|
||||||
|
$gap: () !default;
|
||||||
|
$gap: map-deep-merge(
|
||||||
|
(
|
||||||
|
"0": 0,
|
||||||
|
"1": 0.25rem,
|
||||||
|
"2": 0.5rem,
|
||||||
|
"3": 0.75rem,
|
||||||
|
"4": 1rem,
|
||||||
|
"5": 1.25rem,
|
||||||
|
"6":1.5rem,
|
||||||
|
"7": 1.75rem,
|
||||||
|
"8": 2rem,
|
||||||
|
"9": 2.25rem,
|
||||||
|
"10": 2.5rem,
|
||||||
|
"11": 2.75rem,
|
||||||
|
"12": 3rem,
|
||||||
|
"14": 3.5rem,
|
||||||
|
"16": 4rem,
|
||||||
|
"20": 5rem,
|
||||||
|
"24": 6rem,
|
||||||
|
"28": 7rem,
|
||||||
|
"32": 8rem,
|
||||||
|
"36": 9rem,
|
||||||
|
"40": 10rem,
|
||||||
|
"44": 11rem,
|
||||||
|
"48": 12rem,
|
||||||
|
"52": 13rem,
|
||||||
|
"56": 14rem,
|
||||||
|
"60": 15rem,
|
||||||
|
"64": 16rem,
|
||||||
|
"72": 18rem,
|
||||||
|
"80": 20rem,
|
||||||
|
"96": 24rem
|
||||||
|
),
|
||||||
|
$gap
|
||||||
|
);
|
||||||
259
src/@core/scss/base/_vertical-nav.scss
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
@use "@core/scss/base/placeholders" as *;
|
||||||
|
@use "@core/scss/template/placeholders" as *;
|
||||||
|
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "@core/scss/base/mixins" as mixins;
|
||||||
|
@use "vuetify/lib/styles/tools/states" as vuetifyStates;
|
||||||
|
|
||||||
|
.layout-nav-type-vertical {
|
||||||
|
// 👉 Layout Vertical nav
|
||||||
|
.layout-vertical-nav {
|
||||||
|
$sl-layout-nav-type-vertical: &;
|
||||||
|
|
||||||
|
@extend %nav;
|
||||||
|
|
||||||
|
@at-root {
|
||||||
|
// ℹ️ Add styles for collapsed vertical nav
|
||||||
|
.layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}.hovered {
|
||||||
|
@include mixins.elevation(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: variables.$vertical-nav-background-color;
|
||||||
|
|
||||||
|
// 👉 Nav header
|
||||||
|
.nav-header {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: variables.$vertical-nav-header-padding;
|
||||||
|
margin-inline: variables.$vertical-nav-header-inline-spacing;
|
||||||
|
min-block-size: variables.$vertical-nav-header-height;
|
||||||
|
|
||||||
|
// TEMPLATE: Check if we need to move this to master
|
||||||
|
.app-logo {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: transform 0.25s ease-in-out;
|
||||||
|
|
||||||
|
@at-root {
|
||||||
|
// Move logo a bit to align center with the icons in vertical nav mini variant
|
||||||
|
.layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}:not(.hovered) .nav-header .app-logo {
|
||||||
|
transform: translateX(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini);
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: translateX(-(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-title {
|
||||||
|
margin-inline-start: variables.$vertical-nav-header-logo-title-spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-action {
|
||||||
|
@extend %nav-header-action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Nav items shadow
|
||||||
|
.vertical-nav-items-shadow {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background:
|
||||||
|
linear-gradient(
|
||||||
|
rgb(#{variables.$vertical-nav-background-color-rgb}) 5%,
|
||||||
|
rgba(#{variables.$vertical-nav-background-color-rgb}, 75%) 45%,
|
||||||
|
rgba(#{variables.$vertical-nav-background-color-rgb}, 20%) 80%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
block-size: 55px;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: calc(#{variables.$vertical-nav-header-height} - 2px);
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.15s ease-in-out;
|
||||||
|
will-change: opacity;
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: translateX(8px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.scrolled {
|
||||||
|
.vertical-nav-items-shadow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ Setting z-index 1 will make perfect scrollbar thumb appear on top of vertical nav items shadow;
|
||||||
|
.ps__rail-y {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Nav section title
|
||||||
|
.nav-section-title {
|
||||||
|
@extend %vertical-nav-item;
|
||||||
|
@extend %vertical-nav-section-title;
|
||||||
|
|
||||||
|
margin-block-end: variables.$vertical-nav-section-title-mb;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-block-start: variables.$vertical-nav-section-title-mt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-icon {
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav item badge
|
||||||
|
.nav-item-badge {
|
||||||
|
@extend %vertical-nav-item-badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Nav group & Link
|
||||||
|
.nav-link,
|
||||||
|
.nav-group {
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
@extend %vertical-nav-item;
|
||||||
|
@extend %vertical-nav-item-interactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-icon {
|
||||||
|
@extend %vertical-nav-items-icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: var(--v-disabled-opacity);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Vertical nav link
|
||||||
|
.nav-link {
|
||||||
|
@extend %nav-link;
|
||||||
|
|
||||||
|
> .router-link-exact-active {
|
||||||
|
@extend %nav-link-active;
|
||||||
|
}
|
||||||
|
|
||||||
|
> a {
|
||||||
|
// Adds before psudo element to style hover state
|
||||||
|
@include mixins.before-pseudo;
|
||||||
|
|
||||||
|
// Adds vuetify states
|
||||||
|
|
||||||
|
&:not(.router-link-active, .router-link-exact-active) {
|
||||||
|
@include vuetifyStates.states($active: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Vertical nav group
|
||||||
|
.nav-group {
|
||||||
|
// Reduce the size of icon if link/group is inside group
|
||||||
|
.nav-group,
|
||||||
|
.nav-link {
|
||||||
|
.nav-item-icon {
|
||||||
|
@extend %vertical-nav-items-nested-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide icons after 2nd level
|
||||||
|
& .nav-group {
|
||||||
|
.nav-link,
|
||||||
|
.nav-group {
|
||||||
|
.nav-item-icon {
|
||||||
|
@extend %vertical-nav-items-icon-after-2nd-level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-arrow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transform-origin: center;
|
||||||
|
transition: transform variables.$vertical-nav-nav-group-arrow-transition-duration variables.$vertical-nav-nav-group-arrow-transition-timing-function;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate arrow icon if group is opened
|
||||||
|
&.open {
|
||||||
|
> .nav-group-label .nav-group-arrow {
|
||||||
|
transform: rotateZ(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav group label
|
||||||
|
> :first-child {
|
||||||
|
// Adds before psudo element to style hover state
|
||||||
|
@include mixins.before-pseudo;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.active,.open) > :first-child {
|
||||||
|
// Adds vuetify states
|
||||||
|
@include vuetifyStates.states($active: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active & open states for nav group label
|
||||||
|
&.active,
|
||||||
|
&.open {
|
||||||
|
> :first-child {
|
||||||
|
@extend %vertical-nav-group-open-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECTION: Transitions
|
||||||
|
.vertical-nav-section-title-enter-active,
|
||||||
|
.vertical-nav-section-title-leave-active {
|
||||||
|
transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-section-title-enter-from,
|
||||||
|
.vertical-nav-section-title-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(15px);
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: translateX(-15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-slide-x-enter-active,
|
||||||
|
.transition-slide-x-leave-active {
|
||||||
|
transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-slide-x-enter-from,
|
||||||
|
.transition-slide-x-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-15px);
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: translateX(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-app-title-enter-active,
|
||||||
|
.vertical-nav-app-title-leave-active {
|
||||||
|
transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-app-title-enter-from,
|
||||||
|
.vertical-nav-app-title-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-15px);
|
||||||
|
|
||||||
|
@include layoutsMixins.rtl {
|
||||||
|
transform: translateX(15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// !SECTION
|
||||||
35
src/@core/scss/base/libs/_perfect-scrollbar.scss
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
$ps-size: 0.25rem;
|
||||||
|
$ps-hover-size: 0.375rem;
|
||||||
|
$ps-track-size: 0.5rem;
|
||||||
|
|
||||||
|
.ps__thumb-y {
|
||||||
|
inline-size: $ps-size !important;
|
||||||
|
inset-inline-end: 0.0625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__thumb-y,
|
||||||
|
.ps__thumb-x {
|
||||||
|
background-color: rgb(var(--v-theme-perfect-scrollbar-thumb)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__thumb-x {
|
||||||
|
block-size: $ps-size !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__rail-x {
|
||||||
|
background: transparent !important;
|
||||||
|
block-size: $ps-track-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__rail-y {
|
||||||
|
background: transparent !important;
|
||||||
|
inline-size: $ps-track-size !important;
|
||||||
|
inset-inline-end: 0.125rem !important;
|
||||||
|
inset-inline-start: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps__rail-y.ps--clicking .ps__thumb-y,
|
||||||
|
.ps__rail-y:focus > .ps__thumb-y,
|
||||||
|
.ps__rail-y:hover > .ps__thumb-y {
|
||||||
|
inline-size: $ps-hover-size !important;
|
||||||
|
}
|
||||||
1
src/@core/scss/base/libs/vuetify/_index.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use "overrides";
|
||||||
257
src/@core/scss/base/libs/vuetify/_overrides.scss
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
@use "@core/scss/base/utils";
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
|
||||||
|
// 👉 Application
|
||||||
|
// ℹ️ We need accurate vh in mobile devices as well
|
||||||
|
.v-application__wrap {
|
||||||
|
/* stylelint-disable-next-line liberty/use-logical-spec */
|
||||||
|
min-height: 100dvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Typography
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
.text-h1,
|
||||||
|
.text-h2,
|
||||||
|
.text-h3,
|
||||||
|
.text-h4,
|
||||||
|
.text-h5,
|
||||||
|
.text-h6,
|
||||||
|
.text-button,
|
||||||
|
.text-overline,
|
||||||
|
.v-card-title {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
.text-body-1,
|
||||||
|
.text-body-2,
|
||||||
|
.text-subtitle-1,
|
||||||
|
.text-subtitle-2 {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Grid
|
||||||
|
// Remove margin-bottom of v-input_details inside grid (validation error message)
|
||||||
|
.v-row {
|
||||||
|
.v-col,
|
||||||
|
[class^="v-col-*"] {
|
||||||
|
.v-input__details {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Button
|
||||||
|
@if variables.$vuetify-reduce-default-compact-button-icon-size {
|
||||||
|
.v-btn--density-compact.v-btn--size-default {
|
||||||
|
.v-btn__content > svg {
|
||||||
|
block-size: 22px;
|
||||||
|
font-size: 22px;
|
||||||
|
inline-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Card
|
||||||
|
// Removes padding-top for immediately placed v-card-text after itself
|
||||||
|
.v-card-text {
|
||||||
|
& + & {
|
||||||
|
padding-block-start: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
👉 Checkbox & Radio Ripple
|
||||||
|
|
||||||
|
TODO Checkbox and switch component. Remove it when vuetify resolve the extra spacing: https://github.com/vuetifyjs/vuetify/issues/15519
|
||||||
|
We need this because form elements likes checkbox and switches are by default set to height of textfield height which is way big than we want
|
||||||
|
Tested with checkbox & switches
|
||||||
|
*/
|
||||||
|
.v-checkbox.v-input,
|
||||||
|
.v-switch.v-input {
|
||||||
|
--v-input-control-height: auto;
|
||||||
|
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-radio-group {
|
||||||
|
.v-selection-control-group {
|
||||||
|
.v-radio:not(:last-child) {
|
||||||
|
margin-inline-end: 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
👉 Tabs
|
||||||
|
Disable tab transition
|
||||||
|
|
||||||
|
This is for tabs where we don't have card wrapper to tabs and have multiple cards as tab content.
|
||||||
|
|
||||||
|
This class will disable transition and adds `overflow: unset` on `VWindow` to allow spreading shadow
|
||||||
|
*/
|
||||||
|
.disable-tab-transition {
|
||||||
|
overflow: unset !important;
|
||||||
|
|
||||||
|
.v-window__container {
|
||||||
|
block-size: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-window-item:not(.v-window-item--active) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-window__container .v-window-item {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 List
|
||||||
|
.v-list {
|
||||||
|
// Set icons opacity to .87
|
||||||
|
.v-list-item__prepend > .v-icon,
|
||||||
|
.v-list-item__append > .v-icon {
|
||||||
|
opacity: var(--v-high-emphasis-opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Card list
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ Custom class
|
||||||
|
|
||||||
|
Remove list spacing inside card
|
||||||
|
|
||||||
|
This is because card title gets padding of 20px and list item have padding of 16px. Moreover, list container have padding-bottom as well.
|
||||||
|
*/
|
||||||
|
.card-list {
|
||||||
|
--v-card-list-gap: 20px;
|
||||||
|
|
||||||
|
&.v-list {
|
||||||
|
padding-block: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-item {
|
||||||
|
min-block-size: unset;
|
||||||
|
min-block-size: auto !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
padding-inline: 0 !important;
|
||||||
|
|
||||||
|
> .v-ripple__container {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
padding-block-end: var(--v-card-list-gap) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-item:hover,
|
||||||
|
.v-list-item:focus,
|
||||||
|
.v-list-item:active,
|
||||||
|
.v-list-item.active {
|
||||||
|
> .v-list-item__overlay {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Divider
|
||||||
|
.v-divider {
|
||||||
|
color: rgb(var(--v-border-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-divider.v-divider--vertical {
|
||||||
|
block-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 DataTable
|
||||||
|
.v-data-table {
|
||||||
|
/* stylelint-disable-next-line no-descending-specificity */
|
||||||
|
.v-checkbox-btn .v-selection-control__wrapper {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-selection-control {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-pagination {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 v-field
|
||||||
|
.v-field:hover .v-field__outline {
|
||||||
|
--v-field-border-opacity: var(--v-medium-emphasis-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 VLabel
|
||||||
|
.v-label {
|
||||||
|
opacity: 1 !important;
|
||||||
|
|
||||||
|
&:not(.v-field-label--floating) {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Overlay
|
||||||
|
.v-overlay__scrim,
|
||||||
|
.v-navigation-drawer__scrim {
|
||||||
|
background: rgba(var(--v-overlay-scrim-background), var(--v-overlay-scrim-opacity)) !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 VMessages
|
||||||
|
.v-messages {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Alert close btn
|
||||||
|
.v-alert__close {
|
||||||
|
.v-btn--icon .v-icon {
|
||||||
|
--v-icon-size-multiplier: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Badge icon alignment
|
||||||
|
.v-badge__badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 Btn focus outline style removed
|
||||||
|
.v-btn:focus-visible::after {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .v-select chip spacing for slot
|
||||||
|
.v-input:not(.v-select--chips) .v-select__selection {
|
||||||
|
.v-chip {
|
||||||
|
margin-block: 2px var(--select-chips-margin-bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 VCard and VList subtitle color
|
||||||
|
.v-card-subtitle,
|
||||||
|
.v-list-item-subtitle {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 👉 placeholders
|
||||||
|
.v-field__input {
|
||||||
|
@at-root {
|
||||||
|
& input::placeholder,
|
||||||
|
input#{&}::placeholder,
|
||||||
|
textarea#{&}::placeholder {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)) !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/@core/scss/base/libs/vuetify/_variables.scss
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
@use "sass:map";
|
||||||
|
|
||||||
|
/* 👉 Shadow opacities */
|
||||||
|
$shadow-key-umbra-opacity-custom: var(--v-shadow-key-umbra-opacity);
|
||||||
|
$shadow-key-penumbra-opacity-custom: var(--v-shadow-key-penumbra-opacity);
|
||||||
|
$shadow-key-ambient-opacity-custom: var(--v-shadow-key-ambient-opacity);
|
||||||
|
|
||||||
|
/* 👉 Card transition properties */
|
||||||
|
$card-transition-property-custom: box-shadow, opacity;
|
||||||
|
|
||||||
|
@forward "vuetify/settings" with (
|
||||||
|
// 👉 General settings
|
||||||
|
$color-pack: false !default,
|
||||||
|
|
||||||
|
// 👉 Shadow opacity
|
||||||
|
$shadow-key-umbra-opacity: $shadow-key-umbra-opacity-custom !default,
|
||||||
|
$shadow-key-penumbra-opacity: $shadow-key-penumbra-opacity-custom !default,
|
||||||
|
$shadow-key-ambient-opacity: $shadow-key-ambient-opacity-custom !default,
|
||||||
|
|
||||||
|
// 👉 Card
|
||||||
|
$card-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default,
|
||||||
|
$card-elevation: 6 !default,
|
||||||
|
$card-title-line-height: 1.6 !default,
|
||||||
|
$card-actions-min-height: unset !default,
|
||||||
|
$card-text-padding: 1.25rem !default,
|
||||||
|
$card-item-padding: 1.25rem !default,
|
||||||
|
$card-actions-padding: 0 12px 12px !default,
|
||||||
|
$card-transition-property: $card-transition-property-custom !default,
|
||||||
|
$card-subtitle-opacity: 1 !default,
|
||||||
|
|
||||||
|
// 👉 Expansion Panel
|
||||||
|
$expansion-panel-active-title-min-height: 48px !default,
|
||||||
|
|
||||||
|
// 👉 List
|
||||||
|
$list-item-icon-margin-end: 16px !default,
|
||||||
|
$list-item-icon-margin-start: 16px !default,
|
||||||
|
$list-item-subtitle-opacity: 1 !default,
|
||||||
|
|
||||||
|
// 👉 Navigation Drawer
|
||||||
|
$navigation-drawer-content-overflow-y: hidden !default,
|
||||||
|
|
||||||
|
// 👉 Tooltip
|
||||||
|
$tooltip-background-color: rgba(59, 55, 68, 0.9) !default,
|
||||||
|
$tooltip-text-color: rgb(var(--v-theme-on-primary)) !default,
|
||||||
|
$tooltip-font-size: 0.75rem !default,
|
||||||
|
|
||||||
|
$button-icon-density: ("default": 2, "comfortable": 0, "compact": -1 ) !default,
|
||||||
|
|
||||||
|
// 👉 VTimeline
|
||||||
|
$timeline-dot-size: 34px !default,
|
||||||
|
|
||||||
|
// 👉 table
|
||||||
|
$table-transition-property: height !default,
|
||||||
|
|
||||||
|
// 👉 VOverlay
|
||||||
|
$overlay-opacity: 1 !default,
|
||||||
|
|
||||||
|
// 👉 VContainer
|
||||||
|
$container-max-widths: (
|
||||||
|
"xl": 1440px,
|
||||||
|
"xxl": 1440px
|
||||||
|
) !default,
|
||||||
|
|
||||||
|
);
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "misc";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
%default-layout-horizontal-nav-navbar-and-nav-container {
|
||||||
|
@include mixins.elevation(3);
|
||||||
|
|
||||||
|
// ℹ️ 1000 is v-window z-index
|
||||||
|
z-index: 1001;
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
|
||||||
|
&.header-blur {
|
||||||
|
@extend %blurry-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%default-layout-horizontal-nav-navbar {
|
||||||
|
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
%default-layout-horizontal-nav-nav {
|
||||||
|
padding-block: variables.$horizontal-nav-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
%default-layout-horizontal-nav-nav-items-list {
|
||||||
|
gap: variables.$horizontal-nav-top-level-items-gap;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "misc";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
%default-layout-vertical-nav-scrolled-sticky-elevated-nav {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
}
|
||||||
|
|
||||||
|
%default-layout-vertical-nav-floating-navbar-and-sticky-elevated-navbar-scrolled {
|
||||||
|
@include mixins.elevation(variables.$vertical-nav-navbar-elevation);
|
||||||
|
|
||||||
|
// If navbar is contained => Squeeze navbar content on scroll
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
padding-inline: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%default-layout-vertical-nav-floating-navbar-overlay {
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
/* stylelint-disable property-no-vendor-prefix */
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
/* stylelint-enable */
|
||||||
|
background:
|
||||||
|
linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(var(--v-theme-background), 70%) 44%,
|
||||||
|
rgba(var(--v-theme-background), 43%) 73%,
|
||||||
|
rgba(var(--v-theme-background), 0%)
|
||||||
|
);
|
||||||
|
background-repeat: repeat;
|
||||||
|
block-size: calc(variables.$layout-vertical-nav-navbar-height + variables.$vertical-nav-floating-navbar-top + 0.5rem);
|
||||||
|
content: "";
|
||||||
|
inset-block-start: -(variables.$vertical-nav-floating-navbar-top);
|
||||||
|
inset-inline: 0 0;
|
||||||
|
/* stylelint-disable property-no-vendor-prefix */
|
||||||
|
-webkit-mask: linear-gradient(black, black 18%, transparent 100%);
|
||||||
|
mask: linear-gradient(black, black 18%, transparent 100%);
|
||||||
|
/* stylelint-enable */
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/@core/scss/base/placeholders/_default-layout.scss
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
%layout-navbar {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
98
src/@core/scss/base/placeholders/_horizontal-nav.scss
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
@use "@layouts/styles/mixins" as layoutsMixins;
|
||||||
|
@use "@core/scss/base/variables";
|
||||||
|
@use "@layouts/styles/placeholders";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
// Horizontal nav item styles (including nested)
|
||||||
|
%horizontal-nav-item {
|
||||||
|
padding-block: 0.6rem;
|
||||||
|
padding-inline: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top level horizontal nav item styles (`a` tag & group label)
|
||||||
|
%horizontal-nav-top-level-item {
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
%horizontal-nav-disabled {
|
||||||
|
opacity: var(--v-disabled-opacity);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active styles for sub nav link
|
||||||
|
%horizontal-nav-sub-nav-link-active {
|
||||||
|
background: rgba(var(--v-theme-primary), 0.1);
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ This style is required when you don't provide any transition to horizontal nav items via themeConfig `themeConfig.horizontalNav.transition`
|
||||||
|
Also, you have to disable it if you are using transition
|
||||||
|
*/
|
||||||
|
// Popper content styles when it's hidden
|
||||||
|
%horizontal-nav-popper-content-hidden {
|
||||||
|
// display: none;
|
||||||
|
|
||||||
|
// opacity: 0;
|
||||||
|
// pointer-events: none;
|
||||||
|
// transform: translateY(7px);
|
||||||
|
// transition: transform 0.25s ease-in-out, opacity 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ This style is required when you don't provide any transition to horizontal nav items via themeConfig `themeConfig.horizontalNav.transition`
|
||||||
|
Also, you have to disable it if you are using transition
|
||||||
|
*/
|
||||||
|
// Popper content styles when it's shown
|
||||||
|
%horizontal-nav-popper-content-visible {
|
||||||
|
// display: block;
|
||||||
|
|
||||||
|
// opacity: 1;
|
||||||
|
// pointer-events: auto;
|
||||||
|
// pointer-events: auto;
|
||||||
|
// transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal nav item icon (Including sub nav items)
|
||||||
|
%horizontal-nav-item-icon {
|
||||||
|
font-size: variables.$horizontal-nav-items-icon-size;
|
||||||
|
margin-inline-end: variables.$horizontal-nav-items-icon-margin-inline-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal nav subitem
|
||||||
|
%horizontal-nav-subitem {
|
||||||
|
min-inline-size: 12rem;
|
||||||
|
|
||||||
|
.nav-item-title {
|
||||||
|
margin-inline-end: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Styles for third level item icon/ (e.g. Reduce the icon's size of nested group's nav links (Top level group > Sub group > [Nav links]))
|
||||||
|
%third-level-nav-item-icon {
|
||||||
|
font-size: variables.$horizontal-nav-third-level-icon-size;
|
||||||
|
margin-inline: calc((variables.$horizontal-nav-items-icon-size - variables.$horizontal-nav-third-level-icon-size) / 2) 0.75rem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ `margin-inline` will be (normal icon font-size - small icon font-size) / 2
|
||||||
|
(1.5rem - 0.9rem) / 2 => 0.6rem / 2 => 0.3rem
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal nav item title
|
||||||
|
%horizontal-nav-item-title {
|
||||||
|
margin-inline-end: 0.3rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Popper content styles
|
||||||
|
%horizontal-nav-popper-content {
|
||||||
|
@include mixins.elevation(4);
|
||||||
|
|
||||||
|
border-radius: 6px;
|
||||||
|
padding-block: 0.3rem;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
@extend %style-scroll-bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/@core/scss/base/placeholders/_index.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@forward "horizontal-nav";
|
||||||
|
@forward "vertical-nav";
|
||||||
|
@forward "nav";
|
||||||
|
@forward "default-layout";
|
||||||
|
@forward "default-layout-vertical-nav";
|
||||||
|
@forward "default-layout-horizontal-nav";
|
||||||
|
@forward "misc";
|
||||||
7
src/@core/scss/base/placeholders/_misc.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
%blurry-bg {
|
||||||
|
/* stylelint-disable property-no-vendor-prefix */
|
||||||
|
-webkit-backdrop-filter: blur(6px);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
/* stylelint-enable */
|
||||||
|
background-color: rgb(var(--v-theme-surface), 0.9);
|
||||||
|
}
|
||||||
33
src/@core/scss/base/placeholders/_nav.scss
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
|
||||||
|
// ℹ️ This is common style that needs to be applied to both navs
|
||||||
|
%nav {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
|
||||||
|
.nav-item-title {
|
||||||
|
letter-spacing: 0.15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section-title {
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Active nav link styles for horizontal & vertical nav
|
||||||
|
|
||||||
|
For horizontal nav it will be only applied to top level nav items
|
||||||
|
For vertical nav it will be only applied to nav links (not nav groups)
|
||||||
|
*/
|
||||||
|
%nav-link-active {
|
||||||
|
background-color: rgb(var(--v-global-theme-primary));
|
||||||
|
color: rgb(var(--v-theme-on-primary));
|
||||||
|
|
||||||
|
@include mixins.elevation(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
%nav-link {
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
80
src/@core/scss/base/placeholders/_vertical-nav.scss
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "vuetify/lib/styles/tools/states" as vuetifyStates;
|
||||||
|
|
||||||
|
%nav-header-action {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav items styles (including section title)
|
||||||
|
%vertical-nav-item {
|
||||||
|
margin-block: 0;
|
||||||
|
margin-inline: variables.$vertical-nav-horizontal-spacing;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: variables.$vertical-nav-horizontal-padding;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is same as `%vertical-nav-item` except section title is excluded
|
||||||
|
%vertical-nav-item-interactive {
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
block-size: 2.75rem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ℹ️ We will use `margin-block-end` instead of `margin-block` to give more space for shadow to appear.
|
||||||
|
With `margin-block`, due to small space (space gets divided between top & bottom) shadow cuts
|
||||||
|
*/
|
||||||
|
margin-block-end: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common styles for nav item icon styles
|
||||||
|
// ℹ️ Nav group's children icon styles are not here (Adjusts height, width & margin)
|
||||||
|
%vertical-nav-items-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: variables.$vertical-nav-items-icon-size;
|
||||||
|
margin-inline-end: variables.$vertical-nav-items-icon-margin-inline-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ℹ️ Icon styling for icon nested inside another nav item (2nd level)
|
||||||
|
%vertical-nav-items-nested-icon {
|
||||||
|
/*
|
||||||
|
ℹ️ `margin-inline` will be (normal icon font-size - small icon font-size) / 2
|
||||||
|
(1.5rem - 0.9rem) / 2 => 0.6rem / 2 => 0.3rem
|
||||||
|
*/
|
||||||
|
$vertical-nav-items-nested-icon-margin-inline: calc((variables.$vertical-nav-items-icon-size - variables.$vertical-nav-items-nested-icon-size) / 2);
|
||||||
|
|
||||||
|
font-size: variables.$vertical-nav-items-nested-icon-size;
|
||||||
|
margin-inline: $vertical-nav-items-nested-icon-margin-inline $vertical-nav-items-nested-icon-margin-inline + variables.$vertical-nav-items-icon-margin-inline-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
%vertical-nav-items-icon-after-2nd-level {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open & Active nav group styles
|
||||||
|
%vertical-nav-group-open-active {
|
||||||
|
@include mixins.selected-states("&::before");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section title
|
||||||
|
// ℹ️ Setting height will prevent jerking when text & icon is toggled
|
||||||
|
%vertical-nav-section-title {
|
||||||
|
block-size: 1.5rem;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertical nav item badge styles
|
||||||
|
%vertical-nav-item-badge {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
padding-block: 0.25em;
|
||||||
|
padding-inline: 0.55em;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: baseline;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
72
src/@core/scss/base/skins/_bordered.scss
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
@use "sass:map";
|
||||||
|
@use "@core/scss/base/mixins";
|
||||||
|
@use "@configured-variables" as variables;
|
||||||
|
@use "../utils";
|
||||||
|
|
||||||
|
$header: ".layout-navbar";
|
||||||
|
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
$header: ".layout-navbar .navbar-content-container";
|
||||||
|
}
|
||||||
|
|
||||||
|
.skin--bordered {
|
||||||
|
@include mixins.bordered-skin(".v-card:not(.v-card--flat)");
|
||||||
|
@include mixins.bordered-skin(".v-menu .v-overlay__content > .v-card, .v-menu .v-overlay__content > .v-sheet, .v-menu .v-overlay__content > .v-list");
|
||||||
|
@include mixins.bordered-skin(".popper-content");
|
||||||
|
|
||||||
|
// Navbar
|
||||||
|
// -- Horizontal
|
||||||
|
@include mixins.bordered-skin(".layout-navbar-and-nav-container", "border-bottom");
|
||||||
|
|
||||||
|
// -- Vertical
|
||||||
|
// ℹ️ We have added `.layout-navbar-sticky` as well in selector because we don't want to add borders if navbar is static
|
||||||
|
@if variables.$layout-vertical-nav-navbar-is-contained {
|
||||||
|
@include mixins.bordered-skin(".layout-nav-type-vertical.window-scrolled.layout-navbar-sticky #{$header}");
|
||||||
|
.layout-nav-type-vertical.window-scrolled #{$header} {
|
||||||
|
border-block-start: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// stylelint-disable-next-line @stylistic/indentation
|
||||||
|
@else {
|
||||||
|
@include mixins.bordered-skin(".layout-nav-type-vertical.window-scrolled.layout-navbar-sticky #{$header}", "border-bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
// -- Vertical
|
||||||
|
@include mixins.bordered-skin(".layout-nav-type-vertical.layout-footer-sticky .layout-footer .footer-content-container");
|
||||||
|
|
||||||
|
.layout-nav-type-vertical.layout-footer-sticky .layout-footer .footer-content-container {
|
||||||
|
border-block-end: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Horizontal
|
||||||
|
@include mixins.bordered-skin(".layout-nav-type-horizontal.layout-footer-sticky .layout-footer");
|
||||||
|
|
||||||
|
.layout-nav-type-horizontal.layout-footer-sticky .layout-footer {
|
||||||
|
border-block-end: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertical Nav
|
||||||
|
.layout-vertical-nav {
|
||||||
|
border-inline-end: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expansion Panels
|
||||||
|
.v-expansion-panels:not(.customized-panels) {
|
||||||
|
.v-expansion-panel__shadow {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-expansion-panel {
|
||||||
|
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-block-end: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||