From abbaeabfe9b40d4b03342268d2a0aebc48751ed1 Mon Sep 17 00:00:00 2001
From: linshen <32978552+linshenkx@users.noreply.github.com>
Date: Sun, 29 Mar 2026 16:40:09 +0800
Subject: [PATCH] fix(ui): align about popover with naive theme
---
.../app-layout/AppHeaderActions.vue | 131 +++++-------------
.../unit/components/AppHeaderActions.spec.ts | 17 ++-
2 files changed, 45 insertions(+), 103 deletions(-)
diff --git a/packages/ui/src/components/app-layout/AppHeaderActions.vue b/packages/ui/src/components/app-layout/AppHeaderActions.vue
index d4e589af..292dc365 100644
--- a/packages/ui/src/components/app-layout/AppHeaderActions.vue
+++ b/packages/ui/src/components/app-layout/AppHeaderActions.vue
@@ -93,9 +93,7 @@
v-model:show="showAboutPopover"
trigger="click"
placement="bottom-end"
- raw
:show-arrow="false"
- content-class="about-popover-content"
>
-
-
{{ appVersion }}
+
+
-
+
-
+
@@ -209,7 +209,7 @@ import ActionButtonUI from '../ActionButton.vue'
import ThemeToggleUI from '../ThemeToggleUI.vue'
import LanguageSwitchDropdown from '../LanguageSwitchDropdown.vue'
import UpdaterIcon from '../UpdaterIcon.vue'
-import { NButton, NPopover } from 'naive-ui'
+import { NButton, NPopover, NTag } from 'naive-ui'
interface Props {
appVersion: string
@@ -277,93 +277,44 @@ const handleOpenDocs = () => {
margin-left: 6px;
}
-:deep(.about-popover-content) {
- padding: 0 !important;
- background: transparent !important;
- box-shadow: none !important;
- border: 0 !important;
-}
-
-.about-flyout {
+.about-panel {
display: flex;
flex-direction: column;
- align-items: flex-end;
- gap: 7px;
- padding-top: 8px;
+ gap: 6px;
+ min-width: 220px;
+ max-width: 260px;
}
-.about-chip {
- display: inline-flex;
- align-items: center;
- gap: 10px;
+.about-panel-header {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.about-version-tag {
max-width: 100%;
- box-sizing: border-box;
- border-radius: 999px;
- border: 1px solid color-mix(in srgb, var(--border-color, rgba(239, 239, 245, 0.82)) 86%, transparent);
- background: color-mix(in srgb, var(--card-color, #fff) 94%, transparent);
- color: inherit;
- backdrop-filter: blur(14px);
- box-shadow:
- 0 10px 24px rgba(15, 23, 42, 0.08),
- 0 2px 8px rgba(15, 23, 42, 0.05);
}
-.about-chip-version {
- align-self: flex-end;
- padding: 4px 9px;
- font-size: 11px;
- line-height: 1;
- color: var(--text-color-3);
- border-color: color-mix(in srgb, var(--border-color, rgba(239, 239, 245, 0.8)) 68%, transparent);
- background: color-mix(in srgb, var(--hover-color, rgba(0, 0, 0, 0.03)) 70%, transparent);
- box-shadow:
- 0 8px 18px rgba(15, 23, 42, 0.06),
- 0 1px 4px rgba(15, 23, 42, 0.03);
+.about-link-button {
+ width: 100%;
+ justify-content: space-between;
+ gap: 12px;
}
-.about-chip-link {
- max-width: 100%;
- min-width: 0;
- padding: 8px 12px 8px 13px;
- text-align: left;
- cursor: pointer;
- transition:
- background-color 0.2s ease,
- border-color 0.2s ease,
- color 0.2s ease,
- transform 0.2s ease,
- box-shadow 0.2s ease;
-}
-
-.about-chip-link:hover {
- background: color-mix(in srgb, var(--hover-color, rgba(0, 0, 0, 0.04)) 78%, transparent);
- border-color: color-mix(in srgb, var(--primary-color, #18a058) 22%, var(--border-color, rgba(239, 239, 245, 0.8)));
- transform: translateY(-1px);
- box-shadow:
- 0 12px 28px rgba(15, 23, 42, 0.1),
- 0 3px 10px rgba(15, 23, 42, 0.06);
-}
-
-.about-chip-link:focus-visible {
- outline: none;
- border-color: color-mix(in srgb, var(--primary-color, #18a058) 28%, var(--border-color, rgba(239, 239, 245, 0.8)));
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-color, #18a058) 14%, transparent);
-}
-
-.about-chip-text {
+.about-link-copy {
display: inline-flex;
align-items: baseline;
- gap: 7px;
+ gap: 8px;
min-width: 0;
+ text-align: left;
}
-.about-chip-label {
+.about-link-label {
flex-shrink: 0;
font-size: 11px;
color: var(--text-color-3);
}
-.about-chip-value {
+.about-link-value {
min-width: 0;
font-size: 12px;
font-weight: 600;
@@ -373,18 +324,10 @@ const handleOpenDocs = () => {
white-space: nowrap;
}
-.about-chip-icon {
+.about-link-icon {
width: 12px;
height: 12px;
flex-shrink: 0;
color: var(--text-color-3);
- transition:
- color 0.2s ease,
- transform 0.2s ease;
-}
-
-.about-chip-link:hover .about-chip-icon {
- color: var(--text-color-2);
- transform: translate(1px, -1px);
}
diff --git a/packages/ui/tests/unit/components/AppHeaderActions.spec.ts b/packages/ui/tests/unit/components/AppHeaderActions.spec.ts
index 679d1bed..72c7fe86 100644
--- a/packages/ui/tests/unit/components/AppHeaderActions.spec.ts
+++ b/packages/ui/tests/unit/components/AppHeaderActions.spec.ts
@@ -25,8 +25,8 @@ vi.mock('naive-ui', async (importOriginal) => {
}),
NTag: defineComponent({
name: 'NTag',
- setup(_, { slots }) {
- return () => h('span', { class: 'n-tag-stub' }, slots.default?.())
+ setup(_, { slots, attrs }) {
+ return () => h('span', { class: 'n-tag-stub', ...attrs }, slots.default?.())
},
}),
NText: defineComponent({
@@ -41,7 +41,7 @@ vi.mock('naive-ui', async (importOriginal) => {
import AppHeaderActions from '../../../src/components/app-layout/AppHeaderActions.vue'
describe('AppHeaderActions about menu layout hooks', () => {
- it('renders compact chip-style about actions without a product title row', () => {
+ it('renders the about popover with naive-themed panel content', () => {
const wrapper = mount(AppHeaderActions, {
props: {
appVersion: 'v2.7.0',
@@ -77,12 +77,11 @@ describe('AppHeaderActions about menu layout hooks', () => {
},
})
- expect(wrapper.find('.about-menu-title').exists()).toBe(false)
-
- const chips = wrapper.findAll('.about-chip')
- expect(chips).toHaveLength(3)
- expect(wrapper.find('.about-chip-version').text()).toContain('v2.7.0')
- expect(wrapper.findAll('.about-chip-link')).toHaveLength(2)
+ expect(wrapper.find('.about-flyout').exists()).toBe(false)
+ expect(wrapper.findAll('.about-chip')).toHaveLength(0)
+ expect(wrapper.find('.about-panel').exists()).toBe(true)
+ expect(wrapper.find('.about-version-tag').text()).toContain('v2.7.0')
+ expect(wrapper.findAll('.about-link-button')).toHaveLength(2)
expect(wrapper.text()).toContain('always200.com')
expect(wrapper.text()).toContain('docs.always200.com')
})