feat(Layout): Add classic layout
This commit is contained in:
parent
958edefe7b
commit
839b6015b8
|
@ -14,5 +14,6 @@
|
|||
"i18n-ally.enabledParsers": ["ts"],
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.displayLanguage": "zh-CN",
|
||||
"i18n-ally.enabledFrameworks": ["vue", "react"]
|
||||
"i18n-ally.enabledFrameworks": ["vue", "react"],
|
||||
"god.tsconfig": "./tsconfig.json"
|
||||
}
|
||||
|
|
19
src/App.vue
19
src/App.vue
|
@ -6,7 +6,9 @@ import { isDark } from '@/utils/is'
|
|||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const size = computed(() => appStore.size)
|
||||
const currentSize = computed(() => appStore.getCurrentSize)
|
||||
|
||||
const greyMode = computed(() => appStore.getGreyMode)
|
||||
|
||||
const initDark = () => {
|
||||
const isDarkTheme = isDark()
|
||||
|
@ -17,12 +19,14 @@ initDark()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<ConfigGlobal :size="size">
|
||||
<RouterView />
|
||||
<ConfigGlobal :size="currentSize">
|
||||
<RouterView :class="{ 'v-grey__mode': greyMode }" />
|
||||
</ConfigGlobal>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-grey';
|
||||
|
||||
.size {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -39,4 +43,13 @@ body {
|
|||
.size;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls}__mode {
|
||||
-webkit-filter: grayscale(100%);
|
||||
-moz-filter: grayscale(100%);
|
||||
-ms-filter: grayscale(100%);
|
||||
-o-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,13 +2,18 @@
|
|||
import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
|
||||
import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// import { compile } from 'path-to-regexp'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { filterBreadcrumb } from './helper'
|
||||
import { filter, treeToList } from '@/utils/tree'
|
||||
import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
// 面包屑图标
|
||||
const breadcrumbIcon = computed(() => appStore.getBreadcrumbIcon)
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Breadcrumb',
|
||||
|
@ -41,7 +46,7 @@ export default defineComponent({
|
|||
const meta = v.meta as RouteMeta
|
||||
return (
|
||||
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
|
||||
{meta?.icon ? (
|
||||
{meta?.icon && breadcrumbIcon.value ? (
|
||||
<>
|
||||
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title)}
|
||||
</>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import ColorRadioPicker from './src/ColorRadioPicker.vue'
|
||||
|
||||
export { ColorRadioPicker }
|
|
@ -0,0 +1,60 @@
|
|||
<script setup lang="ts">
|
||||
import { PropType, watch, unref, ref } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
const props = defineProps({
|
||||
schema: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
},
|
||||
modelValue: propTypes.string.def('')
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const colorVal = ref(props.modelValue)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string) => {
|
||||
if (val === unref(colorVal)) return
|
||||
colorVal.value = val
|
||||
}
|
||||
)
|
||||
|
||||
// 监听
|
||||
watch(
|
||||
() => colorVal.value,
|
||||
(val: string) => {
|
||||
emit('update:modelValue', val)
|
||||
emit('change', val)
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="v-color-radio-picker flex flex-wrap space-x-14px">
|
||||
<span
|
||||
v-for="(item, i) in schema"
|
||||
:key="`radio-${i}`"
|
||||
class="v-color-radio-picker w-20px h-20px cursor-pointer rounded-2px border-solid border-gray-300 border-2px text-center leading-20px mb-5px"
|
||||
:class="{ 'is-active': colorVal === item }"
|
||||
:style="{
|
||||
background: item
|
||||
}"
|
||||
@click="colorVal = item"
|
||||
>
|
||||
<Icon v-if="colorVal === item" color="#fff" icon="ep:check" :size="16" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-color-radio-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.is-active {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { provide, computed, watch } from 'vue'
|
||||
import { provide, computed, watch, onMounted } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { ElConfigProvider } from 'element-plus'
|
||||
import { useLocaleStore } from '@/store/modules/locale'
|
||||
|
@ -9,8 +9,20 @@ import { setCssVar } from '@/utils'
|
|||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const props = defineProps({
|
||||
size: propTypes.oneOf<ElememtPlusSzie[]>(['default', 'small', 'large']).def('default')
|
||||
})
|
||||
|
||||
provide('configGlobal', props)
|
||||
|
||||
// 初始化所有主题色
|
||||
onMounted(() => {
|
||||
appStore.setCssVarTheme()
|
||||
})
|
||||
|
||||
const { width } = useWindowSize()
|
||||
|
||||
// 监听窗口变化
|
||||
watch(
|
||||
() => width.value,
|
||||
(width: number) => {
|
||||
|
@ -29,19 +41,14 @@ watch(
|
|||
}
|
||||
)
|
||||
|
||||
// 多语言相关
|
||||
const localeStore = useLocaleStore()
|
||||
|
||||
const locale = computed(() => localeStore.locale)
|
||||
|
||||
const props = defineProps({
|
||||
size: propTypes.oneOf<ElememtPlusSzie[]>(['default', 'small', 'large']).def('default')
|
||||
})
|
||||
|
||||
provide('configGlobal', props)
|
||||
const currentLocale = computed(() => localeStore.currentLocale)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElConfigProvider :locale="locale.elLocale" :message="{ max: 1 }" :size="size">
|
||||
<ElConfigProvider :locale="currentLocale.elLocale" :message="{ max: 1 }" :size="size">
|
||||
<slot></slot>
|
||||
</ElConfigProvider>
|
||||
</template>
|
||||
|
|
|
@ -8,13 +8,13 @@ const localeStore = useLocaleStore()
|
|||
|
||||
const langMap = computed(() => localeStore.getLocaleMap)
|
||||
|
||||
const currentLang = computed(() => localeStore.getLocale)
|
||||
const currentLang = computed(() => localeStore.getCurrentLocale)
|
||||
|
||||
const setLang = (lang: LocaleType) => {
|
||||
if (lang === unref(currentLang).lang) return
|
||||
// 需要重新加载页面让整个语言多初始化
|
||||
window.location.reload()
|
||||
localeStore.setLocale({
|
||||
localeStore.setCurrentLocale({
|
||||
lang
|
||||
})
|
||||
const { changeLocale } = useLocale()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { ref, watch, computed, onMounted, unref } from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
@ -12,6 +12,10 @@ const layout = computed(() => appStore.getLayout)
|
|||
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
||||
onMounted(() => {
|
||||
if (unref(collapse)) show.value = false
|
||||
})
|
||||
|
||||
watch(
|
||||
() => collapse.value,
|
||||
(collapse: boolean) => {
|
||||
|
@ -37,7 +41,7 @@ watch(
|
|||
{
|
||||
'v-logo__Top': layout !== 'classic'
|
||||
},
|
||||
'flex h-[var(--logo-height)] items-center cursor-pointer pl-8px'
|
||||
'flex h-[var(--logo-height)] items-center cursor-pointer pl-8px relative'
|
||||
]"
|
||||
to="/"
|
||||
>
|
||||
|
@ -50,3 +54,18 @@ watch(
|
|||
}}</div>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-logo';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&:after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--logo-border-color);
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,6 +14,9 @@ export default defineComponent({
|
|||
setup() {
|
||||
const appStore = useAppStore()
|
||||
|
||||
// logo
|
||||
const logo = computed(() => appStore.logo)
|
||||
|
||||
const { push, currentRoute } = useRouter()
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
|
@ -61,8 +64,8 @@ export default defineComponent({
|
|||
'bg-[var(--left-menu-bg-color)]'
|
||||
]}
|
||||
>
|
||||
<Logo></Logo>
|
||||
<ElScrollbar class={[{ '!h-[calc(100%-var(--top-tool-height))]': true }]}>
|
||||
{logo.value ? <Logo></Logo> : undefined}
|
||||
<ElScrollbar class={[{ '!h-[calc(100%-var(--logo-height))]': logo.value }]}>
|
||||
<ElMenu
|
||||
defaultActive={unref(activeMenu)}
|
||||
mode={unref(menuMode)}
|
||||
|
@ -89,9 +92,28 @@ export default defineComponent({
|
|||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-menu';
|
||||
|
||||
.is-active--after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
background-color: var(--el-color-primary);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
transition: width var(--transition-time-02);
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
border-left: 1px solid var(--left-menu-border-color);
|
||||
content: '';
|
||||
}
|
||||
|
||||
:deep(.el-menu) {
|
||||
width: 100% !important;
|
||||
border-right: none;
|
||||
|
@ -123,6 +145,14 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
.is-active--after;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置子菜单的背景颜色
|
||||
.el-menu {
|
||||
.el-sub-menu__title,
|
||||
|
@ -138,7 +168,12 @@ export default defineComponent({
|
|||
|
||||
& > .is-active,
|
||||
& > .is-active > .el-sub-menu__title {
|
||||
position: relative;
|
||||
background-color: var(--left-menu-collapse-bg-active-color) !important;
|
||||
|
||||
&:after {
|
||||
.is-active--after;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +190,16 @@ export default defineComponent({
|
|||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-menu-popper';
|
||||
|
||||
.is-active--after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
background-color: var(--el-color-primary);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
&--vertical {
|
||||
// 设置选中时子标题的颜色
|
||||
|
@ -175,11 +220,16 @@ export default defineComponent({
|
|||
|
||||
// 设置选中时的高亮背景
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
background-color: var(--left-menu-bg-active-color) !important;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--left-menu-bg-active-color) !important;
|
||||
}
|
||||
|
||||
&:after {
|
||||
.is-active--after;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,64 @@
|
|||
<script setup lang="ts">
|
||||
import { ElDrawer } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import { ElDrawer, ElDivider } from 'element-plus'
|
||||
import { ref, unref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||
import { ColorRadioPicker } from '@/components/ColorRadioPicker'
|
||||
import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
|
||||
import { useCssVar } from '@vueuse/core'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { trim, setCssVar } from '@/utils'
|
||||
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const drawer = ref(false)
|
||||
|
||||
// 主题色相关
|
||||
const systemTheme = ref(appStore.getTheme.elColorPrimary)
|
||||
|
||||
const setSystemTheme = (color: string) => {
|
||||
setCssVar('--el-color-primary', color)
|
||||
appStore.setTheme({ elColorPrimary: color })
|
||||
const leftMenuBgColor = useCssVar('--left-menu-bg-color', document.documentElement)
|
||||
setMenuTheme(trim(unref(leftMenuBgColor)))
|
||||
}
|
||||
|
||||
// 菜单主题相关
|
||||
const menuTheme = ref(appStore.getTheme.leftMenuBgColor)
|
||||
|
||||
const setMenuTheme = (color: string) => {
|
||||
const primaryColor = useCssVar('--el-color-primary', document.documentElement)
|
||||
const isDarkColor = colorIsDark(color)
|
||||
const theme: Recordable = {
|
||||
// 左侧菜单边框颜色
|
||||
leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
|
||||
// 左侧菜单背景颜色
|
||||
leftMenuBgColor: color,
|
||||
// 左侧菜单浅色背景颜色
|
||||
leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
|
||||
// 左侧菜单选中背景颜色
|
||||
leftMenuBgActiveColor: isDarkColor
|
||||
? 'var(--el-color-primary)'
|
||||
: hexToRGB(unref(primaryColor), 0.1),
|
||||
// 左侧菜单收起选中背景颜色
|
||||
leftMenuCollapseBgActiveColor: isDarkColor
|
||||
? 'var(--el-color-primary)'
|
||||
: hexToRGB(unref(primaryColor), 0.1),
|
||||
// 左侧菜单字体颜色
|
||||
leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
|
||||
// 左侧菜单选中字体颜色
|
||||
leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
|
||||
// logo字体颜色
|
||||
logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
|
||||
// logo边框颜色
|
||||
logoBorderColor: isDarkColor ? 'inherit' : '#eee'
|
||||
}
|
||||
appStore.setTheme(theme)
|
||||
appStore.setCssVarTheme()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -13,7 +69,58 @@ const drawer = ref(false)
|
|||
<Icon icon="ant-design:setting-outlined" color="#fff" />
|
||||
</div>
|
||||
|
||||
<ElDrawer v-model="drawer" :with-header="false" direction="rtl" size="300px">ddd</ElDrawer>
|
||||
<ElDrawer v-model="drawer" direction="rtl" size="350px">
|
||||
<template #title>
|
||||
<span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
|
||||
</template>
|
||||
|
||||
<div class="text-center">
|
||||
<!-- 主题 -->
|
||||
<ElDivider>{{ t('setting.theme') }}</ElDivider>
|
||||
<ThemeSwitch />
|
||||
|
||||
<!-- 布局 -->
|
||||
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
||||
|
||||
<!-- 系统主题 -->
|
||||
<ElDivider>{{ t('setting.systemTheme') }}</ElDivider>
|
||||
<ColorRadioPicker
|
||||
v-model="systemTheme"
|
||||
:schema="[
|
||||
'#409eff',
|
||||
'#009688',
|
||||
'#536dfe',
|
||||
'#ff5c93',
|
||||
'#ee4f12',
|
||||
'#0096c7',
|
||||
'#9c27b0',
|
||||
'#ff9800'
|
||||
]"
|
||||
@change="setSystemTheme"
|
||||
/>
|
||||
|
||||
<!-- 菜单主题 -->
|
||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
||||
<ColorRadioPicker
|
||||
v-model="menuTheme"
|
||||
:schema="[
|
||||
'#fff',
|
||||
'#001529',
|
||||
'#212121',
|
||||
'#273352',
|
||||
'#191b24',
|
||||
'#383f45',
|
||||
'#001628',
|
||||
'#344058'
|
||||
]"
|
||||
@change="setMenuTheme"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 界面显示 -->
|
||||
<ElDivider>{{ t('setting.interfaceDisplay') }}</ElDivider>
|
||||
<InterfaceDisplay />
|
||||
</ElDrawer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
<script setup lang="ts">
|
||||
import { ElSwitch } from 'element-plus'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// 面包屑
|
||||
const breadcrumb = ref(appStore.getBreadcrumb)
|
||||
|
||||
const breadcrumbChange = (show: boolean) => {
|
||||
appStore.setBreadcrumb(show)
|
||||
}
|
||||
|
||||
// 面包屑图标
|
||||
const breadcrumbIcon = ref(appStore.getBreadcrumbIcon)
|
||||
|
||||
const breadcrumbIconChange = (show: boolean) => {
|
||||
appStore.setBreadcrumbIcon(show)
|
||||
}
|
||||
|
||||
// 折叠菜单
|
||||
const collapse = ref(appStore.getCollapse)
|
||||
|
||||
const collapseChange = (show: boolean) => {
|
||||
appStore.setCollapse(show)
|
||||
}
|
||||
|
||||
// 折叠图标
|
||||
const hamburger = ref(appStore.getHamburger)
|
||||
|
||||
const hamburgerChange = (show: boolean) => {
|
||||
appStore.setHamburger(show)
|
||||
}
|
||||
|
||||
// 全屏图标
|
||||
const screenfull = ref(appStore.getScreenfull)
|
||||
|
||||
const screenfullChange = (show: boolean) => {
|
||||
appStore.setScreenfull(show)
|
||||
}
|
||||
|
||||
// 尺寸图标
|
||||
const size = ref(appStore.getSize)
|
||||
|
||||
const sizeChange = (show: boolean) => {
|
||||
appStore.setSize(show)
|
||||
}
|
||||
|
||||
// 多语言图标
|
||||
const locale = ref(appStore.getLocale)
|
||||
|
||||
const localeChange = (show: boolean) => {
|
||||
appStore.setLocale(show)
|
||||
}
|
||||
|
||||
// 标签页
|
||||
const tagsView = ref(appStore.getTagsView)
|
||||
|
||||
const tagsViewChange = (show: boolean) => {
|
||||
appStore.setTagsView(show)
|
||||
}
|
||||
|
||||
// logo
|
||||
const logo = ref(appStore.getLogo)
|
||||
|
||||
const logoChange = (show: boolean) => {
|
||||
appStore.setLogo(show)
|
||||
}
|
||||
|
||||
// 灰色模式
|
||||
const greyMode = ref(appStore.getGreyMode)
|
||||
|
||||
const greyModeChange = (show: boolean) => {
|
||||
appStore.setGreyMode(show)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="v-interface-display">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.breadcrumb') }}</span>
|
||||
<ElSwitch v-model="breadcrumb" @change="breadcrumbChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.breadcrumbIcon') }}</span>
|
||||
<ElSwitch v-model="breadcrumbIcon" @change="breadcrumbIconChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.collapseMenu') }}</span>
|
||||
<ElSwitch v-model="collapse" @change="collapseChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.hamburgerIcon') }}</span>
|
||||
<ElSwitch v-model="hamburger" @change="hamburgerChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.screenfullIcon') }}</span>
|
||||
<ElSwitch v-model="screenfull" @change="screenfullChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.sizeIcon') }}</span>
|
||||
<ElSwitch v-model="size" @change="sizeChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.localeIcon') }}</span>
|
||||
<ElSwitch v-model="locale" @change="localeChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.tagsView') }}</span>
|
||||
<ElSwitch v-model="tagsView" @change="tagsViewChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.logo') }}</span>
|
||||
<ElSwitch v-model="logo" @change="logoChange" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-14px">{{ t('setting.greyMode') }}</span>
|
||||
<ElSwitch v-model="greyMode" @change="greyModeChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -9,13 +9,13 @@ const appStore = useAppStore()
|
|||
|
||||
const sizeMap = computed(() => appStore.sizeMap)
|
||||
|
||||
const setSize = (size: ElememtPlusSzie) => {
|
||||
appStore.setSize(size)
|
||||
const setCurrentSize = (size: ElememtPlusSzie) => {
|
||||
appStore.setCurrentSize(size)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDropdown trigger="click" @command="setSize">
|
||||
<ElDropdown trigger="click" @command="setCurrentSize">
|
||||
<Icon
|
||||
:size="18"
|
||||
icon="mdi:format-size"
|
||||
|
|
|
@ -127,7 +127,7 @@ watch(
|
|||
<template>
|
||||
<div class="v-tags-view h-[var(--tags-view-height)] flex w-full">
|
||||
<span class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer">
|
||||
<Icon icon="ant-design:left-outlined" color="#333" />
|
||||
<Icon icon="ep:d-arrow-left" color="#333" />
|
||||
</span>
|
||||
<div class="overflow-hidden flex-1">
|
||||
<ElScrollbar>
|
||||
|
@ -216,7 +216,7 @@ watch(
|
|||
</ElScrollbar>
|
||||
</div>
|
||||
<span class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer">
|
||||
<Icon icon="ant-design:right-outlined" color="#333" />
|
||||
<Icon icon="ep:d-arrow-right" color="#333" />
|
||||
</span>
|
||||
<span
|
||||
class="v-tags-view__tool w-[40px] h-[40px] text-center leading-[40px] cursor-pointer"
|
||||
|
|
|
@ -5,47 +5,68 @@ const { wsCache } = useCache()
|
|||
export type LayoutType = 'classic' | 'leftTop' | 'top' | 'test'
|
||||
|
||||
export interface AppState {
|
||||
breadcrumb: boolean
|
||||
breadcrumbIcon: boolean
|
||||
collapse: boolean
|
||||
showTags: boolean
|
||||
showLogo: boolean
|
||||
showNavbar: boolean
|
||||
fixedHeader: boolean
|
||||
hamburger: boolean
|
||||
screenfull: boolean
|
||||
size: boolean
|
||||
locale: boolean
|
||||
tagsView: boolean
|
||||
logo: boolean
|
||||
greyMode: boolean
|
||||
|
||||
layout: LayoutType
|
||||
showBreadcrumb: boolean
|
||||
showHamburger: boolean
|
||||
showScreenfull: boolean
|
||||
showUserInfo: boolean
|
||||
title: string
|
||||
logoTitle: string
|
||||
userInfo: string
|
||||
greyMode: boolean
|
||||
showBackTop: boolean
|
||||
showMenuTab: boolean
|
||||
isDark: boolean
|
||||
size: ElememtPlusSzie
|
||||
currentSize: ElememtPlusSzie
|
||||
sizeMap: ElememtPlusSzie[]
|
||||
mobile: boolean
|
||||
theme: Recordable
|
||||
}
|
||||
|
||||
export const appModules: AppState = {
|
||||
collapse: false, // 菜单栏是否栏缩收
|
||||
showLogo: true, // 是否显示logo
|
||||
showTags: true, // 是否显示标签栏
|
||||
showNavbar: true, // 是否显示navbar
|
||||
fixedHeader: true, // 是否固定header
|
||||
breadcrumb: true, // 面包屑
|
||||
breadcrumbIcon: true, // 面包屑图标
|
||||
collapse: false, // 折叠菜单
|
||||
hamburger: true, // 折叠图标
|
||||
screenfull: true, // 全屏图标
|
||||
size: true, // 尺寸图标
|
||||
locale: true, // 多语言图标
|
||||
tagsView: true, // 标签页
|
||||
logo: true, // logo
|
||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||
|
||||
layout: 'classic', // layout布局
|
||||
showBreadcrumb: true, // 是否显示面包屑
|
||||
showHamburger: true, // 是否显示侧边栏缩收按钮
|
||||
showScreenfull: true, // 是否全屏按钮
|
||||
showUserInfo: true, // 是否显示用户头像
|
||||
title: 'butterfly-admin', // 标题
|
||||
logoTitle: 'ButterflyAdmin', // logo标题
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||
showBackTop: true, // 是否显示回到顶部
|
||||
showMenuTab: false, // 是否固定一级菜单
|
||||
isDark: wsCache.get('isDark') || false, // 是否是暗黑模式
|
||||
size: wsCache.get('default') || 'default', // 组件尺寸
|
||||
currentSize: wsCache.get('default') || 'default', // 组件尺寸
|
||||
sizeMap: ['default', 'large', 'small'],
|
||||
mobile: false // 是否是移动端
|
||||
mobile: false, // 是否是移动端
|
||||
theme: wsCache.get('theme') || {
|
||||
// 主题色
|
||||
elColorPrimary: '#409eff',
|
||||
// 左侧菜单边框颜色
|
||||
leftMenuBorderColor: 'inherit',
|
||||
// 左侧菜单背景颜色
|
||||
leftMenuBgColor: '#001529',
|
||||
// 左侧菜单浅色背景颜色
|
||||
leftMenuBgLightColor: '#0f2438',
|
||||
// 左侧菜单选中背景颜色
|
||||
leftMenuBgActiveColor: 'var(--el-color-primary)',
|
||||
// 左侧菜单收起选中背景颜色
|
||||
leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
|
||||
// 左侧菜单字体颜色
|
||||
leftMenuTextColor: '#bfcbd9',
|
||||
// 左侧菜单选中字体颜色
|
||||
leftMenuTextActiveColor: '#fff',
|
||||
// logo字体颜色
|
||||
logoTitleTextColor: '#fff',
|
||||
// logo边框颜色
|
||||
logoBorderColor: 'inherit'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,13 @@ export const elLocaleMap = {
|
|||
'zh-CN': zhCn,
|
||||
en: en
|
||||
}
|
||||
|
||||
export interface LocaleState {
|
||||
locale: LocaleDropdownType
|
||||
currentLocale: LocaleDropdownType
|
||||
localeMap: LocaleDropdownType[]
|
||||
}
|
||||
|
||||
export const localeModules: LocaleState = {
|
||||
locale: {
|
||||
currentLocale: {
|
||||
lang: wsCache.get('lang') || 'zh-CN',
|
||||
elLocale: elLocaleMap[wsCache.get('lang') || 'zh-CN']
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ const setI18nLanguage = (locale: LocaleType) => {
|
|||
} else {
|
||||
;(i18n.global.locale as any).value = locale
|
||||
}
|
||||
localeStore.setLocale({
|
||||
localeStore.setCurrentLocale({
|
||||
lang: locale
|
||||
})
|
||||
setHtmlPageLang(locale)
|
||||
|
|
|
@ -15,10 +15,30 @@ import AppView from './components/AppView.vue'
|
|||
|
||||
const appStore = useAppStore()
|
||||
|
||||
// 是否是移动端
|
||||
const mobile = computed(() => appStore.getMobile)
|
||||
|
||||
// 面包屑
|
||||
const breadcrumb = computed(() => appStore.getBreadcrumb)
|
||||
|
||||
// 菜单折叠
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
||||
// 折叠图标
|
||||
const hamburger = computed(() => appStore.getHamburger)
|
||||
|
||||
// 全屏图标
|
||||
const screenfull = computed(() => appStore.getScreenfull)
|
||||
|
||||
// 尺寸图标
|
||||
const size = computed(() => appStore.getSize)
|
||||
|
||||
// 多语言图标
|
||||
const locale = computed(() => appStore.getLocale)
|
||||
|
||||
// 标签页
|
||||
const tagsView = computed(() => appStore.getTagsView)
|
||||
|
||||
const classSuffix = computed(() => appStore.getLayout)
|
||||
|
||||
const handleClickOutside = () => {
|
||||
|
@ -57,19 +77,22 @@ export default defineComponent({
|
|||
]}
|
||||
>
|
||||
<div class="h-full flex items-center">
|
||||
<Collapse class="header__tigger"></Collapse>
|
||||
<Breadcrumb class="<md:hidden"></Breadcrumb>
|
||||
{hamburger.value ? <Collapse class="header__tigger"></Collapse> : undefined}
|
||||
{breadcrumb.value ? <Breadcrumb class="<md:hidden"></Breadcrumb> : undefined}
|
||||
</div>
|
||||
<div class="h-full flex items-center">
|
||||
<Screenfull class="header__tigger"></Screenfull>
|
||||
<SizeDropdown class="header__tigger"></SizeDropdown>
|
||||
<LocaleDropdown class="header__tigger"></LocaleDropdown>
|
||||
{screenfull.value ? <Screenfull class="header__tigger"></Screenfull> : undefined}
|
||||
{size.value ? <SizeDropdown class="header__tigger"></SizeDropdown> : undefined}
|
||||
{locale.value ? <LocaleDropdown class="header__tigger"></LocaleDropdown> : undefined}
|
||||
<UserInfo class="header__tigger"></UserInfo>
|
||||
</div>
|
||||
</div>
|
||||
{tagsView.value ? (
|
||||
<div class="v-app-right__tags-view relative">
|
||||
<TagsView></TagsView>
|
||||
</div>
|
||||
) : undefined}
|
||||
|
||||
<AppView></AppView>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -19,6 +19,24 @@ export default {
|
|||
closeOther: 'Close other',
|
||||
closeAll: 'Close all'
|
||||
},
|
||||
setting: {
|
||||
projectSetting: 'Project setting',
|
||||
theme: 'Theme',
|
||||
layout: 'Layout',
|
||||
systemTheme: 'System theme',
|
||||
menuTheme: 'Menu theme',
|
||||
interfaceDisplay: 'Interface display',
|
||||
breadcrumb: 'Breadcrumb',
|
||||
breadcrumbIcon: 'Breadcrumb icon',
|
||||
collapseMenu: 'Collapse menu',
|
||||
hamburgerIcon: 'Hamburger icon',
|
||||
screenfullIcon: 'Screenfull icon',
|
||||
sizeIcon: 'Size icon',
|
||||
localeIcon: 'Locale icon',
|
||||
tagsView: 'Tags view',
|
||||
logo: 'Logo',
|
||||
greyMode: 'Grey mode'
|
||||
},
|
||||
size: {
|
||||
default: 'Default',
|
||||
large: 'Large',
|
||||
|
@ -46,9 +64,6 @@ export default {
|
|||
menu12: 'Menu1-2',
|
||||
menu2: 'Menu2'
|
||||
},
|
||||
mock: {
|
||||
loginErr: 'Wrong account or password'
|
||||
},
|
||||
formDemo: {
|
||||
input: 'Input',
|
||||
inputNumber: 'InputNumber',
|
||||
|
|
|
@ -19,6 +19,24 @@ export default {
|
|||
closeOther: '关闭其他标签页',
|
||||
closeAll: '关闭全部标签页'
|
||||
},
|
||||
setting: {
|
||||
projectSetting: '项目配置',
|
||||
theme: '主题',
|
||||
layout: '布局',
|
||||
systemTheme: '系统主题',
|
||||
menuTheme: '菜单主题',
|
||||
interfaceDisplay: '界面显示',
|
||||
breadcrumb: '面包屑',
|
||||
breadcrumbIcon: '面包屑图标',
|
||||
collapseMenu: '折叠菜单',
|
||||
hamburgerIcon: '折叠图标',
|
||||
screenfullIcon: '全屏图标',
|
||||
sizeIcon: '尺寸图标',
|
||||
localeIcon: '多语言图标',
|
||||
tagsView: '标签页',
|
||||
logo: '标志',
|
||||
greyMode: '灰色模式'
|
||||
},
|
||||
size: {
|
||||
default: '默认',
|
||||
large: '大',
|
||||
|
@ -46,9 +64,6 @@ export default {
|
|||
menu12: '菜单1-2',
|
||||
menu2: '菜单2'
|
||||
},
|
||||
mock: {
|
||||
loginErr: '账号或密码错误'
|
||||
},
|
||||
formDemo: {
|
||||
input: '输入框',
|
||||
inputNumber: '数字输入框',
|
||||
|
|
|
@ -8,14 +8,14 @@ export let i18n: ReturnType<typeof createI18n>
|
|||
|
||||
const createI18nOptions = async (): Promise<I18nOptions> => {
|
||||
const localeStore = useLocaleStoreWithOut()
|
||||
const locale = localeStore.getLocale
|
||||
const locale = localeStore.getCurrentLocale
|
||||
const localeMap = localeStore.getLocaleMap
|
||||
const defaultLocal = await import(`../../locales/${locale.lang}.ts`)
|
||||
const message = defaultLocal.default ?? {}
|
||||
|
||||
setHtmlPageLang(locale.lang)
|
||||
|
||||
localeStore.setLocale({
|
||||
localeStore.setCurrentLocale({
|
||||
lang: locale.lang
|
||||
// elLocale: elLocal
|
||||
})
|
||||
|
|
|
@ -3,6 +3,7 @@ import { store } from '../index'
|
|||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { appModules } from '@/config/app'
|
||||
import type { AppState, LayoutType } from '@/config/app'
|
||||
import { setCssVar, humpToUnderline } from '@/utils'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
|
@ -10,36 +11,40 @@ export const useAppStore = defineStore({
|
|||
id: 'app',
|
||||
state: (): AppState => appModules,
|
||||
getters: {
|
||||
getBreadcrumb(): boolean {
|
||||
return this.breadcrumb
|
||||
},
|
||||
getBreadcrumbIcon(): boolean {
|
||||
return this.breadcrumbIcon
|
||||
},
|
||||
getCollapse(): boolean {
|
||||
return this.collapse
|
||||
},
|
||||
getShowLogo(): boolean {
|
||||
return this.showLogo
|
||||
getHamburger(): boolean {
|
||||
return this.hamburger
|
||||
},
|
||||
getShowTags(): boolean {
|
||||
return this.showTags
|
||||
getScreenfull(): boolean {
|
||||
return this.screenfull
|
||||
},
|
||||
getShowNavbar(): boolean {
|
||||
return this.showNavbar
|
||||
getSize(): boolean {
|
||||
return this.size
|
||||
},
|
||||
getFixedHeader(): boolean {
|
||||
return this.fixedHeader
|
||||
getLocale(): boolean {
|
||||
return this.locale
|
||||
},
|
||||
getTagsView(): boolean {
|
||||
return this.tagsView
|
||||
},
|
||||
getLogo(): boolean {
|
||||
return this.logo
|
||||
},
|
||||
getGreyMode(): boolean {
|
||||
return this.greyMode
|
||||
},
|
||||
|
||||
getLayout(): LayoutType {
|
||||
return this.layout
|
||||
},
|
||||
getShowBreadcrumb(): boolean {
|
||||
return this.showBreadcrumb
|
||||
},
|
||||
getShowHamburger(): boolean {
|
||||
return this.showHamburger
|
||||
},
|
||||
getShowScreenfull(): boolean {
|
||||
return this.showScreenfull
|
||||
},
|
||||
getShowUserInfo(): boolean {
|
||||
return this.showUserInfo
|
||||
},
|
||||
getTitle(): string {
|
||||
return this.title
|
||||
},
|
||||
|
@ -49,74 +54,63 @@ export const useAppStore = defineStore({
|
|||
getUserInfo(): string {
|
||||
return this.userInfo
|
||||
},
|
||||
getGreyMode(): boolean {
|
||||
return this.greyMode
|
||||
},
|
||||
getShowBackTop(): boolean {
|
||||
return this.showBackTop
|
||||
},
|
||||
getShowMenuTab(): boolean {
|
||||
return this.showMenuTab
|
||||
},
|
||||
getIsDark(): boolean {
|
||||
return this.isDark
|
||||
},
|
||||
getSize(): ElememtPlusSzie {
|
||||
return this.size
|
||||
getCurrentSize(): ElememtPlusSzie {
|
||||
return this.currentSize
|
||||
},
|
||||
getSizeMap(): ElememtPlusSzie[] {
|
||||
return this.sizeMap
|
||||
},
|
||||
getMobile(): boolean {
|
||||
return this.mobile
|
||||
},
|
||||
getTheme(): Recordable {
|
||||
return this.theme
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setBreadcrumb(breadcrumb: boolean) {
|
||||
this.breadcrumb = breadcrumb
|
||||
},
|
||||
setBreadcrumbIcon(breadcrumbIcon: boolean) {
|
||||
this.breadcrumbIcon = breadcrumbIcon
|
||||
},
|
||||
setCollapse(collapse: boolean) {
|
||||
this.collapse = collapse
|
||||
},
|
||||
setShowLogo(showLogo: boolean) {
|
||||
this.showLogo = showLogo
|
||||
setHamburger(hamburger: boolean) {
|
||||
this.hamburger = hamburger
|
||||
},
|
||||
setShowTags(showTags: boolean) {
|
||||
this.showTags = showTags
|
||||
setScreenfull(screenfull: boolean) {
|
||||
this.screenfull = screenfull
|
||||
},
|
||||
setShowNavbar(showNavbar: boolean) {
|
||||
this.showNavbar = showNavbar
|
||||
setSize(size: boolean) {
|
||||
this.size = size
|
||||
},
|
||||
setFixedHeader(fixedHeader: boolean) {
|
||||
this.fixedHeader = fixedHeader
|
||||
setLocale(locale: boolean) {
|
||||
this.locale = locale
|
||||
},
|
||||
setTagsView(tagsView: boolean) {
|
||||
this.tagsView = tagsView
|
||||
},
|
||||
setLogo(logo: boolean) {
|
||||
this.logo = logo
|
||||
},
|
||||
setGreyMode(greyMode: boolean) {
|
||||
this.greyMode = greyMode
|
||||
},
|
||||
|
||||
setLayout(layout: LayoutType) {
|
||||
this.layout = layout
|
||||
},
|
||||
setBreadcrumb(showBreadcrumb: boolean) {
|
||||
this.showBreadcrumb = showBreadcrumb
|
||||
},
|
||||
setHamburger(showHamburger: boolean) {
|
||||
this.showHamburger = showHamburger
|
||||
},
|
||||
setScreenfull(showScreenfull: boolean) {
|
||||
this.showScreenfull = showScreenfull
|
||||
},
|
||||
setUserInfo(showUserInfo: boolean) {
|
||||
this.showUserInfo = showUserInfo
|
||||
},
|
||||
setTitle(title: string) {
|
||||
this.title = title
|
||||
},
|
||||
setLogoTitle(logoTitle: string) {
|
||||
this.logoTitle = logoTitle
|
||||
},
|
||||
setGreyMode(greyMode: boolean) {
|
||||
this.greyMode = greyMode
|
||||
},
|
||||
setShowBackTop(showBackTop: boolean) {
|
||||
this.showBackTop = showBackTop
|
||||
},
|
||||
setShowMenuTab(showMenuTab: boolean) {
|
||||
this.showMenuTab = showMenuTab
|
||||
},
|
||||
setIsDark(isDark: boolean) {
|
||||
this.isDark = isDark
|
||||
if (this.isDark) {
|
||||
|
@ -128,12 +122,21 @@ export const useAppStore = defineStore({
|
|||
}
|
||||
wsCache.set('isDark', this.isDark)
|
||||
},
|
||||
setSize(size: ElememtPlusSzie) {
|
||||
this.size = size
|
||||
wsCache.set('size', this.size)
|
||||
setCurrentSize(currentSize: ElememtPlusSzie) {
|
||||
this.currentSize = currentSize
|
||||
wsCache.set('currentSize', this.currentSize)
|
||||
},
|
||||
setMobile(mobile: boolean) {
|
||||
this.mobile = mobile
|
||||
},
|
||||
setTheme(theme: Recordable) {
|
||||
this.theme = Object.assign(this.theme, theme)
|
||||
wsCache.set('theme', this.theme)
|
||||
},
|
||||
setCssVarTheme() {
|
||||
for (const key in this.theme) {
|
||||
setCssVar(`--${humpToUnderline(key)}`, this.theme[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -10,18 +10,18 @@ export const useLocaleStore = defineStore({
|
|||
id: 'locales',
|
||||
state: (): LocaleState => localeModules,
|
||||
getters: {
|
||||
getLocale(): LocaleDropdownType {
|
||||
return this.locale
|
||||
getCurrentLocale(): LocaleDropdownType {
|
||||
return this.currentLocale
|
||||
},
|
||||
getLocaleMap(): LocaleDropdownType[] {
|
||||
return this.localeMap
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setLocale(localeMap: LocaleDropdownType) {
|
||||
setCurrentLocale(localeMap: LocaleDropdownType) {
|
||||
// this.locale = Object.assign(this.locale, localeMap)
|
||||
this.locale.lang = localeMap?.lang
|
||||
this.locale.elLocale = elLocaleMap[localeMap?.lang]
|
||||
this.currentLocale.lang = localeMap?.lang
|
||||
this.currentLocale.elLocale = elLocaleMap[localeMap?.lang]
|
||||
wsCache.set('lang', localeMap?.lang)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
--dark-bg-color: #293146;
|
||||
|
||||
/* left menu start */
|
||||
--left-menu-border-color: 'inherit';
|
||||
|
||||
--left-menu-max-width: 200px;
|
||||
|
||||
--left-menu-min-width: 64px;
|
||||
|
@ -23,10 +25,12 @@
|
|||
--logo-height: 50px;
|
||||
|
||||
--logo-title-text-color: #fff;
|
||||
|
||||
--logo-border-color: 'inherit';
|
||||
/* logo end */
|
||||
|
||||
/* header start */
|
||||
--top-tool-height: 40px;
|
||||
--top-tool-height: var(--logo-height);
|
||||
|
||||
--top-tool-p-x: 0;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export const rgbToHex = (r: number, g: number, b: number) => {
|
|||
* @param {string} hex The color to transform
|
||||
* @returns The RGB representation of the passed color
|
||||
*/
|
||||
export const hexToRGB = (hex: string) => {
|
||||
export const hexToRGB = (hex: string, opacity?: number) => {
|
||||
let sHex = hex.toLowerCase()
|
||||
if (isHexColor(hex)) {
|
||||
if (sHex.length === 4) {
|
||||
|
@ -44,7 +44,9 @@ export const hexToRGB = (hex: string) => {
|
|||
for (let i = 1; i < 7; i += 2) {
|
||||
sColorChange.push(parseInt('0x' + sHex.slice(i, i + 2)))
|
||||
}
|
||||
return 'RGB(' + sColorChange.join(',') + ')'
|
||||
return opacity
|
||||
? 'RGBA(' + sColorChange.join(',') + ',' + opacity + ')'
|
||||
: 'RGB(' + sColorChange.join(',') + ')'
|
||||
}
|
||||
return sHex
|
||||
}
|
||||
|
|
|
@ -59,3 +59,7 @@ export const findIndex = <T = Recordable>(ary: Array<T>, fn: Fn): number => {
|
|||
})
|
||||
return index
|
||||
}
|
||||
|
||||
export const trim = (str: string) => {
|
||||
return str.replace(/(^\s*)|(\s*$)/g, '')
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ const { t } = useI18n()
|
|||
|
||||
<div class="flex justify-end items-center space-x-10px">
|
||||
<ThemeSwitch />
|
||||
<LocaleDropdown class="<xl:!text-white dark:!text-white" />
|
||||
<LocaleDropdown class="<xl:text-white dark:text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<Transition appear enter-active-class="animate__animated animate__bounceInRight">
|
||||
|
|
Loading…
Reference in New Issue