@@ -237,7 +294,7 @@ onBeforeMount(() => {
.system-layout {
width: 100vw;
height: 100vh;
- background-color: #f1f4f3;
+ background-color: var(--color-canvas-parchment);
display: flex;
@keyframes rotate {
@@ -255,12 +312,17 @@ onBeforeMount(() => {
padding: 16px;
position: relative;
min-width: 240px;
+ background-color: var(--color-canvas);
+ border-right: 1px solid var(--color-hairline);
.default-sqlbot {
display: flex;
align-items: center;
- font-weight: 500;
- font-size: 16px;
+ font-family: var(--font-sans);
+ font-weight: 600;
+ font-size: 17px;
+ letter-spacing: -0.374px;
+ color: var(--color-ink);
cursor: pointer;
margin-bottom: 12px;
.collapse-icon {
@@ -271,8 +333,11 @@ onBeforeMount(() => {
.sys-management {
display: flex;
align-items: center;
- font-weight: 500;
- font-size: 16px;
+ font-family: var(--font-sans);
+ font-weight: 600;
+ font-size: 17px;
+ letter-spacing: -0.374px;
+ color: var(--color-ink);
cursor: pointer;
margin-bottom: 12px;
.collapse-icon {
@@ -292,19 +357,19 @@ onBeforeMount(() => {
display: flex;
align-items: center;
justify-content: center;
- border-radius: 6px;
+ border-radius: 8px;
height: 40px;
cursor: pointer;
&:not(.collapse) {
- background: #1f23290a;
- border: 1px solid #d9dcdf;
+ background: var(--overlay-hover);
+ border: 1px solid var(--color-hairline);
}
&:hover {
- background-color: #1f23291a;
+ background-color: var(--overlay-hover);
}
&:active {
- background-color: #1f232926;
+ background-color: var(--overlay-pressed);
}
.ed-icon {
margin-right: 4.95px;
@@ -319,16 +384,16 @@ onBeforeMount(() => {
.fold {
cursor: pointer;
margin-left: auto;
- border-radius: 6px;
+ border-radius: 8px;
width: 40px;
height: 40px;
&:hover,
&:focus {
- background: #1f23291a;
+ background: var(--overlay-hover);
}
&:active {
- background: #1f232933;
+ background: var(--overlay-strong);
}
}
}
@@ -338,7 +403,6 @@ onBeforeMount(() => {
width: 64px;
min-width: 64px;
padding: 16px 12px;
- // animation: rotate 0.1s ease-in-out;
.ed-menu--collapse {
--ed-menu-icon-width: 32px;
@@ -380,9 +444,10 @@ onBeforeMount(() => {
width: 100%;
height: 100%;
padding: 16px 24px;
- background-color: #fff;
- border-radius: 12px;
- box-shadow: 0px 2px 4px 0px #1f23291f;
+ background-color: var(--color-canvas);
+ border: 1px solid var(--color-hairline);
+ border-radius: 18px;
+ box-shadow: none;
overflow-x: auto;
&:has(.no-padding) {
@@ -390,5 +455,100 @@ onBeforeMount(() => {
}
}
}
+
+ &.system-layout--chat {
+ align-items: stretch;
+ }
+
+ .layout-column-resizer {
+ width: 6px;
+ flex-shrink: 0;
+ cursor: col-resize;
+ align-self: stretch;
+ margin: 8px 0;
+ border-radius: 4px;
+ background: transparent;
+ transition: background 0.15s;
+
+ &:hover {
+ background: var(--overlay-hover);
+ }
+ }
+
+ .left-side--chat {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ overflow: hidden;
+
+ .left-side-nav-block {
+ flex-shrink: 0;
+ flex: 0 1 auto;
+ max-height: 46%;
+ min-height: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ position: relative;
+ z-index: 5;
+ }
+
+ .layout-chat-history-shell {
+ flex: 1;
+ min-height: 0;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ padding-top: 4px;
+ position: relative;
+ z-index: 1;
+ }
+
+ .layout-chat-history-divider {
+ flex-shrink: 0;
+ height: 1px;
+ margin: 0 12px;
+ background: var(--color-hairline);
+ }
+
+ .layout-chat-history-heading {
+ flex-shrink: 0;
+ padding: 8px 16px 4px;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 18px;
+ color: var(--color-muted);
+ letter-spacing: 0.02em;
+ }
+
+ .layout-chat-history {
+ flex: 1;
+ min-height: 0;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+
+ & > * {
+ flex: 1;
+ min-height: 0;
+ width: 100%;
+ }
+ }
+
+ .bottom.bottom--flow {
+ position: static !important;
+ width: 100% !important;
+ left: auto !important;
+ bottom: auto !important;
+ margin-top: auto;
+ padding-top: 8px;
+ }
+ }
+
+ .right-main--chat {
+ flex: 1;
+ width: auto !important;
+ min-width: 0;
+ min-height: 0;
+ }
}
diff --git a/frontend/src/components/layout/Menu.vue b/frontend/src/components/layout/Menu.vue
index 731d1027a..e8cdf93d4 100644
--- a/frontend/src/components/layout/Menu.vue
+++ b/frontend/src/components/layout/Menu.vue
@@ -87,59 +87,79 @@ const routerList = computed(() => {
border-right: none;
.ed-menu-item {
height: 40px !important;
- border-radius: 6px !important;
+ border-radius: 8px !important;
margin-bottom: 2px;
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: -0.224px;
+ color: var(--color-muted);
&.is-active {
- background-color: #fff !important;
- border-radius: 6px;
- font-weight: 500;
+ background-color: rgba(0, 102, 204, 0.1) !important;
+ border-radius: 8px;
+ font-weight: 600;
+ color: var(--color-ink);
}
}
.ed-sub-menu .ed-sub-menu__title {
- border-radius: 6px;
+ border-radius: 8px;
+ color: var(--color-muted);
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: -0.224px;
}
.ed-sub-menu.is-active:not(.is-opened) {
.ed-sub-menu__title {
- background-color: #fff !important;
- color: var(--ed-color-primary) !important;
- font-weight: 500;
+ background-color: rgba(0, 102, 204, 0.1) !important;
+ color: #0066cc !important;
+ font-weight: 600;
}
}
.ed-sub-menu.is-active.is-opened {
.ed-sub-menu__title {
- color: var(--ed-color-primary) !important;
- font-weight: 500;
+ color: #0066cc !important;
+ font-weight: 600;
}
}
.ed-sub-menu .ed-icon {
margin-right: 8px;
+ color: var(--color-muted);
}
}
.ed-popper.is-light:has(.ed-menu--popup) {
- border: 1px solid #dee0e3;
- border-radius: 6px;
- box-shadow: 0px 4px 8px 0px #1f23291a;
- background: #eff1f0;
+ border: 1px solid var(--color-hairline);
+ border-radius: 8px;
+ box-shadow: none;
+ background: var(--color-canvas);
overflow: hidden;
}
.ed-menu--popup {
padding: 8px;
- background: #eff1f0;
+ background: var(--color-canvas);
.ed-menu-item {
padding: 9px 16px;
height: 40px !important;
- border-radius: 6px;
+ border-radius: 8px;
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: -0.224px;
+ color: var(--color-muted);
&.is-active {
- background-color: #fff !important;
- font-weight: 500;
+ background-color: rgba(0, 102, 204, 0.1) !important;
+ font-weight: 600;
+ color: var(--color-ink);
}
}
}
+
+/* 问数侧栏折叠时,设置等子菜单浮层需盖过下方历史区与主内容区 */
+.menu-left-sub-popup {
+ z-index: 6000 !important;
+}
.ed-sub-menu {
.subTitleMenu {
display: none;
@@ -147,7 +167,7 @@ const routerList = computed(() => {
}
.ed-menu--popup-container .subTitleMenu {
- color: #646a73 !important;
+ color: var(--color-muted) !important;
pointer-events: none;
}
diff --git a/frontend/src/components/layout/MenuItem.vue b/frontend/src/components/layout/MenuItem.vue
index 279030569..3b932150e 100644
--- a/frontend/src/components/layout/MenuItem.vue
+++ b/frontend/src/components/layout/MenuItem.vue
@@ -82,7 +82,11 @@ const MenuItem = defineComponent({
const icon = route.path.startsWith(path) ? iconActive : iconDeActive
return h(
ElSubMenu,
- { index: path, onClick: () => handleMenuClick(props.menu) },
+ {
+ index: path,
+ onClick: () => handleMenuClick(props.menu),
+ popperClass: 'menu-left-sub-popup',
+ },
{
title: () => titleWithIcon({ title, icon }),
default: () => [
diff --git a/frontend/src/components/layout/Person.vue b/frontend/src/components/layout/Person.vue
index ae0448e26..e451a02b1 100644
--- a/frontend/src/components/layout/Person.vue
+++ b/frontend/src/components/layout/Person.vue
@@ -8,6 +8,7 @@ import icon_maybe_outlined from '@/assets/svg/icon-maybe_outlined.svg'
import icon_key_outlined from '@/assets/svg/icon-key_outlined.svg'
import icon_api_key from '@/assets/svg/icon-api_key.svg'
import icon_translate_outlined from '@/assets/svg/icon_translate_outlined.svg'
+import icon_replace_outlined from '@/assets/svg/icon_replace_outlined.svg'
import icon_logout_outlined from '@/assets/svg/icon_logout_outlined.svg'
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
import AboutDialog from '@/components/about/index.vue'
@@ -20,6 +21,13 @@ import { useUserStore } from '@/stores/user'
import { userApi } from '@/api/auth'
import { toLoginPage } from '@/utils/utils'
import { useCache } from '@/utils/useCache'
+import { ElMessage } from 'element-plus-secondary'
+import {
+ applyUiTheme,
+ getStoredUiTheme,
+ UI_THEME_ORDER,
+ type UiThemeId,
+} from '@/utils/uiTheme'
const { wsCache } = useCache()
const router = useRouter()
@@ -69,6 +77,17 @@ const languageList = computed(() => [
])
const popoverRef = ref()
+const currentUiTheme = ref
(getStoredUiTheme())
+const themeList = computed(() =>
+ UI_THEME_ORDER.map((id) => ({ id, name: t(`theme.${id}`) }))
+)
+
+function selectUiTheme(id: UiThemeId) {
+ applyUiTheme(id)
+ currentUiTheme.value = id
+ ElMessage.success(t('common.switch_success'))
+}
+
const toSystem = () => {
popoverRef.value.hide()
router.push('/system')
@@ -137,7 +156,7 @@ const logout = async () => {
{{ account }}