feat(Layout): Add classic layout

This commit is contained in:
陈凯龙 2022-01-18 16:22:47 +08:00
parent 958edefe7b
commit 839b6015b8
26 changed files with 632 additions and 147 deletions

View File

@ -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"
}

View File

@ -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>

View File

@ -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)}
</>

View File

@ -0,0 +1,3 @@
import ColorRadioPicker from './src/ColorRadioPicker.vue'
export { ColorRadioPicker }

View File

@ -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>

View File

@ -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>

View File

@ -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()

View File

@ -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>

View File

@ -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;
}
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -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'
}
}

View File

@ -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']
},

View File

@ -10,7 +10,7 @@ const setI18nLanguage = (locale: LocaleType) => {
} else {
;(i18n.global.locale as any).value = locale
}
localeStore.setLocale({
localeStore.setCurrentLocale({
lang: locale
})
setHtmlPageLang(locale)

View File

@ -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>

View File

@ -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',

View File

@ -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: '数字输入框',

View File

@ -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
})

View File

@ -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])
}
}
}
})

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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
}

View File

@ -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, '')
}

View File

@ -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">