+
{{ $t('setting.forum') }}
@@ -15,17 +15,17 @@
-
-
-
- {{ isProductPro ? $t('license.pro') : $t('license.community') }}
-
-
-
{{ version }}
-
-
- ({{ $t('setting.hasNewVersion') }})
-
+
+
+ {{ isProductPro ? $t('license.pro') : $t('license.community') }}
+
+
+ {{ version }}
+
+
+
+ ({{ $t('setting.hasNewVersion') }})
+
- ({{ $t('setting.upgradeCheck') }})
+ ({{ $t('setting.upgradeCheck') }})
{{ $t('setting.upgrading') }}
@@ -201,11 +201,10 @@ onMounted(() => {
diff --git a/frontend/src/components/v-charts/components/Pie.vue b/frontend/src/components/v-charts/components/Pie.vue
index 693bc046c..145f5eb91 100644
--- a/frontend/src/components/v-charts/components/Pie.vue
+++ b/frontend/src/components/v-charts/components/Pie.vue
@@ -7,7 +7,7 @@ import * as echarts from 'echarts';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';
const globalStore = GlobalStore();
-const { isDarkGoldTheme, isDarkTheme } = storeToRefs(globalStore);
+const { isDarkTheme } = storeToRefs(globalStore);
const props = defineProps({
id: {
@@ -25,7 +25,7 @@ const props = defineProps({
option: {
type: Object,
required: true,
- }, // option: { title , data }
+ },
});
function initChart() {
@@ -34,6 +34,12 @@ function initChart() {
myChart = echarts.init(document.getElementById(props.id) as HTMLElement);
}
let percentText = String(props.option.data).split('.');
+ const primaryLight2 = getComputedStyle(document.documentElement)
+ .getPropertyValue('--panel-color-primary-light-3')
+ .trim();
+ const primaryLight1 = getComputedStyle(document.documentElement).getPropertyValue('--panel-color-primary').trim();
+ const pieBgColor = getComputedStyle(document.documentElement).getPropertyValue('--panel-pie-bg-color').trim();
+
const option = {
title: [
{
@@ -99,11 +105,11 @@ function initChart() {
new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
- color: isDarkGoldTheme.value ? '#836c4c' : 'rgba(81, 192, 255, .1)',
+ color: primaryLight2,
},
{
offset: 1,
- color: isDarkGoldTheme.value ? '#eaba63' : '#4261F6',
+ color: primaryLight1,
},
]),
],
@@ -119,7 +125,7 @@ function initChart() {
label: {
show: false,
},
- color: isDarkTheme.value ? '#16191D' : '#fff',
+ color: pieBgColor,
data: [
{
value: 0,
diff --git a/frontend/src/hooks/use-theme.ts b/frontend/src/hooks/use-theme.ts
index 5038d1014..38ab4e0c6 100644
--- a/frontend/src/hooks/use-theme.ts
+++ b/frontend/src/hooks/use-theme.ts
@@ -1,22 +1,29 @@
import { GlobalStore } from '@/store';
+import { setPrimaryColor } from '@/utils/theme';
export const useTheme = () => {
- const globalStore = GlobalStore();
const switchTheme = () => {
- if (globalStore.themeConfig.isGold && globalStore.isProductPro) {
- const body = document.documentElement as HTMLElement;
- body.setAttribute('class', 'dark-gold');
- return;
+ const globalStore = GlobalStore();
+ const themeConfig = globalStore.themeConfig;
+ let itemTheme = themeConfig.theme;
+ if (itemTheme === 'auto') {
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ itemTheme = prefersDark ? 'dark' : 'light';
}
+ document.documentElement.className = itemTheme === 'dark' ? 'dark' : 'light';
+ if (globalStore.isProductPro && themeConfig.themeColor) {
+ try {
+ const themeColor = JSON.parse(themeConfig.themeColor);
+ const color = itemTheme === 'dark' ? themeColor.dark : themeColor.light;
- let itemTheme = globalStore.themeConfig.theme;
- if (globalStore.themeConfig.theme === 'auto') {
- const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
- itemTheme = prefersDark.matches ? 'dark' : 'light';
+ if (color) {
+ themeConfig.primary = color;
+ setPrimaryColor(color);
+ }
+ } catch (e) {
+ console.error('Failed to parse themeColor', e);
+ }
}
- const body = document.documentElement as HTMLElement;
- if (itemTheme === 'dark') body.setAttribute('class', 'dark');
- else body.setAttribute('class', '');
};
return {
diff --git a/frontend/src/layout/components/AppFooter.vue b/frontend/src/layout/components/AppFooter.vue
index bf6d5825a..83ed63f08 100644
--- a/frontend/src/layout/components/AppFooter.vue
+++ b/frontend/src/layout/components/AppFooter.vue
@@ -28,8 +28,8 @@ const mobile = computed(() => {
align-items: center;
justify-content: space-between;
height: 48px;
- background: #ffffff;
- border-top: 1px solid #e4e7ed;
+ background: var(--panel-footer-bg);
+ border-top: 1px solid var(--panel-footer-border);
box-sizing: border-box;
padding: 10px 20px;
a {
diff --git a/frontend/src/layout/components/Sidebar/components/Collapse.vue b/frontend/src/layout/components/Sidebar/components/Collapse.vue
index 449762654..9050c91d7 100644
--- a/frontend/src/layout/components/Sidebar/components/Collapse.vue
+++ b/frontend/src/layout/components/Sidebar/components/Collapse.vue
@@ -18,7 +18,7 @@ const isCollapse = computed(() => menuStore.isCollapse);
display: flex;
align-items: center;
box-sizing: border-box;
- border-top: 1px solid #e4e7ed;
+ border-top: 1px solid var(--panel-footer-border);
height: 48px;
}
diff --git a/frontend/src/layout/components/Sidebar/components/Logo.vue b/frontend/src/layout/components/Sidebar/components/Logo.vue
index 34efac09b..19246a01c 100644
--- a/frontend/src/layout/components/Sidebar/components/Logo.vue
+++ b/frontend/src/layout/components/Sidebar/components/Logo.vue
@@ -37,6 +37,7 @@ const goHome = () => {
align-items: center;
justify-content: center;
height: 55px;
+ z-index: 1;
img {
object-fit: contain;
width: 95%;
diff --git a/frontend/src/layout/components/Sidebar/index.vue b/frontend/src/layout/components/Sidebar/index.vue
index cf2722c46..9ded3c4a5 100644
--- a/frontend/src/layout/components/Sidebar/index.vue
+++ b/frontend/src/layout/components/Sidebar/index.vue
@@ -6,6 +6,9 @@
element-loading-svg-view-box="-10, -10, 50, 50"
element-loading-background="rgba(122, 122, 122, 0.01)"
>
+
{
display: flex;
flex-direction: column;
height: 100%;
- background: url(@/assets/images/menu-bg.png) var(--el-menu-bg-color) no-repeat top;
+ background: var(--panel-menu-bg-color) no-repeat top;
.el-scrollbar {
flex: 1;
diff --git a/frontend/src/layout/index.vue b/frontend/src/layout/index.vue
index b8ba2c56c..f4ba5f031 100644
--- a/frontend/src/layout/index.vue
+++ b/frontend/src/layout/index.vue
@@ -137,7 +137,7 @@ onMounted(() => {
height: 100vh;
transition: margin-left 0.3s;
margin-left: var(--panel-menu-width);
- background-color: #f4f4f4;
+ background-color: var(--panel-main-bg-color-9);
overflow-x: hidden;
}
.app-main {
diff --git a/frontend/src/store/interface/index.ts b/frontend/src/store/interface/index.ts
index c27ec2337..bc114a936 100644
--- a/frontend/src/store/interface/index.ts
+++ b/frontend/src/store/interface/index.ts
@@ -4,13 +4,13 @@ export interface ThemeConfigProp {
panelName: string;
primary: string;
theme: string; // dark | bright | auto
- isGold: boolean;
footer: boolean;
title: string;
logo: string;
logoWithText: string;
favicon: string;
+ themeColor: string;
}
export interface GlobalState {
diff --git a/frontend/src/store/modules/global.ts b/frontend/src/store/modules/global.ts
index 293e665ee..a8eca34bd 100644
--- a/frontend/src/store/modules/global.ts
+++ b/frontend/src/store/modules/global.ts
@@ -14,11 +14,10 @@ const GlobalStore = defineStore({
language: '',
themeConfig: {
panelName: '',
- primary: '#005EEB',
+ primary: '#005eeb',
theme: 'auto',
- isGold: false,
footer: true,
-
+ themeColor: '',
title: '',
logo: '',
logoWithText: '',
@@ -46,9 +45,8 @@ const GlobalStore = defineStore({
getters: {
isDarkTheme: (state) =>
state.themeConfig.theme === 'dark' ||
- state.themeConfig.isGold ||
(state.themeConfig.theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches),
- isDarkGoldTheme: (state) => state.themeConfig.isGold && state.isProductPro,
+ isDarkGoldTheme: (state) => state.themeConfig.primary === '#F0BE96' && state.isProductPro,
},
actions: {
setOpenMenuTabs(openMenuTabs: boolean) {
diff --git a/frontend/src/styles/common.scss b/frontend/src/styles/common.scss
index 04ab2dcb2..fb019bda3 100644
--- a/frontend/src/styles/common.scss
+++ b/frontend/src/styles/common.scss
@@ -124,7 +124,7 @@ html {
.input-help {
font-size: 12px;
word-break: break-all;
- color: #8f959e;
+ color: #ADB0BC;
width: 100%;
display: inline-block;
}
@@ -219,7 +219,6 @@ html {
background: var(--el-button-bg-color, var(--el-fill-color-blank));
border: 0;
font-weight: 350;
- border-left: 0;
color: var(--el-button-text-color, var(--el-text-color-regular));
text-align: center;
box-sizing: border-box;
@@ -361,7 +360,7 @@ html {
.el-input-group__append {
border-left: 0;
- background-color: #ffffff !important;
+ background-color: var(--el-fill-color-light) !important;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
box-shadow: 0 1px 0 0 var(--el-input-border-color) inset, 0 -1px 0 0 var(--el-input-border-color) inset,
diff --git a/frontend/src/styles/element-dark.scss b/frontend/src/styles/element-dark.scss
index c2116f809..564eb19b9 100644
--- a/frontend/src/styles/element-dark.scss
+++ b/frontend/src/styles/element-dark.scss
@@ -1,375 +1,237 @@
html.dark {
- --el-box-shadow-light: 0px 0px 4px rgba(0, 0, 0, 0.1) !important;
- --dark-gold-base-color: #5a5a5a;
- --el-border-color-lighter: #1d2023;
- --el-fill-color-blank: #111417;
- --el-bg-color: rgba(0, 11, 21, 1);
- // --el-text-color-primary: #999999;
- --el-text-color-regular: #bbbfc4 !important;
- --el-fill-color-light: #111417;
- --el-border-color: #303438;
- --el-bg-color-overlay: rgba(0, 11, 21, 1);
- --el-border-color-light: #1d2023;
- // * menu
- --el-menu-bg-color: #111417 !important;
- --el-menu-item-bg-color: #111417;
- --el-menu-text-color: #ffffff;
- --el-menu-item-bg-color-active: rgb(44, 45, 46);
-
- // * panel-admin
- --panel-text-color: rgb(174, 166, 153);
- --panel-border: 1px solid #1d2023;
- --panel-border-color: #394c5e;
- --panel-main-bg-color: rgba(12, 12, 12, 1);
- --panel-button-active: var(--el-color-primary);
-
- --panel-login-shadow-light: 5px 5px 15px rgb(255 255 255 / 20%);
- --panel-box-shadow-light: 0 0 10px rgb(255 255 255 / 10%);
- --panel-popup-color: #060708;
- --panel-alert-bg: #2f3030;
- --panel-path-bg: #2f3030;
- --panel-button-disabled: #5a5a5a;
-
- .el-tag.el-tag--info {
- --el-tag-bg-color: rgb(49, 51, 51);
- --el-tag-border-color: rgb(64, 67, 67);
+
+ --panel-color-primary: #3D8EFF;
+ --panel-color-primary-light-8: #3674CC;
+ --panel-color-primary-light-1: #6EAAFF;
+ --panel-color-primary-light-2: #366FC2;
+ --panel-color-primary-light-3: #3364AD;
+ --panel-color-primary-light-4: #2F558F;
+ --panel-color-primary-light-5: #372E46;
+ --panel-color-primary-light-6: #2A4066;
+ --panel-color-primary-light-7: #2D4A7A;
+ --panel-color-primary-light-9: #2D4A7A;
+
+ --panel-main-bg-color-1: #E3E6F3;
+ --panel-main-bg-color-2: #C0C2CF;
+ --panel-main-bg-color-3: #ADB0BC;
+ --panel-main-bg-color-4: #9597A4;
+ --panel-main-bg-color-5: #90929F;
+ --panel-main-bg-color-6: #787B88;
+ --panel-main-bg-color-7: #5B5E6A;
+ --panel-main-bg-color-8: #434552;
+ --panel-main-bg-color-9: #2E313D;
+ --panel-main-bg-color-10: #242633;
+ --panel-main-bg-color-11: #60626F;
+
+ --panel-alert-error-bg-color: #54293A;
+ --panel-alert-error-text-color: #B22F48;
+ --panel-alert-error-hover-bg-color: #672A3D;
+
+ --panel-alert-success-bg-color: #1E5146;
+ --panel-alert-success-text-color: #169262;
+ --panel-alert-success-hover-bg-color: #1D5849;
+
+ --panel-alert-warning-bg-color: #59472A;
+ --panel-alert-warning-text-color: #BB8A2E;
+ --panel-alert-warning-hover-bg-color: #6A5531;
+
+ --panel-alert-info-bg-color: var(--panel-main-bg-color-6);
+ --panel-alert-info-text-color: var(--panel-main-bg-color-3);
+ --panel-alert-info-hover-bg-color: var(--panel-main-bg-color-4);
+
+ --panel-pie-bg-color: #434552;
+ --panel-text-color-white: #ffffff;
+
+
+ --el-color-primary: var(--panel-color-primary);
+ --el-color-primary-light-3: var(--panel-color-primary-light-3);
+ --el-color-primary-light-5: var(--panel-color-primary-light-5);
+ --el-color-primary-light-7: var(--panel-color-primary-light-7);
+ --el-color-primary-light-8: var(--panel-color-primary-light-8);
+ --el-color-primary-light-9: var(--panel-color-primary-light-9);
+
+
+ --panel-border: 2px solid var(--panel-main-bg-color-8);
+ --panel-button-active: var(--panel-main-bg-color-10);
+ --panel-button-text-color: var(--panel-main-bg-color-10);
+ --panel-button-bg-color: var(--panel-color-primary);
+ --panel-footer-bg: var(--panel-main-bg-color-9);
+ --panel-footer-border: var(--panel-main-bg-color-7);
+ --panel-text-color: var(--panel-main-bg-color-1);
+ --panel-menu-bg-color: var(--panel-main-bg-color-10);
+ --panel-terminal-tag-bg-color: var(--panel-main-bg-color-10);
+
+ --el-menu-item-bg-color: var(--panel-main-bg-color-10);
+ --el-menu-item-bg-color-active: var(--panel-main-bg-color-8);
+ --el-menu-hover-bg-color: var(--panel-main-bg-color-8);
+ --el-menu-text-color: var(--panel-main-bg-color-2);
+ --el-fill-color-blank: var(--panel-main-bg-color-10);
+ --el-fill-color-light: var(--panel-main-bg-color-10);
+ --el-border-color: var(--panel-main-bg-color-8);
+ --el-border-color-light: var(--panel-main-bg-color-8);
+ --el-border-color-lighter: var(--panel-main-bg-color-8);
+
+ --el-text-color-primary: var(--panel-main-bg-color-2);
+ --el-text-color-regular: var(--panel-main-bg-color-2);
+
+ --el-box-shadow: 0px 12px 32px 4px rgba(36, 38, 51, .36), 0px 8px 20px rgba(36, 38, 51, .72);
+ --el-box-shadow-light: 0px 0px 12px rgba(36, 38, 51, .72);
+ --el-box-shadow-lighter: 0px 0px 6px rgba(36, 38, 51, .72);
+ --el-box-shadow-dark: 0px 16px 48px 16px rgba(36, 38, 51, .72), 0px 12px 32px #242633, 0px 8px 16px -8px #242633;
+ --el-bg-color: var(--panel-main-bg-color-9);
+ --el-bg-color-overlay: var(--panel-main-bg-color-9);
+
+ --el-text-color-placeholder: var(--panel-main-bg-color-4);
+
+ .el-descriptions__content:not(.is-bordered-label) {
+ color: var(--panel-main-bg-color-3);
}
- .el-tag.el-tag--light {
- --el-tag-bg-color: #111417;
- --el-tag-border-color: var(--el-color-primary);
+
+ .el-menu-item:hover, .el-sub-menu__title:hover{
+ background: var(--panel-main-bg-color-8) !important;
}
- .el-tag.el-tag--success {
- --el-tag-border-color: var(--el-color-success);
+
+ .el-menu .el-menu-item {
+ box-shadow: 0 0 4px rgba(36, 38, 51, .72);
}
- .el-tag.el-tag--danger {
- --el-tag-border-color: var(--el-color-danger);
+
+ .el-menu .el-sub-menu__title {
+ box-shadow: 0 0 4px rgba(36, 38, 51, .72);
}
- .el-card {
- --el-card-bg-color: rgb(35, 35, 35);
- color: #ffffff;
- border: 1px solid var(--el-card-border-color) !important;
+
+ .el-overlay {
+ background-color: #2E313D90;
}
- .el-table {
- --el-table-bg-color: rgba(0, 11, 21, 1);
- --el-table-tr-bg-color: rgba(0, 11, 21, 1);
- --el-table-header-bg-color: rgba(0, 11, 21, 1);
- --el-table-border: var(--panel-border);
- --el-table-border-color: rgb(64, 67, 67);
+ .el-tag.el-tag--primary {
+ --el-tag-bg-color: var(--panel-main-bg-color-9);
+ --el-tag-border-color: var(--panel-color-primary-light-8);
+ --el-tag-hover-color: var(--panel-color-primary);
}
- .el-message-box {
- --el-messagebox-title-color: var(--el-menu-text-color);
- border: 1px solid var(--panel-border-color);
+
+ .el-tabs--card > .el-tabs__header .el-tabs__nav {
+ border: 1px solid var(--panel-main-bg-color-8);
}
- .el-alert--info {
- --el-alert-bg-color: rgb(56, 59, 59);
+ .el-tabs--card > .el-tabs__header .el-tabs__item.is-active {
+ border-bottom-color: var(--panel-color-primary);
+ --el-text-color-regular: var(--panel-color-primary);
+ }
+
+ .el-loading-mask {
+ background-color:var(--panel-main-bg-color-10);
}
.el-input {
- --el-input-bg-color: rgb(47 48 48);
- --el-input-border-color: #303438;
+ --el-input-border-color: var(--panel-main-bg-color-8);
}
- .el-pagination {
- --el-pagination-button-color: #999999;
+ input:-webkit-autofill {
+ box-shadow: 0 0 0 1000px var(--el-box-shadow) inset;
+ background-color: var(--panel-main-bg-color-1);
+ transition: background-color 1000s ease-out 0.5s;
}
- .el-popover {
- --el-popover-title-text-color: #999999;
- border: 1px solid var(--panel-border-color);
+ .el-input.is-disabled .el-input__wrapper {
+ --el-disabled-bg-color: var(--panel-main-bg-color-9);
+ --el-disabled-border-color: var(--panel-main-bg-color-8);
}
- .md-editor-dark {
- --md-bk-color: #111417;
+ .el-input > .el-input-group__append:hover {
+ background-color: var(--panel-main-bg-color-9) !important;
}
- // * 以下为自定义暗黑模式内容
- // login
- .login-container {
- .login-form {
- input:-webkit-autofill {
- box-shadow: 0 0 0 1000px #f1f4f9 inset;
- -webkit-text-fill-color: #333333;
- -webkit-transition: background-color 1000s ease-out 0.5s;
- transition: background-color 1000s ease-out 0.5s;
- }
- .el-input__wrapper {
- background-color: #ffffff;
- box-shadow: 0 0 0 1px #dcdfe6 inset;
- }
- .el-input__inner {
- color: #606266;
- }
- }
+ .el-form-item__label {
+ color: var(--panel-main-bg-color-3);
}
- // scroll-bar
- ::-webkit-scrollbar {
- background-color: var(--el-scrollbar-bg-color) !important;
+ .el-card {
+ --el-card-bg-color: var(--panel-main-bg-color-10)
}
- ::-webkit-scrollbar-thumb {
- background-color: var(--el-border-color-darker);
+
+ .el-button--primary {
+ --el-button-hover-link-text-color: var(--panel-color-primary-light-1);
}
- // sidebar
- .sidebar-container-popper {
- border: 1px solid #66686c;
- .el-menu--popup-container {
- border: none;
- }
+
+ .el-button--primary.is-plain, .el-button--primary.is-text, .el-button--primary.is-link {
+ --el-button-bg-color: var(--panel-main-bg-color-9);
+ --el-button-border-color: var(--panel-main-bg-color-8);
+ --el-button-hover-bg-color: var(--panel-main-bg-color-9);
+ --el-button-hover-border-color: var(--panel-main-bg-color-8);
}
- .sidebar-container {
- border-right: 1px solid var(--el-border-color-light);
+
+ .el-button:hover {
+ --el-button-hover-text-color: var(--panel-text-color-white);
+ --el-button-border-color: var(--el-color-primary-light-3);
+ --el-button-hover-bg-color: var(--el-color-primary-light-3);
+ --el-button-hover-border-color: var(--el-color-primary-light-3);
}
- .el-menu {
- .el-menu-item {
- &:hover {
- background: rgba(37, 39, 44, 1);
- }
- &.is-active {
- background: var(--el-color-primary);
- color: #ffffff;
- &:hover {
- .el-icon {
- color: #ffffff !important;
- }
-
- span {
- color: #ffffff !important;
- }
- }
- &::before {
- background: #ffffff;
- }
- }
- }
- .el-sub-menu {
- .el-sub-menu__title {
- &:hover {
- background: rgba(37, 39, 44, 1);
- }
- }
- }
+
+ .el-button:active {
+ --el-button-hover-text-color: var(--panel-text-color-white);
+ --el-button-active-bg-color: var(--el-color-primary-light-3);
+ --el-button-active-border-color: var(--el-color-primary-light-3);
}
- .menu-collapse {
- color: var(--el-menu-text-color);
- border: var(--panel-border);
+
+ .el-button:focus-visible {
+ outline: none;
}
- // layout
- .app-wrapper {
- .main-container {
- background-color: var(--panel-main-bg-color) !important;
- }
- .app-footer {
- background-color: var(--panel-main-bg-color) !important;
- border-top: var(--panel-border);
- }
- .mobile-header {
- background-color: var(--panel-main-bg-color) !important;
- border-bottom: var(--panel-border);
- color: #ffffff;
- }
+ .el-button.is-disabled {
+ color: var(--panel-main-bg-color-7);
+ border-color: var(--panel-main-bg-color-8);
+ background: var(--panel-main-bg-color-9);
}
- .system-label {
- color: var(--el-menu-text-color);
+
+ .el-button.is-disabled:hover {
+ border-color: var(--panel-main-bg-color-8);
+ background: var(--panel-main-bg-color-9);
}
- .router_card_button {
- .el-radio-button__inner {
- background: none !important;
- }
- .el-radio-button__original-radio:checked + .el-radio-button__inner {
- color: #ffffff;
- background-color: var(--panel-button-active) !important;
- box-shadow: none !important;
- border: none !important;
- }
+ .el-button--primary.is-link.is-disabled {
+ color: var(--panel-main-bg-color-8);
}
- // content-box
- .content-box {
- .text {
- color: var(--el-text-color-regular) !important;
- }
+
+ .el-dropdown-menu__item:hover {
+ background-color: var(--panel-main-bg-color-7);
}
.el-drawer .el-drawer__header span {
color: var(--el-menu-text-color);
}
- .el-drawer {
- border-left: 0.5px solid var(--panel-border-color);
- }
- .el-input__wrapper {
- background-color: var(--el-disabled-bg-color);
- }
- .el-input.is-disabled .el-input__wrapper {
- box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
- }
- .el-radio-button__inner {
- background: #1d2023;
- }
- .el-button--primary.is-plain.is-disabled {
- background: #1d2023;
- border-color: #303438;
- }
- .el-button--primary.is-plain {
- background: #1d2023;
- border-color: #303438;
- }
- .el-button.is-link.is-disabled {
- color: var(--panel-button-disabled) !important;
- }
- .el-button.is-disabled {
- border-color: #303438;
- color: var(--panel-button-disabled);
- }
- .el-popper.is-dark {
- color: rgb(171 173 173);
- }
- .path {
- border: var(--panel-border);
- .split {
- color: #666666;
- }
- }
- input:-webkit-autofill {
- box-shadow: 0 0 0 1000px #323232 inset;
- -webkit-text-fill-color: #cfd3dc;
- transition: background-color 1000s ease-out 0.5s;
- }
- .el-avatar {
- --el-avatar-bg-color: #111417 !important;
- box-shadow: 0px 0px 4px rgba(0, 94, 235, 0.1);
- border: 0.5px solid #1f2022;
- }
- .el-page-header__content {
- color: rgb(174, 166, 153);
- }
.el-dialog {
+ background-color: var(--panel-main-bg-color-8);
border: 1px solid var(--panel-border-color);
.el-dialog__header {
border-bottom: var(--panel-border);
- color: #999999;
+ color: var(--el-text-color-primary);
.el-dialog__title {
color: var(--el-menu-text-color);
}
}
}
- .el-tabs__item {
- color: #999999;
- }
- .el-tabs__item.is-active {
- color: var(--el-color-primary) !important;
- }
- .el-descriptions__title {
- color: #999999;
- }
- .el-descriptions__content.el-descriptions__cell.is-bordered-content {
- color: #999999;
- }
- .el-descriptions--large .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell {
- padding: 12px 15px;
- background-color: transparent;
- }
- .el-descriptions__body {
- background-color: transparent;
- }
- .el-descriptions__label {
- color: var(--el-color-primary) !important;
- margin-right: 16px;
- }
-
- .terminal-tabs {
- background: none !important;
- .el-tabs__header {
- background: #000000;
- }
- }
- .el-pager {
- li {
- color: #999999;
- &.is-active {
- color: var(--el-pagination-hover-color);
- }
- }
- }
- .el-loading-mask {
- background-color: rgba(0, 0, 0, 0.8);
- }
- .h-app-card {
- .h-app-content {
- .h-app-title {
- color: #f2f8ff;
- }
- }
+ .el-alert--error {
+ --el-alert-bg-color: var(--panel-alert-error-bg-color);
+ --el-color-error: var(--panel-alert-error-text-color);
}
- .infinite-list .infinite-list-item {
- background: #212426;
- &:hover {
- background: #212426;
- }
+ .el-alert--success {
+ --el-alert-bg-color: var(--panel-alert-success-bg-color);
+ --el-color-success: var(--panel-alert-success-text-color);;
}
- .el-alert--warning.is-light {
- background-color: rgb(56, 59, 59);
- color: var(--el-color-warning);
- }
- .el-dropdown-menu__item.is-disabled {
- color: var(--panel-button-disabled);
- }
- .el-date-editor .el-range-separator {
- color: var(--panel-button-disabled);
+ .el-alert--warning {
+ --el-alert-bg-color: var(--panel-alert-warning-bg-color);
+ --el-color-warning: var(--panel-alert-warning-text-color);
}
- .el-input-group__append {
- border-left: 0;
- background-color: #212426 !important;
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
- box-shadow: 0 1px 0 0 var(--el-input-border-color) inset, 0 -1px 0 0 var(--el-input-border-color) inset,
- -1px 0 0 0 var(--el-input-border-color) inset;
-
- &:hover {
- color: var(--el-color-primary);
- background-color: var(--el-color-primary-light-9) !important;
- }
- }
-
- .el-collapse-item__header {
- color: #ffffff;
- }
-
- .file-item:hover {
- background-color: #4f4f4f;
+ .el-alert--info {
+ --el-alert-bg-color: var(--panel-alert-info-bg-color);
+ --el-color-info: var(--panel-alert-info-text-color);
}
- .level-up-pro {
- --dark-gold-base-color: #eaba63;
- --dark-gold-text-color: #1f2329;
- --el-color-primary: var(--dark-gold-base-color);
-
- .title {
- color: var(--dark-gold-base-color);
- }
- .el-button--primary {
- &.is-plain {
- background: var(--dark-gold-base-color);
- --el-button-text-color: var(--dark-gold-text-color);
-
- &.is-disabled {
- background: #1d2023;
- border-color: #303438;
- }
- }
-
- &.is-text {
- --el-button-text-color: var(--dark-gold-base-color);
- }
- }
- }
-}
+}
\ No newline at end of file
diff --git a/frontend/src/styles/element.scss b/frontend/src/styles/element.scss
index 9522215d9..83f8fb409 100644
--- a/frontend/src/styles/element.scss
+++ b/frontend/src/styles/element.scss
@@ -1,33 +1,56 @@
:root {
- --el-color-primary: #005eeb;
- --el-color-primary-dark-2: #0054d3;
+ --panel-gradient-end-color: var(--el-color-primary-light-7);
+
--el-color-primary-light-1: #196eed;
--el-color-primary-light-2: #337eef;
- --el-color-primary-light-3: #4c8ef1;
--el-color-primary-light-4: #669ef3;
- --el-color-primary-light-5: #7faef5;
--el-color-primary-light-6: #99bef7;
- --el-color-primary-light-7: #b2cef9;
- --el-color-primary-light-8: #ccdefb;
- --el-color-primary-light-9: #e5eefd;
+
+ --panel-color-primary: #005eeb;
+ --panel-color-primary-light-8: #196eed;
+ --panel-color-primary-light-1: #196eed;
+ --panel-color-primary-light-2: #337eef;
+ --panel-color-primary-light-3: #4c8ef1;
+ --panel-color-primary-light-4: #669ef3;
+ --panel-color-primary-light-5: #7faef5;
+ --panel-color-primary-light-6: #99bef7;
+ --panel-color-primary-light-7: #b2cef9;
+ --panel-color-primary-light-9: #e5eefd;
+
+ --el-color-primary: var(--panel-color-primary);
+ --el-color-primary-light-3: var(--panel-color-primary-light-1);
+ --el-color-primary-light-5: var(--panel-color-primary-light-5);
+ --el-color-primary-light-7: var(--panel-color-primary-light-7);
+ --el-color-primary-light-8: var(--panel-color-primary-light-8);
+ --el-color-primary-light-9: var(--panel-color-primary-light-9);
+
+ --el-text-color-regular: #646a73;
}
html {
--el-box-shadow-light: 0px 0px 4px rgba(0, 94, 235, 0.1) !important;
- --el-text-color-regular: #646a73 !important;
// * menu
- --el-menu-bg-color: rgba(0, 94, 235, 0.1) !important;
--el-menu-item-bg-color: rgba(255, 255, 255, 0.3);
--el-menu-item-bg-color-active: #ffffff;
+ --panel-main-bg-color-9: #f4f4f4;
+ --panel-menu-bg-color: rgba(0, 94, 235, 0.1);
--panel-menu-width: 180px;
--panel-menu-hide-width: 75px;
--panel-text-color: #1f2329;
--panel-border: 1px solid #f2f2f2;
--panel-button-active: #ffffff;
+ --panel-button-text-color: var(--panel-color-primary);
+ --panel-button-bg-color: #ffffff;
+ --panel-footer-border: #e4e7ed;
+ --panel-terminal-tag-bg-color: #efefef;
--panel-alert-bg: #e2e4ec;
--panel-path-bg: #ffffff;
+ --panel-footer-bg: #ffffff;
+ --panel-pie-bg-color: #ffffff;
+
+ --el-fill-color-light: #ffffff;
}
.el-notification {
diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts
new file mode 100644
index 000000000..128191cba
--- /dev/null
+++ b/frontend/src/utils/theme.ts
@@ -0,0 +1,8 @@
+export function setPrimaryColor(color: string) {
+ let setPrimaryColor: (arg0: string) => any;
+ const xpackModules = import.meta.glob('../xpack/utils/theme/tool.ts', { eager: true });
+ if (xpackModules['../xpack/utils/theme/tool.ts']) {
+ setPrimaryColor = xpackModules['../xpack/utils/theme/tool.ts']['setPrimaryColor'] || {};
+ return setPrimaryColor(color);
+ }
+}
diff --git a/frontend/src/utils/theme/tool.ts b/frontend/src/utils/theme/tool.ts
deleted file mode 100644
index e8ad0627d..000000000
--- a/frontend/src/utils/theme/tool.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { MsgWarning } from '../message';
-
-/**
- * hex颜色转rgb颜色
- * @param str 颜色值字符串
- * @returns 返回处理后的颜色值
- */
-export function hexToRgb(str: any) {
- let hexs: any = '';
- let reg = /^\#?[0-9A-Fa-f]{6}$/;
- if (!reg.test(str)) return MsgWarning('输入错误的hex');
- str = str.replace('#', '');
- hexs = str.match(/../g);
- for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
- return hexs;
-}
-
-/**
- * rgb颜色转Hex颜色
- * @param r 代表红色
- * @param g 代表绿色
- * @param b 代表蓝色
- * @returns 返回处理后的颜色值
- */
-export function rgbToHex(r: any, g: any, b: any) {
- let reg = /^\d{1,3}$/;
- if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return MsgWarning('输入错误的rgb颜色值');
- let hexs = [r.toString(16), g.toString(16), b.toString(16)];
- for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
- return `#${hexs.join('')}`;
-}
-
-/**
- * 加深颜色值
- * @param color 颜色值字符串
- * @param level 加深的程度,限0-1之间
- * @returns 返回处理后的颜色值
- */
-export function getDarkColor(color: string, level: number) {
- let reg = /^\#?[0-9A-Fa-f]{6}$/;
- if (!reg.test(color)) return MsgWarning('输入错误的hex颜色值');
- let rgb = hexToRgb(color);
- for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level));
- return rgbToHex(rgb[0], rgb[1], rgb[2]);
-}
-
-/**
- * 变浅颜色值
- * @param color 颜色值字符串
- * @param level 加深的程度,限0-1之间
- * @returns 返回处理后的颜色值
- */
-export function getLightColor(color: string, level: number) {
- let reg = /^\#?[0-9A-Fa-f]{6}$/;
- if (!reg.test(color)) return MsgWarning('输入错误的hex颜色值');
- let rgb = hexToRgb(color);
- for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
- return rgbToHex(rgb[0], rgb[1], rgb[2]);
-}
diff --git a/frontend/src/utils/xpack.ts b/frontend/src/utils/xpack.ts
index 5e3e0e732..1fe395c49 100644
--- a/frontend/src/utils/xpack.ts
+++ b/frontend/src/utils/xpack.ts
@@ -9,7 +9,6 @@ export function resetXSetting() {
globalStore.themeConfig.logo = '';
globalStore.themeConfig.logoWithText = '';
globalStore.themeConfig.favicon = '';
- globalStore.themeConfig.isGold = false;
}
export function initFavicon() {
@@ -18,13 +17,26 @@ export function initFavicon() {
const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement;
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
- if (globalStore.isDarkGoldTheme) {
- let goldLink = new URL(`../assets/images/favicon-gold.png`, import.meta.url).href;
+ let goldLink = new URL(`../assets/images/favicon.svg`, import.meta.url).href;
+ if (globalStore.isProductPro) {
+ const themeColor = globalStore.themeConfig.primary;
+ const svg = `
+
+ `;
+ goldLink = `data:image/svg+xml,${encodeURIComponent(svg)}`;
link.href = favicon ? '/api/v1/images/favicon' : goldLink;
} else {
link.href = favicon ? '/api/v1/images/favicon' : '/public/favicon.png';
}
- document.getElementsByTagName('head')[0].appendChild(link);
+ document.head.appendChild(link);
}
export async function getXpackSetting() {
@@ -102,7 +114,7 @@ export async function getXpackSettingForTheme() {
globalStore.themeConfig.logo = res2.data?.logo;
globalStore.themeConfig.logoWithText = res2.data?.logoWithText;
globalStore.themeConfig.favicon = res2.data?.favicon;
- globalStore.themeConfig.isGold = res2.data?.theme === 'dark-gold';
+ globalStore.themeConfig.themeColor = res2.data?.themeColor;
} else {
resetXSetting();
}
diff --git a/frontend/src/views/home/app/index.vue b/frontend/src/views/home/app/index.vue
index 1d570d808..e7eccf217 100644
--- a/frontend/src/views/home/app/index.vue
+++ b/frontend/src/views/home/app/index.vue
@@ -105,7 +105,7 @@ defineExpose({
.h-app-title {
font-weight: 500;
font-size: 15px;
- color: #1f2329;
+ color: var(--panel-text-color);
}
.h-app-desc {
diff --git a/frontend/src/views/host/terminal/terminal/index.vue b/frontend/src/views/host/terminal/terminal/index.vue
index 2a312ca07..32ee4e78b 100644
--- a/frontend/src/views/host/terminal/terminal/index.vue
+++ b/frontend/src/views/host/terminal/terminal/index.vue
@@ -3,7 +3,7 @@
{
height: 45px;
margin-top: 10px;
background-color: #005eeb;
+ border-color: #005eeb;
color: #ffffff;
+ &:hover {
+ --el-button-hover-border-color: #005eeb;
+ }
}
.demo {
@@ -503,6 +507,13 @@ onMounted(() => {
color: #005eeb;
}
+ :deep(a) {
+ color: #005eeb;
+ &:hover {
+ color: #005eeb95;
+ }
+ }
+
:deep(.el-checkbox__input .el-checkbox__inner) {
background-color: #fff !important;
border-color: #fff !important;
@@ -523,4 +534,24 @@ onMounted(() => {
margin-left: 20px;
}
}
+.cursor-pointer {
+ outline: none;
+}
+
+.el-dropdown:focus-visible {
+ outline: none;
+}
+
+.el-tooltip__trigger:focus-visible {
+ outline: none;
+}
+
+:deep(.el-dropdown-menu__item:not(.is-disabled):hover) {
+ color: #005eeb !important;
+ background-color: #e5eefd !important;
+}
+:deep(.el-dropdown-menu__item:not(.is-disabled):focus) {
+ color: #005eeb !important;
+ background-color: #e5eefd !important;
+}
diff --git a/frontend/src/views/setting/license/index.vue b/frontend/src/views/setting/license/index.vue
index 944ae9c0e..c2d261fad 100644
--- a/frontend/src/views/setting/license/index.vue
+++ b/frontend/src/views/setting/license/index.vue
@@ -2,7 +2,7 @@
-
+
@@ -123,6 +123,7 @@ import LicenseImport from '@/components/license-import/index.vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store';
+import { initFavicon } from '@/utils/xpack';
const loading = ref();
const licenseRef = ref();
const globalStore = GlobalStore();
@@ -168,7 +169,7 @@ const onUnBind = async () => {
.then(() => {
loading.value = false;
globalStore.isProductPro = false;
- globalStore.themeConfig.isGold = false;
+ initFavicon();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
window.location.reload();
})
@@ -251,6 +252,9 @@ onMounted(() => {
background-color: rgba(0, 94, 235, 0.03);
}
}
+:deep(.license-card .el-card) {
+ border: var(--panel-border) !important;
+}
:deep(.el-descriptions__content) {
max-width: 300px;
}
diff --git a/frontend/src/views/setting/panel/index.vue b/frontend/src/views/setting/panel/index.vue
index a4ad8f896..c77cd8baf 100644
--- a/frontend/src/views/setting/panel/index.vue
+++ b/frontend/src/views/setting/panel/index.vue
@@ -27,20 +27,27 @@
-
-
- {{ $t('setting.darkGold') }}
-
-
- {{ $t('setting.light') }}
-
-
- {{ $t('setting.dark') }}
-
-
- {{ $t('setting.auto') }}
-
-
+
+
+
+ {{ $t('setting.light') }}
+
+
+ {{ $t('setting.dark') }}
+
+
+ {{ $t('setting.auto') }}
+
+
+
+ {{ $t('container.custom') }}
+
+
@@ -164,6 +171,7 @@
+
@@ -183,8 +191,10 @@ import SystemIP from '@/views/setting/panel/systemip/index.vue';
import Proxy from '@/views/setting/panel/proxy/index.vue';
import Network from '@/views/setting/panel/default-network/index.vue';
import HideMenu from '@/views/setting/panel/hidemenu/index.vue';
+import ThemeColor from '@/views/setting/panel/theme-color/index.vue';
import { storeToRefs } from 'pinia';
import { getXpackSetting, updateXpackSettingByKey } from '@/utils/xpack';
+import { setPrimaryColor } from '@/utils/theme';
const loading = ref(false);
const i18n = useI18n();
@@ -198,6 +208,11 @@ const mobile = computed(() => {
return globalStore.isMobile();
});
+interface ThemeColor {
+ light: string;
+ dark: string;
+}
+
const form = reactive({
userName: '',
password: '',
@@ -209,6 +224,7 @@ const form = reactive({
panelName: '',
systemIP: '',
theme: '',
+ themeColor: {} as ThemeColor,
menuTabs: '',
language: '',
complexityVerification: '',
@@ -238,6 +254,7 @@ const proxyRef = ref();
const timeoutRef = ref();
const networkRef = ref();
const hideMenuRef = ref();
+const themeColorRef = ref();
const unset = ref(i18n.t('setting.unSetting'));
interface Node {
@@ -279,15 +296,16 @@ const search = async () => {
const json: Node = JSON.parse(res.data.xpackHideMenu);
const checkedTitles = getCheckedTitles(json);
form.proHideMenus = checkedTitles.toString();
-
if (isProductPro.value) {
const xpackRes = await getXpackSetting();
if (xpackRes) {
- form.theme = xpackRes.data.theme === 'dark-gold' ? 'dark-gold' : res.data.theme;
- return;
+ form.theme = xpackRes.data.theme || globalStore.themeConfig.theme;
+ form.themeColor = JSON.parse(xpackRes.data.themeColor);
+ globalStore.themeConfig.themeColor = xpackRes.data.themeColor;
}
+ } else {
+ form.theme = res.data.theme;
}
- form.theme = res.data.theme;
};
function extractTitles(node: Node, result: string[]): void {
@@ -347,6 +365,11 @@ const onChangeHideMenus = () => {
hideMenuRef.value.acceptParams({ menuList: form.hideMenuList });
};
+const onChangeThemeColor = () => {
+ const themeColor: ThemeColor = JSON.parse(globalStore.themeConfig.themeColor);
+ themeColorRef.value.acceptParams({ themeColor: themeColor, theme: globalStore.themeConfig.theme });
+};
+
const onSave = async (key: string, val: any) => {
loading.value = true;
if (key === 'Language') {
@@ -354,21 +377,24 @@ const onSave = async (key: string, val: any) => {
globalStore.updateLanguage(val);
}
if (key === 'Theme') {
- if (val === 'dark-gold') {
- globalStore.themeConfig.isGold = true;
- } else {
- globalStore.themeConfig.isGold = false;
- globalStore.themeConfig.theme = val;
- }
+ globalStore.themeConfig.theme = val;
switchTheme();
if (globalStore.isProductPro) {
- updateXpackSettingByKey('Theme', val === 'dark-gold' ? 'dark-gold' : '');
- if (val === 'dark-gold') {
- MsgSuccess(i18n.t('commons.msg.operationSuccess'));
- loading.value = false;
- search();
- return;
+ await updateXpackSettingByKey('Theme', val);
+ let color: string;
+ const themeColor: ThemeColor = JSON.parse(globalStore.themeConfig.themeColor);
+ if (val === 'auto') {
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
+ color = prefersDark.matches ? themeColor.dark : themeColor.light;
+ } else {
+ color = val === 'dark' ? themeColor.dark : themeColor.light;
}
+ globalStore.themeConfig.primary = color;
+ setPrimaryColor(color);
+ MsgSuccess(i18n.t('commons.msg.operationSuccess'));
+ loading.value = false;
+ await search();
+ return;
}
}
if (key === 'MenuTabs') {
@@ -385,7 +411,7 @@ const onSave = async (key: string, val: any) => {
}
loading.value = false;
MsgSuccess(i18n.t('commons.msg.operationSuccess'));
- search();
+ await search();
})
.catch(() => {
loading.value = false;
diff --git a/frontend/src/views/setting/panel/theme-color/index.vue b/frontend/src/views/setting/panel/theme-color/index.vue
new file mode 100644
index 000000000..a6b735ce7
--- /dev/null
+++ b/frontend/src/views/setting/panel/theme-color/index.vue
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+