initial commit

This commit is contained in:
2026-06-23 13:28:38 +07:00
commit 966ed115b2
590 changed files with 111412 additions and 0 deletions
@@ -0,0 +1,24 @@
import { useTheme } from 'vuetify'
import { useThemeConfig } from '@core/composable/useThemeConfig'
const { skin } = useThemeConfig()
// composable function to return the image variant as per the current theme and skin
export const useGenerateImageVariant = (imgLight, imgDark, imgLightBordered, imgDarkBordered, bordered = false) => {
const { global } = useTheme()
return computed(() => {
if (global.name.value === 'light') {
if (skin.value === 'bordered' && bordered)
return imgLightBordered
else
return imgLight
}
if (global.name.value === 'dark') {
if (skin.value === 'bordered' && bordered)
return imgDarkBordered
else
return imgDark
}
})
}
@@ -0,0 +1,23 @@
import { useDisplay } from 'vuetify'
export const useResponsiveLeftSidebar = (mobileBreakpoint = 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,
}
}
+36
View File
@@ -0,0 +1,36 @@
import { VThemeProvider } from 'vuetify/components/VThemeProvider'
import { AppContentLayoutNav } from '@layouts/enums'
// TODO: Use `VThemeProvider` from dist instead of lib (Using this component from dist causes navbar to loose sticky positioning)
import { useThemeConfig } from '@core/composable/useThemeConfig'
export const useSkins = () => {
const { isVerticalNavSemiDark, skin, appContentLayoutNav } = useThemeConfig()
const layoutAttrs = computed(() => ({
verticalNavAttrs: {
wrapper: h(VThemeProvider, { tag: 'aside' }),
wrapperProps: {
withBackground: true,
theme: (isVerticalNavSemiDark.value && appContentLayoutNav.value === AppContentLayoutNav.Vertical)
? 'dark'
: undefined,
},
},
}))
const injectSkinClasses = () => {
const bodyClasses = document.body.classList
const genSkinClass = _skin => `skin--${_skin}`
watch(skin, (val, oldVal) => {
bodyClasses.remove(genSkinClass(oldVal))
bodyClasses.add(genSkinClass(val))
}, { immediate: true })
}
return {
injectSkinClasses,
layoutAttrs,
}
}
@@ -0,0 +1,157 @@
import { useTheme } from 'vuetify'
import { useLayouts } from '@layouts'
import { themeConfig } from '@themeConfig'
export const isDarkPreferred = usePreferredDark()
export const useThemeConfig = () => {
const theme = computed({
get() {
return themeConfig.app.theme.value
},
set(value) {
themeConfig.app.theme.value = value
localStorage.setItem(`${themeConfig.app.title}-theme`, value.toString())
// ️ We will not reset semi dark value when turning off dark mode because some user think it as bug
// if (value !== 'light')
// isVerticalNavSemiDark.value = false
},
})
const isVerticalNavSemiDark = computed({
get() {
return themeConfig.verticalNav.isVerticalNavSemiDark.value
},
set(value) {
themeConfig.verticalNav.isVerticalNavSemiDark.value = value
localStorage.setItem(`${themeConfig.app.title}-isVerticalNavSemiDark`, value.toString())
},
})
const syncVuetifyThemeWithTheme = () => {
const vuetifyTheme = useTheme()
watch([theme, isDarkPreferred], ([val, _]) => {
vuetifyTheme.global.name.value = val === 'system'
? isDarkPreferred.value
? 'dark'
: 'light'
: val
})
}
/*
️ 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(theme, () => {
// ️ We are not using theme.current.colors.surface because watcher is independent and when this watcher is ran `theme` computed is not updated
localStorage.setItem(`${themeConfig.app.title}-initial-loader-bg`, vuetifyTheme.current.value.colors.surface)
localStorage.setItem(`${themeConfig.app.title}-initial-loader-color`, vuetifyTheme.current.value.colors.primary)
}, {
immediate: true,
})
}
const skin = computed({
get() {
return themeConfig.app.skin.value
},
set(value) {
themeConfig.app.skin.value = value
localStorage.setItem(`${themeConfig.app.title}-skin`, value)
},
})
const handleSkinChanges = () => {
const { themes } = useTheme()
// 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(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 })
}
const appRouteTransition = computed({
get() {
return themeConfig.app.routeTransition.value
},
set(value) {
themeConfig.app.routeTransition.value = value
localStorage.setItem(`${themeConfig.app.title}-transition`, value)
},
})
// `@layouts` exports
const { navbarType, isNavbarBlurEnabled, footerType, isVerticalNavCollapsed, appContentWidth, appContentLayoutNav, horizontalNavType, isLessThanOverlayNavBreakpoint, isAppRtl, switchToVerticalNavOnLtOverlayNavBreakpoint } = useLayouts()
// const syncRtlWithRtlLang = (rtlLangs: string[], rtlDefaultLocale: string, ltrDefaultLocale: string) => {
// const { locale } = useI18n({ useScope: 'global' })
// watch(isAppRtl, val => {
// if (val)
// locale.value = rtlDefaultLocale
// else locale.value = ltrDefaultLocale
// })
// watch(locale, val => {
// if (rtlLangs.includes(val))
// isAppRtl.value = true
// else isAppRtl.value = false
// })
// watch(
// [isAppRtl, locale],
// ([valIsAppRTL, valLocale], [oldValIsAppRtl, oldValLocale]) => {
// const isRtlUpdated = valIsAppRTL !== oldValIsAppRtl
// if (isRtlUpdated) {
// if (valIsAppRTL)
// locale.value = rtlDefaultLocale
// else locale.value = ltrDefaultLocale
// }
// else {
// if (rtlLangs.includes(valLocale))
// isAppRtl.value = true
// else isAppRtl.value = false
// }
// },
// )
// }
return {
theme,
isVerticalNavSemiDark,
syncVuetifyThemeWithTheme,
syncInitialLoaderTheme,
skin,
handleSkinChanges,
appRouteTransition,
// @layouts exports
navbarType,
isNavbarBlurEnabled,
footerType,
isVerticalNavCollapsed,
appContentWidth,
appContentLayoutNav,
horizontalNavType,
isLessThanOverlayNavBreakpoint,
isAppRtl,
switchToVerticalNavOnLtOverlayNavBreakpoint,
// syncRtlWithRtlLang,
}
}