feat: add state grid open app themes
This commit is contained in:
@@ -20,6 +20,10 @@ import { FIRST_MENU_WIDTH_STYLE2 } from './layout.constants';
|
|||||||
* 定义可选择的主题色选项
|
* 定义可选择的主题色选项
|
||||||
*/
|
*/
|
||||||
export const THEME_COLOR_CONFIGS = [
|
export const THEME_COLOR_CONFIGS = [
|
||||||
|
{
|
||||||
|
color: '#006569',
|
||||||
|
name: '国网绿',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
color: '#5147ff',
|
color: '#5147ff',
|
||||||
name: dict('PC.Constants.Theme.colorBlue'),
|
name: dict('PC.Constants.Theme.colorBlue'),
|
||||||
|
|||||||
@@ -5,38 +5,37 @@
|
|||||||
padding: @paddingXs;
|
padding: @paddingXs;
|
||||||
margin-top: @marginXxs;
|
margin-top: @marginXxs;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: @navSecondMenuTextSecondary;
|
color: var(--open-app-sidebar-text-secondary, @navSecondMenuTextSecondary);
|
||||||
|
border-radius: @borderRadius;
|
||||||
|
transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
&.first {
|
&.first {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
color: @navSecondMenuTextSecondary;
|
color: var(--open-app-sidebar-text-secondary, @navSecondMenuTextSecondary);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: @fontSize;
|
font-size: @fontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: rgba(0, 0, 0, 5%);
|
background-color: var(--open-app-sidebar-active-bg, rgba(0, 0, 0, 5%));
|
||||||
color: rgba(0, 0, 0, 90%);
|
color: var(--open-app-sidebar-active-text, rgba(0, 0, 0, 90%));
|
||||||
border-radius: @borderRadius;
|
box-shadow: var(--open-app-sidebar-control-shadow, @boxShadowTertiary);
|
||||||
box-shadow: @boxShadowTertiary;
|
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
color: rgba(0, 0, 0, 90%);
|
color: var(--open-app-sidebar-active-text, rgba(0, 0, 0, 90%));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.active) {
|
&:hover:not(.active) {
|
||||||
background-color: rgba(0, 0, 0, 5%);
|
background-color: var(--open-app-sidebar-hover, rgba(0, 0, 0, 5%));
|
||||||
border-radius: @borderRadius;
|
color: var(--open-app-sidebar-text, @colorTextSecondary);
|
||||||
box-shadow: @boxShadowTertiary;
|
|
||||||
color: @colorTextSecondary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
font-size: @fontSizeSm;
|
font-size: @fontSizeSm;
|
||||||
color: @colorTextTertiary;
|
color: var(--open-app-sidebar-muted, @colorTextTertiary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,83 @@
|
|||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
--open-app-sidebar-bg: #ffffff;
|
||||||
|
--open-app-sidebar-border: rgba(0, 101, 105, 12%);
|
||||||
|
--open-app-sidebar-text: #183638;
|
||||||
|
--open-app-sidebar-text-secondary: rgba(24, 54, 56, 68%);
|
||||||
|
--open-app-sidebar-muted: rgba(24, 54, 56, 52%);
|
||||||
|
--open-app-sidebar-hover: rgba(0, 101, 105, 8%);
|
||||||
|
--open-app-sidebar-active-bg: rgba(0, 101, 105, 12%);
|
||||||
|
--open-app-sidebar-active-text: #006569;
|
||||||
|
--open-app-sidebar-accent: #006569;
|
||||||
|
--open-app-sidebar-accent-2: #00a67a;
|
||||||
|
--open-app-sidebar-control-bg: #ffffff;
|
||||||
|
--open-app-sidebar-control-border: rgba(0, 101, 105, 20%);
|
||||||
|
--open-app-sidebar-control-shadow: 0 8px 24px rgba(0, 101, 105, 10%);
|
||||||
|
--open-app-sidebar-footer-bg: rgba(0, 101, 105, 6%);
|
||||||
|
--open-app-sidebar-gradient-end: #ffffff;
|
||||||
|
--open-app-theme-switch-bg: rgba(0, 101, 105, 8%);
|
||||||
|
--open-app-theme-switch-active-bg: #006569;
|
||||||
|
--open-app-theme-switch-active-text: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light {
|
||||||
|
--open-app-sidebar-bg: #fbfffd;
|
||||||
|
--open-app-sidebar-border: rgba(0, 101, 105, 16%);
|
||||||
|
--open-app-sidebar-text: #183638;
|
||||||
|
--open-app-sidebar-text-secondary: rgba(24, 54, 56, 68%);
|
||||||
|
--open-app-sidebar-muted: rgba(24, 54, 56, 52%);
|
||||||
|
--open-app-sidebar-hover: rgba(0, 101, 105, 8%);
|
||||||
|
--open-app-sidebar-active-bg: rgba(0, 101, 105, 12%);
|
||||||
|
--open-app-sidebar-active-text: #006569;
|
||||||
|
--open-app-sidebar-control-bg: #ffffff;
|
||||||
|
--open-app-sidebar-control-border: rgba(0, 101, 105, 22%);
|
||||||
|
--open-app-sidebar-control-shadow: 0 10px 26px rgba(0, 101, 105, 9%);
|
||||||
|
--open-app-sidebar-footer-bg: rgba(0, 101, 105, 6%);
|
||||||
|
--open-app-sidebar-gradient-end: #fbfffd;
|
||||||
|
--open-app-theme-switch-bg: rgba(0, 101, 105, 8%);
|
||||||
|
--open-app-theme-switch-active-bg: #006569;
|
||||||
|
--open-app-theme-switch-active-text: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-dispatch {
|
||||||
|
--open-app-sidebar-bg: #003f42;
|
||||||
|
--open-app-sidebar-border: rgba(128, 236, 208, 26%);
|
||||||
|
--open-app-sidebar-text: #f2fffc;
|
||||||
|
--open-app-sidebar-text-secondary: rgba(242, 255, 252, 76%);
|
||||||
|
--open-app-sidebar-muted: rgba(242, 255, 252, 56%);
|
||||||
|
--open-app-sidebar-hover: rgba(255, 255, 255, 10%);
|
||||||
|
--open-app-sidebar-active-bg: rgba(0, 166, 122, 22%);
|
||||||
|
--open-app-sidebar-active-text: #ffffff;
|
||||||
|
--open-app-sidebar-accent: #00a67a;
|
||||||
|
--open-app-sidebar-accent-2: #7ee8c4;
|
||||||
|
--open-app-sidebar-control-bg: rgba(255, 255, 255, 10%);
|
||||||
|
--open-app-sidebar-control-border: rgba(126, 232, 196, 32%);
|
||||||
|
--open-app-sidebar-control-shadow: 0 18px 42px rgba(0, 22, 24, 32%);
|
||||||
|
--open-app-sidebar-footer-bg: rgba(0, 34, 36, 48%);
|
||||||
|
--open-app-sidebar-gradient-end: #003f42;
|
||||||
|
--open-app-theme-switch-bg: rgba(255, 255, 255, 10%);
|
||||||
|
--open-app-theme-switch-active-bg: #00a67a;
|
||||||
|
--open-app-theme-switch-active-text: #003f42;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-portal {
|
||||||
|
--open-app-sidebar-bg: #f4fbf8;
|
||||||
|
--open-app-sidebar-border: rgba(0, 101, 105, 20%);
|
||||||
|
--open-app-sidebar-text: #113436;
|
||||||
|
--open-app-sidebar-text-secondary: rgba(17, 52, 54, 70%);
|
||||||
|
--open-app-sidebar-muted: rgba(17, 52, 54, 54%);
|
||||||
|
--open-app-sidebar-hover: rgba(0, 166, 122, 10%);
|
||||||
|
--open-app-sidebar-active-bg: #ffffff;
|
||||||
|
--open-app-sidebar-active-text: #006569;
|
||||||
|
--open-app-sidebar-control-bg: #ffffff;
|
||||||
|
--open-app-sidebar-control-border: rgba(0, 101, 105, 18%);
|
||||||
|
--open-app-sidebar-control-shadow: 0 12px 30px rgba(0, 101, 105, 12%);
|
||||||
|
--open-app-sidebar-footer-bg: #ffffff;
|
||||||
|
--open-app-sidebar-gradient-end: #f4fbf8;
|
||||||
|
--open-app-theme-switch-bg: #ffffff;
|
||||||
|
--open-app-theme-switch-active-bg: #006569;
|
||||||
|
--open-app-theme-switch-active-text: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用智能体侧边栏容器
|
// 应用智能体侧边栏容器
|
||||||
@@ -10,8 +87,9 @@
|
|||||||
width: 250px;
|
width: 250px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: @paddingSm @paddingXs;
|
padding: @paddingSm @paddingXs;
|
||||||
border-right: @colorBorderSecondary 1px solid;
|
border-right: 1px solid var(--open-app-sidebar-border);
|
||||||
background-color: @colorBgContainerDisabled;
|
background: var(--open-app-sidebar-bg);
|
||||||
|
color: var(--open-app-sidebar-text);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: @paddingSm;
|
gap: @paddingSm;
|
||||||
@@ -43,7 +121,8 @@
|
|||||||
width: 26px;
|
width: 26px;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
border-radius: @borderRadius;
|
border-radius: @borderRadius;
|
||||||
background-color: @colorBgContainer;
|
background-color: var(--open-app-sidebar-control-bg);
|
||||||
|
border: 1px solid var(--open-app-sidebar-control-border);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
@@ -59,6 +138,7 @@
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,9 +146,9 @@
|
|||||||
.newSessionBtn {
|
.newSessionBtn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: @controlHeightLg;
|
height: @controlHeightLg;
|
||||||
border: @lineWidth solid @colorBorder;
|
border: @lineWidth solid var(--open-app-sidebar-control-border);
|
||||||
border-radius: @borderRadiusLg;
|
border-radius: @borderRadiusLg;
|
||||||
background-color: @colorBgContainer;
|
background: var(--open-app-sidebar-control-bg);
|
||||||
padding: 0 @paddingSm;
|
padding: 0 @paddingSm;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -77,14 +157,15 @@
|
|||||||
transition: box-shadow 0.2s ease-in-out, background-color 0.2s ease-in-out;
|
transition: box-shadow 0.2s ease-in-out, background-color 0.2s ease-in-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: @boxShadowSecondary;
|
box-shadow: var(--open-app-sidebar-control-shadow);
|
||||||
|
border-color: var(--open-app-sidebar-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.newSessionText {
|
.newSessionText {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: @colorText;
|
color: var(--open-app-sidebar-text);
|
||||||
font-size: @fontSize;
|
font-size: @fontSize;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -97,12 +178,44 @@
|
|||||||
height: 22px;
|
height: 22px;
|
||||||
padding: 0 @paddingXs;
|
padding: 0 @paddingXs;
|
||||||
border-radius: @borderRadiusOuter;
|
border-radius: @borderRadiusOuter;
|
||||||
background: @colorBgLayout;
|
background: var(--open-app-sidebar-hover);
|
||||||
color: @colorTextDescription;
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
font-size: @fontSizeSm;
|
font-size: @fontSizeSm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.themeSwitcher {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 2px;
|
||||||
|
padding: 3px;
|
||||||
|
border: 1px solid var(--open-app-sidebar-control-border);
|
||||||
|
border-radius: @borderRadiusLg;
|
||||||
|
background: var(--open-app-theme-switch-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeOption {
|
||||||
|
min-width: 0;
|
||||||
|
height: 28px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: @borderRadius;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
|
font-size: @fontSizeSm;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--open-app-sidebar-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.themeOptionActive {
|
||||||
|
background: var(--open-app-theme-switch-active-bg);
|
||||||
|
color: var(--open-app-theme-switch-active-text);
|
||||||
|
box-shadow: 0 6px 14px rgba(0, 0, 0, 12%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========================== 导航 ==========================
|
// ========================== 导航 ==========================
|
||||||
.pageNavList {
|
.pageNavList {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -119,6 +232,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: @colorText;
|
color: @colorText;
|
||||||
|
color: var(--open-app-sidebar-text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
transition: background-color 0.2s ease, color 0.2s ease;
|
||||||
@@ -129,11 +243,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #e6e7e8;
|
background-color: var(--open-app-sidebar-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.page-nav-item-active {
|
&.page-nav-item-active {
|
||||||
background-color: #e6e7e8;
|
position: relative;
|
||||||
|
background-color: var(--open-app-sidebar-active-bg);
|
||||||
|
color: var(--open-app-sidebar-active-text);
|
||||||
|
box-shadow: var(--open-app-sidebar-control-shadow);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
width: 3px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--open-app-sidebar-accent-2);
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +283,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: @colorText;
|
color: @colorText;
|
||||||
|
color: var(--open-app-sidebar-text);
|
||||||
font-size: @fontSize;
|
font-size: @fontSize;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
@@ -164,7 +292,7 @@
|
|||||||
.more-conversation {
|
.more-conversation {
|
||||||
line-height: @lineHeight;
|
line-height: @lineHeight;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: @navSecondMenuTextSecondary;
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
font-size: @fontSizeSm;
|
font-size: @fontSizeSm;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.3s ease;
|
transition: color 0.3s ease;
|
||||||
@@ -172,7 +300,7 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: @navSecondMenuTextSecondary;
|
color: var(--open-app-sidebar-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +310,7 @@
|
|||||||
|
|
||||||
.no-used {
|
.no-used {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
color: @colorTextDescription;
|
color: var(--open-app-sidebar-muted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +324,7 @@
|
|||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
180deg,
|
180deg,
|
||||||
rgba(255, 255, 255, 0%) 0%,
|
rgba(255, 255, 255, 0%) 0%,
|
||||||
#f9fafb 80.65%
|
var(--open-app-sidebar-gradient-end) 80.65%
|
||||||
);
|
);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@@ -206,12 +334,13 @@
|
|||||||
.user-area {
|
.user-area {
|
||||||
padding: @paddingXxs @paddingXs;
|
padding: @paddingXxs @paddingXs;
|
||||||
border-radius: @borderRadiusLg;
|
border-radius: @borderRadiusLg;
|
||||||
|
background: var(--open-app-sidebar-footer-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: box-shadow 0.2s ease-in-out, background-color 0.2s ease-in-out;
|
transition: box-shadow 0.2s ease-in-out, background-color 0.2s ease-in-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: @colorBgLayout;
|
background-color: var(--open-app-sidebar-hover);
|
||||||
box-shadow: @boxShadowDrawerUp;
|
box-shadow: var(--open-app-sidebar-control-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户头像
|
// 用户头像
|
||||||
@@ -231,15 +360,46 @@
|
|||||||
|
|
||||||
// 用户名称
|
// 用户名称
|
||||||
.user-name {
|
.user-name {
|
||||||
color: @colorTextSecondary;
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.active-icon-container {
|
.active-icon-container {
|
||||||
color: @navFirstMenuTextSecondary;
|
color: var(--open-app-sidebar-text-secondary);
|
||||||
padding: @paddingXs;
|
padding: @paddingXs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-dispatch {
|
||||||
|
.agentSidebarContainer {
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(0, 166, 122, 12%) 0%, rgba(0, 63, 66, 0%) 34%),
|
||||||
|
var(--open-app-sidebar-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarTop {
|
||||||
|
.logo-container {
|
||||||
|
box-shadow: 0 0 0 3px rgba(126, 232, 196, 18%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.newSessionBtn {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-portal {
|
||||||
|
.agentSidebarContainer {
|
||||||
|
border-top: 4px solid var(--open-app-sidebar-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarTop {
|
||||||
|
padding: 0 @paddingXs;
|
||||||
|
border-radius: @borderRadiusLg;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 101, 105, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.messageContainer {
|
.messageContainer {
|
||||||
left: 13px !important;
|
left: 13px !important;
|
||||||
bottom: 53px !important;
|
bottom: 53px !important;
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ import {
|
|||||||
} from 'umi';
|
} from 'umi';
|
||||||
import ConversationItem from './ConversationItem';
|
import ConversationItem from './ConversationItem';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
import {
|
||||||
|
OPEN_APP_THEME_STORAGE_KEY,
|
||||||
|
OpenAppTheme,
|
||||||
|
getInitialOpenAppTheme,
|
||||||
|
openAppThemes,
|
||||||
|
} from './openAppTheme';
|
||||||
|
|
||||||
// 绑定 classNames,便于动态样式组合
|
// 绑定 classNames,便于动态样式组合
|
||||||
const cx = classNames.bind(styles);
|
const cx = classNames.bind(styles);
|
||||||
@@ -96,6 +102,9 @@ const BaseTemplate: React.FC = () => {
|
|||||||
// 底部渐变显示状态
|
// 底部渐变显示状态
|
||||||
const [showFooterTopGradient, setShowFooterTopGradient] =
|
const [showFooterTopGradient, setShowFooterTopGradient] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
const [openAppTheme, setOpenAppTheme] = useState<OpenAppTheme>(
|
||||||
|
getInitialOpenAppTheme,
|
||||||
|
);
|
||||||
|
|
||||||
/** 手机端且侧栏展开时收起侧栏(用于点主内容区、新建会话、历史项等) */
|
/** 手机端且侧栏展开时收起侧栏(用于点主内容区、新建会话、历史项等) */
|
||||||
const closeSidebarIfMobileOpen = useCallback(() => {
|
const closeSidebarIfMobileOpen = useCallback(() => {
|
||||||
@@ -164,6 +173,10 @@ const BaseTemplate: React.FC = () => {
|
|||||||
document.documentElement.style.minWidth = 'unset';
|
document.documentElement.style.minWidth = 'unset';
|
||||||
}, [agentId]);
|
}, [agentId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem(OPEN_APP_THEME_STORAGE_KEY, openAppTheme);
|
||||||
|
}, [openAppTheme]);
|
||||||
|
|
||||||
// 已发布的智能体详情接口
|
// 已发布的智能体详情接口
|
||||||
const { run: runDetail } = useRequest(apiPublishedAgentInfo, {
|
const { run: runDetail } = useRequest(apiPublishedAgentInfo, {
|
||||||
manual: true,
|
manual: true,
|
||||||
@@ -376,7 +389,6 @@ const BaseTemplate: React.FC = () => {
|
|||||||
zIndex: 999,
|
zIndex: 999,
|
||||||
pointerEvents: isAppSidebarVisible ? 'auto' : 'none',
|
pointerEvents: isAppSidebarVisible ? 'auto' : 'none',
|
||||||
transform: isAppSidebarVisible ? 'translateX(0)' : 'translateX(-100%)',
|
transform: isAppSidebarVisible ? 'translateX(0)' : 'translateX(-100%)',
|
||||||
backgroundColor: '#f5f5f5',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -405,7 +417,14 @@ const BaseTemplate: React.FC = () => {
|
|||||||
const showAppSidebarLoading = appAgentDetailLoading || !appAgentDetail;
|
const showAppSidebarLoading = appAgentDetailLoading || !appAgentDetail;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx('flex', 'h-full', styles.container)}>
|
<div
|
||||||
|
className={cx(
|
||||||
|
'flex',
|
||||||
|
'h-full',
|
||||||
|
styles.container,
|
||||||
|
styles[`theme-${openAppTheme}`],
|
||||||
|
)}
|
||||||
|
>
|
||||||
{/* 侧边菜单栏区域 */}
|
{/* 侧边菜单栏区域 */}
|
||||||
<div
|
<div
|
||||||
className={cx(styles.agentSidebarContainer, {
|
className={cx(styles.agentSidebarContainer, {
|
||||||
@@ -493,6 +512,23 @@ const BaseTemplate: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.themeSwitcher}>
|
||||||
|
{openAppThemes.map((theme) => (
|
||||||
|
<button
|
||||||
|
key={theme.key}
|
||||||
|
type="button"
|
||||||
|
className={cx(styles.themeOption, {
|
||||||
|
[styles.themeOptionActive]: openAppTheme === theme.key,
|
||||||
|
})}
|
||||||
|
title={theme.title}
|
||||||
|
aria-pressed={openAppTheme === theme.key}
|
||||||
|
onClick={() => setOpenAppTheme(theme.key)}
|
||||||
|
>
|
||||||
|
{theme.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 页面导航 */}
|
{/* 页面导航 */}
|
||||||
<ConditionRender
|
<ConditionRender
|
||||||
condition={appAgentDetail?.customPageMenus?.length > 0}
|
condition={appAgentDetail?.customPageMenus?.length > 0}
|
||||||
|
|||||||
38
qiming/src/pages/OpenApp/BaseTemplate/openAppTheme.ts
Normal file
38
qiming/src/pages/OpenApp/BaseTemplate/openAppTheme.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
export const OPEN_APP_THEME_STORAGE_KEY = 'qiming-open-app-theme';
|
||||||
|
|
||||||
|
export const openAppThemes = [
|
||||||
|
{
|
||||||
|
key: 'light',
|
||||||
|
label: '纯白',
|
||||||
|
title: '纯白国网绿轻量版',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dispatch',
|
||||||
|
label: '调度',
|
||||||
|
title: '深绿调度台版',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'portal',
|
||||||
|
label: '门户',
|
||||||
|
title: '绿白政企门户版',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type OpenAppTheme = (typeof openAppThemes)[number]['key'];
|
||||||
|
|
||||||
|
const DEFAULT_OPEN_APP_THEME: OpenAppTheme = 'dispatch';
|
||||||
|
|
||||||
|
export const isOpenAppTheme = (value: string): value is OpenAppTheme => {
|
||||||
|
return openAppThemes.some((theme) => theme.key === value);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInitialOpenAppTheme = (): OpenAppTheme => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return DEFAULT_OPEN_APP_THEME;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedTheme = window.localStorage.getItem(OPEN_APP_THEME_STORAGE_KEY);
|
||||||
|
return storedTheme && isOpenAppTheme(storedTheme)
|
||||||
|
? storedTheme
|
||||||
|
: DEFAULT_OPEN_APP_THEME;
|
||||||
|
};
|
||||||
45
qiming/tests/openAppTheme.test.ts
Normal file
45
qiming/tests/openAppTheme.test.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import {
|
||||||
|
OPEN_APP_THEME_STORAGE_KEY,
|
||||||
|
getInitialOpenAppTheme,
|
||||||
|
isOpenAppTheme,
|
||||||
|
openAppThemes,
|
||||||
|
} from '@/pages/OpenApp/BaseTemplate/openAppTheme';
|
||||||
|
|
||||||
|
describe('openAppTheme', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defines the three State Grid green OpenApp themes', () => {
|
||||||
|
expect(openAppThemes.map((theme) => theme.key)).toEqual([
|
||||||
|
'light',
|
||||||
|
'dispatch',
|
||||||
|
'portal',
|
||||||
|
]);
|
||||||
|
expect(openAppThemes.map((theme) => theme.label)).toEqual([
|
||||||
|
'纯白',
|
||||||
|
'调度',
|
||||||
|
'门户',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('recognizes valid theme keys only', () => {
|
||||||
|
expect(isOpenAppTheme('light')).toBe(true);
|
||||||
|
expect(isOpenAppTheme('dispatch')).toBe(true);
|
||||||
|
expect(isOpenAppTheme('portal')).toBe(true);
|
||||||
|
expect(isOpenAppTheme('dark')).toBe(false);
|
||||||
|
expect(isOpenAppTheme('')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('uses dispatch as the default visual variant', () => {
|
||||||
|
expect(getInitialOpenAppTheme()).toBe('dispatch');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('restores a valid stored theme and ignores invalid storage values', () => {
|
||||||
|
localStorage.setItem(OPEN_APP_THEME_STORAGE_KEY, 'portal');
|
||||||
|
expect(getInitialOpenAppTheme()).toBe('portal');
|
||||||
|
|
||||||
|
localStorage.setItem(OPEN_APP_THEME_STORAGE_KEY, 'unknown');
|
||||||
|
expect(getInitialOpenAppTheme()).toBe('dispatch');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user