Refactor/themes (#311)

* refactor: theme
This commit is contained in:
RealityBoy
2022-07-26 13:16:44 +08:00
committed by GitHub
parent 708ce43e00
commit d824c99489
62 changed files with 1100 additions and 1066 deletions

View File

@@ -6,7 +6,6 @@ import Search from "./search/index.vue";
import Notice from "./notice/index.vue";
import mixNav from "./sidebar/mixNav.vue";
import avatars from "/@/assets/avatars.jpg";
import Hamburger from "./sidebar/hamBurger.vue";
import { watch, getCurrentInstance } from "vue";
import Breadcrumb from "./sidebar/breadCrumb.vue";
import { deviceDetection } from "@pureadmin/utils";
@@ -21,11 +20,11 @@ const {
logout,
onPanel,
changeTitle,
toggleSideBar,
pureApp,
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@@ -51,14 +50,9 @@ function translationEn() {
</script>
<template>
<div class="navbar">
<Hamburger
v-if="pureApp.layout !== 'mix'"
:is-active="pureApp.sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<div
class="navbar bg-[#fff] shadow-sm shadow-[rgba(0, 21, 41, 0.08)] dark:shadow-[#0d0d0d]"
>
<Breadcrumb v-if="pureApp.layout !== 'mix'" class="breadcrumb-container" />
<mixNav v-if="pureApp.layout === 'mix'" />
@@ -72,11 +66,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<IconifyIconOffline
@@ -88,6 +85,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@@ -100,9 +98,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@@ -117,7 +115,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>
@@ -132,17 +130,6 @@ function translationEn() {
width: 100%;
height: 48px;
overflow: hidden;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 48px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
}
.vertical-header-right {
display: flex;
@@ -152,31 +139,6 @@ function translationEn() {
color: #000000d9;
justify-content: flex-end;
:deep(.dropdown-badge) {
&:hover {
background: #f6f6f6;
}
}
.screen-full {
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
.globalization {
height: 48px;
width: 40px;
padding: 11px;
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
.el-dropdown-link {
height: 48px;
padding: 10px;
@@ -186,10 +148,6 @@ function translationEn() {
cursor: pointer;
color: #000000d9;
&:hover {
background: #f6f6f6;
}
p {
font-size: 14px;
}
@@ -208,15 +166,12 @@ function translationEn() {
display: flex;
cursor: pointer;
align-items: center;
&:hover {
background: #f6f6f6;
}
}
}
.breadcrumb-container {
float: left;
margin-left: 16px;
}
}

View File

@@ -22,7 +22,7 @@ function tabClick() {
<template>
<el-dropdown ref="dropdownDom" trigger="click" placement="bottom-end">
<span class="dropdown-badge">
<span class="dropdown-badge navbar-bg-hover select-none">
<el-badge :value="noticesNum" :max="99">
<span class="header-notice-icon">
<IconifyIconOffline icon="bell" />

View File

@@ -44,7 +44,9 @@ function hoverDescription(event, description) {
</script>
<template>
<div class="notice-container">
<div
class="notice-container border-b-1 border-[#f0f0f0] dark:border-[#303030]"
>
<el-avatar
v-if="props.noticeItem.avatar"
:size="30"
@@ -52,7 +54,7 @@ function hoverDescription(event, description) {
class="notice-container-avatar"
/>
<div class="notice-container-text">
<div class="notice-text-title">
<div class="notice-text-title color-[#000000d9] dark:color-white">
<el-tooltip
popper-class="notice-title-popper"
:disabled="!titleTooltip"
@@ -91,7 +93,7 @@ function hoverDescription(event, description) {
{{ props.noticeItem.description }}
</div>
</el-tooltip>
<div class="notice-text-datetime">
<div class="notice-text-datetime color-[#00000073] dark:color-white">
{{ props.noticeItem.datetime }}
</div>
</div>
@@ -109,7 +111,7 @@ function hoverDescription(event, description) {
align-items: flex-start;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
// border-bottom: 1px solid #f0f0f0;
.notice-container-avatar {
margin-right: 16px;
@@ -128,7 +130,6 @@ function hoverDescription(event, description) {
font-weight: 400;
font-size: 14px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.85);
cursor: pointer;
.notice-title-content {
@@ -150,7 +151,6 @@ function hoverDescription(event, description) {
.notice-text-datetime {
font-size: 12px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.45);
}
.notice-text-description {

View File

@@ -18,7 +18,7 @@ emitter.on("openPanel", () => {
<template>
<div :class="{ show: show }" class="right-panel-container">
<div class="right-panel-background" />
<div ref="target" class="right-panel">
<div ref="target" class="right-panel bg-white dark:bg-dark">
<div class="right-panel-items">
<div class="project-configuration">
<h3>项目配置</h3>
@@ -26,7 +26,7 @@ emitter.on("openPanel", () => {
<IconifyIconOffline icon="close" />
</el-icon>
</div>
<div style="border-bottom: 1px solid #dcdfe6" />
<div class="border-b-1 border-[#dcdfe6] dark:border-[#303030]" />
<slot />
</div>
</div>
@@ -62,7 +62,7 @@ emitter.on("openPanel", () => {
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.05);
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
transform: translate(100%);
background: #fff;
// background: #fff;
z-index: 40000;
}

View File

@@ -1,13 +1,16 @@
<script setup lang="ts">
import { useFullscreen } from "@vueuse/core";
import { useI18n } from "vue-i18n";
import { useFullscreen } from "@vueuse/core";
const { t } = useI18n();
const { isFullscreen, toggle } = useFullscreen();
</script>
<template>
<div class="screen-full" @click="toggle">
<div
class="screen-full w-36px h-48px flex-ac cursor-pointer navbar-bg-hover"
@click="toggle"
>
<FontIcon
:title="
isFullscreen ? t('buttons.hsexitfullscreen') : t('buttons.hsfullscreen')
@@ -16,13 +19,3 @@ const { isFullscreen, toggle } = useFullscreen();
/>
</div>
</template>
<style lang="scss" scoped>
.screen-full {
width: 36px;
height: 48px;
display: flex;
align-items: center;
justify-content: space-around;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="search-footer">
<div class="search-footer color-[#333] dark:color-white">
<span class="search-footer-item">
<enterOutlined class="icon" />
确认
@@ -23,7 +23,6 @@ import mdiKeyboardEsc from "/@/assets/svg/mdi_keyboard_esc.svg?component";
<style lang="scss" scoped>
.search-footer {
display: flex;
color: #333;
.search-footer-item {
display: flex;

View File

@@ -1,24 +1,3 @@
<template>
<div class="result">
<template v-for="item in options" :key="item.path">
<div
class="result-item"
:style="{
background:
item?.path === active ? useEpThemeStoreHook().epThemeColor : '',
color: item.path === active ? '#fff' : ''
}"
@click="handleTo"
@mouseenter="handleMouse(item)"
>
<component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" />
<span class="result-item-title">{{ t(item.meta?.title) }}</span>
<enterOutlined />
</div>
</template>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useI18n } from "vue-i18n";
@@ -49,6 +28,17 @@ interface Emits {
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<Emits>();
const itemStyle = computed(() => {
return item => {
return {
background:
item?.path === active.value ? useEpThemeStoreHook().epThemeColor : "",
color: item.path === active.value ? "#fff" : "",
fontSize: item.path === active.value ? "16px" : "14px"
};
};
});
const active = computed({
get() {
return props.value;
@@ -67,6 +57,24 @@ function handleTo() {
emit("enter");
}
</script>
<template>
<div class="result">
<template v-for="item in options" :key="item.path">
<div
class="result-item dark:bg-[#1d1d1d]"
:style="itemStyle(item)"
@click="handleTo"
@mouseenter="handleMouse(item)"
>
<component :is="useRenderIcon(item.meta?.icon ?? 'bookmark-2-line')" />
<span class="result-item-title">{{ t(item.meta?.title) }}</span>
<enterOutlined />
</div>
</template>
</div>
</template>
<style lang="scss" scoped>
.result {
padding-bottom: 12px;
@@ -78,8 +86,9 @@ function handleTo() {
margin-top: 8px;
padding: 14px;
border-radius: 4px;
background: #e5e7eb;
cursor: pointer;
border: 0.1px solid #ccc;
transition: all 0.3s;
&-title {
display: flex;

View File

@@ -8,23 +8,11 @@ function handleSearch() {
</script>
<template>
<div class="search-container" @click="handleSearch">
<div
class="search-container w-40px h-48px flex-c cursor-pointer navbar-bg-hover"
@click="handleSearch"
>
<IconifyIconOffline icon="search" />
</div>
<SearchModal v-model:value="show" />
</template>
<style lang="scss" scoped>
.search-container {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
width: 40px;
cursor: pointer;
&:hover {
background: #f6f6f6;
}
}
</style>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts">
import {
reactive,
ref,
unref,
watch,
reactive,
computed,
nextTick,
useCssModule,
@@ -15,21 +15,30 @@ import { useRouter } from "vue-router";
import panel from "../panel/index.vue";
import { emitter } from "/@/utils/mitt";
import { templateRef } from "@vueuse/core";
import { TinyColor } from "@ctrl/tinycolor";
import { themeColorsType } from "../../types";
import { routerArrays } from "/@/layout/types";
import type { StorageConfigs } from "/#/index";
import { useAppStoreHook } from "/@/store/modules/app";
import { shadeBgColor } from "../../theme/element-plus";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { createNewStyle, writeNewStyle } from "../../theme/element-plus";
import { debounce, storageLocal, storageSession } from "@pureadmin/utils";
import {
useDark,
debounce,
storageLocal,
storageSession
} from "@pureadmin/utils";
import {
darken,
lighten,
toggleTheme
} from "@pureadmin/theme/dist/browser-utils";
import dayIcon from "/@/assets/svg/day.svg?component";
import darkIcon from "/@/assets/svg/dark.svg?component";
const router = useRouter();
const { isDark } = useDark();
const { isSelect } = useCssModule();
const body = document.documentElement as HTMLElement;
const instance =
@@ -39,29 +48,29 @@ const instanceConfig =
getCurrentInstance().appContext.app.config.globalProperties.$config;
let themeColors = ref<Array<themeColorsType>>([
// 道奇蓝(默认)
/* 道奇蓝(默认) */
{ color: "#1b2a47", themeColor: "default" },
// 亮白色
/* 亮白色 */
{ color: "#ffffff", themeColor: "light" },
// 猩红色
/* 猩红色 */
{ color: "#f5222d", themeColor: "dusk" },
// 橙红色
/* 橙红色 */
{ color: "#fa541c", themeColor: "volcano" },
// 金色
/* 金色 */
{ color: "#fadb14", themeColor: "yellow" },
// 绿宝石
/* 绿宝石 */
{ color: "#13c2c2", themeColor: "mingQing" },
// 酸橙绿
/* 酸橙绿 */
{ color: "#52c41a", themeColor: "auroraGreen" },
// 深粉色
/* 深粉色 */
{ color: "#eb2f96", themeColor: "pink" },
// 深紫罗兰色
/* 深紫罗兰色 */
{ color: "#722ed1", themeColor: "saucePurple" }
]);
const mixRef = templateRef<HTMLElement | null>("mixRef", null);
const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
const mixRef = templateRef<HTMLElement | null>("mixRef", null);
let layoutTheme =
ref(storageLocal.getItem<StorageConfigs>("responsive-layout")) ||
@@ -70,7 +79,7 @@ let layoutTheme =
theme: instanceConfig?.Theme ?? "default"
});
// body添加layout属性作用于src/style/sidebar.scss
/* body添加layout属性作用于src/style/sidebar.scss */
if (unref(layoutTheme)) {
let layout = unref(layoutTheme).layout;
let theme = unref(layoutTheme).theme;
@@ -80,13 +89,11 @@ if (unref(layoutTheme)) {
setLayoutModel(layout);
}
// 默认灵动模式
/** 默认灵动模式 */
const markValue = ref(instance.configure?.showModel ?? "smart");
const logoVal = ref(instance.configure?.showLogo ?? true);
const epThemeColor = ref(useEpThemeStoreHook().getEpThemeColor);
const settings = reactive({
greyVal: instance.configure.grey,
weakVal: instance.configure.weak,
@@ -102,6 +109,13 @@ const getThemeColorStyle = computed(() => {
};
});
/** 当网页为暗黑模式时不显示亮白色切换选项 */
const showThemeColors = computed(() => {
return themeColor => {
return themeColor === "light" && isDark.value ? false : true;
};
});
function storageConfigureChange<T>(key: string, val: T): void {
const storageConfigure = instance.configure;
storageConfigure[key] = val;
@@ -115,13 +129,13 @@ function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
targetEl.className = flag ? `${className} ${clsName} ` : className;
}
// 灰色模式设置
/** 灰色模式设置 */
const greyChange = (value): void => {
toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
storageConfigureChange("grey", value);
};
// 色弱模式设置
/** 色弱模式设置 */
const weekChange = (value): void => {
toggleClass(
settings.weakVal,
@@ -143,7 +157,7 @@ const multiTagsCacheChange = () => {
useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache);
};
// 清空缓存并返回登录页
/** 清空缓存并返回登录页 */
function onReset() {
router.push("/login");
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
@@ -162,7 +176,7 @@ function onChange(label) {
emitter.emit("tagViewsShowModel", label);
}
// 侧边栏Logo
/** 侧边栏Logo */
function logoChange() {
unref(logoVal)
? storageConfigureChange("showLogo", true)
@@ -177,7 +191,7 @@ function setFalse(Doms): any {
}
watch(instance, ({ layout }) => {
// 设置wangeditorV5主题色
/* 设置wangeditorV5主题色 */
body.style.setProperty("--w-e-toolbar-active-color", layout["epThemeColor"]);
switch (layout["layout"]) {
case "vertical":
@@ -198,7 +212,7 @@ watch(instance, ({ layout }) => {
}
});
// 主题色 激活选择项
/** 主题色 激活选择项 */
const getThemeColor = computed(() => {
return current => {
if (
@@ -217,7 +231,7 @@ const getThemeColor = computed(() => {
};
});
// 设置导航模式
/** 设置导航模式 */
function setLayoutModel(layout: string) {
layoutTheme.value.layout = layout;
window.document.body.setAttribute("layout", layout);
@@ -231,12 +245,8 @@ function setLayoutModel(layout: string) {
useAppStoreHook().setLayout(layout);
}
// 存放夜间主题切换前的导航主题色
let tempLayoutThemeColor;
// 设置导航主题色
/** 设置导航主题色 */
function setLayoutThemeColor(theme: string) {
tempLayoutThemeColor = instance.layout.theme;
layoutTheme.value.theme = theme;
toggleTheme({
scopeName: `layout-theme-${theme}`
@@ -257,43 +267,60 @@ function setLayoutThemeColor(theme: string) {
}
}
// 设置ep主题色
/**
* @description 自动计算hover和active颜色
* @see {@link https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2}
*/
const shadeBgColor = (color: string): string => {
return new TinyColor(color).shade(10).toString();
};
/** 设置ep主题色 */
const setEpThemeColor = (color: string) => {
// @ts-expect-error
writeNewStyle(createNewStyle(color));
useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));
document.documentElement.style.setProperty("--el-color-primary", color);
for (let i = 1; i <= 9; i++) {
document.documentElement.style.setProperty(
`--el-color-primary-light-${i}`,
lighten(color, i / 10)
);
}
for (let i = 1; i <= 2; i++) {
document.documentElement.style.setProperty(
`--el-color-primary-dark-${i}`,
darken(color, i / 10)
);
}
};
let dataTheme = ref<boolean>(instance.layout.darkMode);
// 日间、夜间主题切换
/** 日间、夜间主题切换 */
function dataThemeChange() {
if (dataTheme.value) {
body.setAttribute("data-theme", "dark");
setLayoutThemeColor("light");
/* 如果当前是light夜间主题默认切换到default主题 */
if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) {
setLayoutThemeColor("default");
} else {
body.setAttribute("data-theme", "");
tempLayoutThemeColor && setLayoutThemeColor(tempLayoutThemeColor);
instance.layout = {
layout: useAppStoreHook().layout,
theme: instance.layout.theme,
darkMode: dataTheme.value,
sidebarStatus: instance.layout.sidebarStatus,
epThemeColor: instance.layout.epThemeColor
};
setLayoutThemeColor(useEpThemeStoreHook().epTheme);
}
if (dataTheme.value) {
instance.layout.darkMode = true;
document.documentElement.classList.add("dark");
} else {
instance.layout.darkMode = false;
document.documentElement.classList.remove("dark");
}
}
//初始化项目配置
/* 初始化项目配置 */
nextTick(() => {
settings.greyVal &&
document.querySelector("html")?.setAttribute("class", "html-grey");
settings.weakVal &&
document.querySelector("html")?.setAttribute("class", "html-weakness");
settings.tabsVal && tagsChange();
// @ts-expect-error
writeNewStyle(createNewStyle(epThemeColor.value));
dataThemeChange();
});
</script>
@@ -346,11 +373,12 @@ nextTick(() => {
</el-tooltip>
</ul>
<el-divider v-show="!dataTheme">主题色</el-divider>
<ul class="theme-color" v-show="!dataTheme">
<el-divider>主题色</el-divider>
<ul class="theme-color">
<li
v-for="(item, index) in themeColors"
:key="index"
v-show="showThemeColors(item.themeColor)"
:style="getThemeColorStyle(item.color)"
@click="setLayoutThemeColor(item.themeColor)"
>
@@ -366,7 +394,7 @@ nextTick(() => {
<el-divider>界面显示</el-divider>
<ul class="setting">
<li v-show="!dataTheme">
<li>
<span>灰色模式</span>
<el-switch
v-model="settings.greyVal"
@@ -377,7 +405,7 @@ nextTick(() => {
@change="greyChange"
/>
</li>
<li v-show="!dataTheme">
<li>
<span>色弱模式</span>
<el-switch
v-model="settings.weakVal"

View File

@@ -98,7 +98,7 @@ const handleLink = (item: RouteLocationMatched): any => {
</script>
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<el-breadcrumb class="app-breadcrumb select-none" separator="/">
<transition-group appear name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span

View File

@@ -1,15 +1,14 @@
<script setup lang="ts">
import { ref } from "vue";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
export interface Props {
import { useDark } from "@pureadmin/utils";
interface Props {
isActive: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isActive: false
});
const fillColor = ref<string>("");
const { isDark } = useDark();
const emit = defineEmits<{
(e: "toggleClick"): void;
@@ -21,43 +20,28 @@ const toggleClick = () => {
</script>
<template>
<div
:class="classes.container"
:title="props.isActive ? '点击折叠' : '点击展开'"
@click="toggleClick"
@mouseenter="fillColor = useEpThemeStoreHook().epThemeColor"
@mouseleave="fillColor = ''"
>
<svg
:fill="fillColor"
:class="['hamburger', props.isActive ? 'is-active' : '']"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
<div class="hamburger-container">
<el-tooltip
placement="right"
:effect="isDark ? 'dark' : 'light'"
:content="props.isActive ? '点击折叠' : '点击展开'"
>
<path
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
<IconifyIconOffline
:icon="props.isActive ? 'menu-fold' : 'menu-unfold'"
class="cursor-pointer inline-block align-middle color-primary hover:color-primary !dark:hover:color-white w-16px h-16px ml-4 mb-1"
@click="toggleClick"
/>
</svg>
</el-tooltip>
</div>
</template>
<style module="classes" scoped>
.container {
padding: 0 15px;
}
</style>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.is-active {
transform: rotate(180deg);
<style lang="scss" scoped>
.hamburger-container {
position: absolute;
bottom: 0;
width: 210px;
height: 40px;
line-height: 40px;
box-shadow: 0 0 6px -2px var(--el-color-primary);
}
</style>

View File

@@ -32,6 +32,7 @@ const {
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@@ -78,11 +79,11 @@ function translationEn() {
<h4>{{ title }}</h4>
</div>
<el-menu
ref="menu"
class="horizontal-header-menu"
mode="horizontal"
:default-active="route.path"
router
ref="menu"
mode="horizontal"
class="horizontal-header-menu"
:default-active="route.path"
@select="indexPath => menuSelect(indexPath, routers)"
>
<sidebar-item
@@ -101,11 +102,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
@@ -115,6 +119,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@@ -127,9 +132,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@@ -144,7 +149,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>

View File

@@ -10,11 +10,17 @@ import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router";
import { deviceDetection } from "@pureadmin/utils";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import { getParentPaths, findRouteByPath } from "/@/router/utils";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component";
import { ref, watch, nextTick, onMounted, getCurrentInstance } from "vue";
import {
ref,
toRaw,
watch,
nextTick,
onMounted,
getCurrentInstance
} from "vue";
const route = useRoute();
const { locale, t } = useI18n();
@@ -27,14 +33,13 @@ const {
logout,
onPanel,
changeTitle,
toggleSideBar,
handleResize,
menuSelect,
resolvePath,
pureApp,
username,
avatarsStyle,
getDropdownItemStyle,
getDropdownItemClass,
changeWangeditorLanguage
} = useNav();
@@ -89,33 +94,12 @@ function translationEn() {
<template>
<div class="horizontal-header">
<div
:class="classes.container"
:title="pureApp.sidebar.opened ? '点击折叠' : '点击展开'"
@click="toggleSideBar"
>
<svg
:fill="useEpThemeStoreHook().fill"
:class="[
'hamburger',
pureApp.sidebar.opened ? 'is-active-hamburger' : ''
]"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
/>
</svg>
</div>
<el-menu
ref="menu"
class="horizontal-header-menu"
mode="horizontal"
:default-active="defaultActive"
router
ref="menu"
mode="horizontal"
class="horizontal-header-menu"
:default-active="defaultActive"
@select="indexPath => menuSelect(indexPath, routers)"
>
<el-menu-item
@@ -124,10 +108,15 @@ function translationEn() {
:index="resolvePath(route) || route.redirect"
>
<template #title>
<div v-show="route.meta.icon" :class="['el-icon', route.meta.icon]">
<component :is="useRenderIcon(route.meta && route.meta.icon)" />
<div
v-if="toRaw(route.meta.icon)"
:class="['sub-menu-icon', route.meta.icon]"
>
<component
:is="useRenderIcon(route.meta && toRaw(route.meta.icon))"
/>
</div>
<span>{{ transformI18n(route.meta.title) }}</span>
<span class="select-none">{{ transformI18n(route.meta.title) }}</span>
<FontIcon
v-if="route.meta.extraIcon"
width="30px"
@@ -148,11 +137,14 @@ function translationEn() {
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown id="header-translation" trigger="click">
<globalization />
<globalization
class="navbar-bg-hover w-40px h-48px p-11px cursor-pointer outline-none"
/>
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'zh')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'zh')]"
@click="translationCh"
>
<span class="check-zh" v-show="locale === 'zh'">
@@ -162,6 +154,7 @@ function translationEn() {
</el-dropdown-item>
<el-dropdown-item
:style="getDropdownItemStyle(locale, 'en')"
:class="['!dark:color-white', getDropdownItemClass(locale, 'en')]"
@click="translationEn"
>
<span class="check-en" v-show="locale === 'en'">
@@ -174,9 +167,9 @@ function translationEn() {
</el-dropdown>
<!-- 退出登录 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<span class="el-dropdown-link navbar-bg-hover">
<img v-if="avatars" :src="avatars" :style="avatarsStyle" />
<p v-if="username">{{ username }}</p>
<p v-if="username" class="dark:color-white">{{ username }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
@@ -191,7 +184,7 @@ function translationEn() {
</template>
</el-dropdown>
<span
class="el-icon-setting"
class="el-icon-setting navbar-bg-hover"
:title="t('buttons.hssystemSet')"
@click="onPanel"
>
@@ -201,26 +194,7 @@ function translationEn() {
</div>
</template>
<style module="classes" scoped>
.container {
padding: 0 15px;
}
</style>
<style lang="scss" scoped>
.hamburger {
width: 20px;
height: 20px;
&:hover {
cursor: pointer;
}
}
.is-active-hamburger {
transform: rotate(180deg);
}
.translation {
::v-deep(.el-dropdown-menu__item) {
padding: 5px 40px;

View File

@@ -5,7 +5,7 @@ import { childrenType } from "../../types";
import { transformI18n } from "/@/plugins/i18n";
import { useAppStoreHook } from "/@/store/modules/app";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
import { ref, PropType, nextTick, computed, CSSProperties } from "vue";
import { ref, toRaw, PropType, nextTick, computed, CSSProperties } from "vue";
const { pureApp } = useNav();
const menuMode = ["vertical", "mix"].includes(pureApp.layout);
@@ -54,9 +54,9 @@ const getDivStyle = computed((): CSSProperties => {
};
});
const getMenuTextStyle = computed((): CSSProperties => {
const getMenuTextStyle = computed(() => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
width: pureApp.sidebar.opened ? "210px" : "",
overflow: "hidden",
textOverflow: "ellipsis",
outline: "none"
@@ -65,14 +65,14 @@ const getMenuTextStyle = computed((): CSSProperties => {
const getSubTextStyle = computed((): CSSProperties => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
width: pureApp.sidebar.opened ? "210px" : "",
display: "inline-block",
overflow: "hidden",
textOverflow: "ellipsis"
};
});
const getSpanStyle = computed((): CSSProperties => {
const getSpanStyle = computed(() => {
return {
overflow: "hidden",
textOverflow: "ellipsis"
@@ -148,12 +148,12 @@ function resolvePath(routePath) {
:class="{ 'submenu-title-noDropdown': !isNest }"
:style="getNoDropdownStyle"
>
<div class="sub-menu-icon" v-show="props.item.meta.icon">
<div class="sub-menu-icon" v-if="toRaw(props.item.meta.icon)">
<component
:is="
useRenderIcon(
onlyOneChild.meta.icon ||
(props.item.meta && props.item.meta.icon)
toRaw(onlyOneChild.meta.icon) ||
(props.item.meta && toRaw(props.item.meta.icon))
)
"
/>
@@ -205,19 +205,14 @@ function resolvePath(routePath) {
</el-menu-item>
</template>
<el-sub-menu
v-else
ref="subMenu"
:index="resolvePath(props.item.path)"
popper-append-to-body
>
<el-sub-menu v-else ref="subMenu" :index="resolvePath(props.item.path)">
<template #title>
<div v-show="props.item.meta.icon" class="sub-menu-icon">
<div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon">
<component
:is="useRenderIcon(props.item.meta && props.item.meta.icon)"
:is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
/>
</div>
<span v-if="!menuMode">{{ transformI18n(props.item.meta.title) }}</span>
<span v-if="!menuMode"> {{ transformI18n(props.item.meta.title) }}</span>
<el-tooltip
v-else
placement="top"

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import Logo from "./logo.vue";
import Hamburger from "./hamBurger.vue";
import { emitter } from "/@/utils/mitt";
import { useNav } from "../../hooks/nav";
import SidebarItem from "./sidebarItem.vue";
@@ -16,7 +17,7 @@ const showLogo = ref(
storageLocal.getItem<StorageConfigs>("responsive-configure")?.showLogo ?? true
);
const { pureApp, isCollapse, menuSelect } = useNav();
const { pureApp, isCollapse, menuSelect, toggleSideBar } = useNav();
let subMenuData = ref([]);
@@ -62,13 +63,13 @@ watch(
<Logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="route.path"
:collapse="isCollapse"
unique-opened
router
:collapse-transition="false"
unique-opened
mode="vertical"
class="outer-most"
:collapse="isCollapse"
:default-active="route.path"
:collapse-transition="false"
@select="indexPath => menuSelect(indexPath, routers)"
>
<sidebar-item
@@ -80,5 +81,9 @@ watch(
/>
</el-menu>
</el-scrollbar>
<Hamburger
:is-active="pureApp.sidebar.opened"
@toggleClick="toggleSideBar"
/>
</div>
</template>

View File

@@ -43,7 +43,7 @@
font-size: 14px;
display: flex;
align-items: center;
color: var(--el-text-color-regular);
color: var(--el-text-color-primary);
background: #fff;
position: relative;
box-shadow: 0 0 1px #888;
@@ -92,7 +92,7 @@
a {
text-decoration: none;
color: #666;
color: var(--el-text-color-primary);
padding: 0 4px;
}
@@ -144,7 +144,7 @@
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
color: #000000d9;
color: var(--el-text-color-primary);
font-weight: normal;
font-size: 13px;
white-space: nowrap;
@@ -160,7 +160,7 @@
align-items: center;
&:hover {
background: var(--el-color-primary-light-9);
// background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
@@ -207,7 +207,7 @@
}
.scroll-item.is-active {
background-color: var(--el-color-primary-light-9);
// background-color: var(--el-color-primary-light-9);
position: relative;
color: #fff;
@@ -220,7 +220,7 @@
}
a {
color: var(--el-color-primary);
color: var(--el-color-primary) !important;
}
}
@@ -228,7 +228,7 @@
.arrow-right {
width: 40px;
height: 38px;
color: #00000073;
color: var(--el-text-color-primary);
position: relative;
svg {

View File

@@ -665,7 +665,10 @@ const getContextMenuStyle = computed((): CSSProperties => {
@mouseleave.prevent="onMouseleave(index)"
@click="tagOnClick(item)"
>
<router-link :to="item.path">
<router-link
:to="item.path"
class="!dark:color-text_color_primary !dark:hover:color-primary"
>
{{ transformI18n(item.meta.title) }}
</router-link>
<span
@@ -729,7 +732,7 @@ const getContextMenuStyle = computed((): CSSProperties => {
placement="bottom-end"
@command="handleCommand"
>
<IconifyIconOffline icon="arrow-down" />
<IconifyIconOffline icon="arrow-down" class="dark:color-white" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item