From 28750ab0681f30a1eb2fa52ffb42b605361c3691 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Sat, 6 Dec 2025 14:57:19 +0800 Subject: [PATCH] feat: implement responsive brand title behavior for mobile viewports with animation handling and CSS adjustments --- app.js | 76 ++++++++++++++++++++++++++++++++- styles.css | 121 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 171 insertions(+), 26 deletions(-) diff --git a/app.js b/app.js index 04d8713..06e7e13 100644 --- a/app.js +++ b/app.js @@ -681,6 +681,10 @@ class CLIProxyManager { } // 顶栏标题动画与状态 + isMobileViewport() { + return typeof window !== 'undefined' ? window.innerWidth <= 768 : false; + } + setupBrandTitleAnimation() { const mainPage = document.getElementById('main-page'); if (mainPage && mainPage.style.display === 'none') { @@ -703,13 +707,45 @@ class CLIProxyManager { toggle.addEventListener('click', this.brandToggleHandler); } if (!this.brandResizeHandler) { - this.brandResizeHandler = () => this.updateBrandTextWidths({ immediate: true }); + this.brandResizeHandler = () => this.handleBrandResize(); window.addEventListener('resize', this.brandResizeHandler); } + if (this.isMobileViewport()) { + this.applyMobileBrandState(); + } else { + this.enableBrandAnimation(); + } + } + + enableBrandAnimation() { + const { toggle } = this.brandElements || {}; + if (toggle) { + toggle.removeAttribute('aria-disabled'); + toggle.style.pointerEvents = ''; + } this.brandAnimationReady = true; } + applyMobileBrandState() { + const { toggle, wrapper, shortText } = this.brandElements || {}; + if (!toggle || !wrapper || !shortText) { + return; + } + + this.clearBrandCollapseTimer(); + this.brandIsCollapsed = true; + this.brandAnimationReady = false; + + toggle.classList.add('collapsed'); + toggle.classList.remove('expanded'); + toggle.setAttribute('aria-disabled', 'true'); + toggle.style.pointerEvents = 'none'; + + const targetWidth = this.getBrandTextWidth(shortText); + this.applyBrandWidth(targetWidth, { animate: false }); + } + getBrandTextWidth(element) { if (!element) { return 0; @@ -762,6 +798,27 @@ class CLIProxyManager { toggle.classList.toggle('expanded', !collapsed); } + handleBrandResize() { + if (!this.brandElements?.wrapper) { + return; + } + + if (this.isMobileViewport()) { + this.applyMobileBrandState(); + return; + } + + if (!this.brandAnimationReady) { + this.enableBrandAnimation(); + this.brandIsCollapsed = false; + this.setBrandCollapsed(false, { animate: false }); + this.scheduleBrandCollapse(this.brandCollapseDelayMs); + return; + } + + this.updateBrandTextWidths({ immediate: true }); + } + scheduleBrandCollapse(delayMs = this.brandCollapseDelayMs) { this.clearBrandCollapseTimer(); this.brandCollapseTimer = window.setTimeout(() => { @@ -779,6 +836,12 @@ class CLIProxyManager { startBrandCollapseCycle() { this.setupBrandTitleAnimation(); + + if (this.isMobileViewport()) { + this.applyMobileBrandState(); + return; + } + if (!this.brandAnimationReady) { return; } @@ -792,6 +855,12 @@ class CLIProxyManager { resetBrandTitleState() { this.clearBrandCollapseTimer(); const mainPage = document.getElementById('main-page'); + + if (this.isMobileViewport()) { + this.applyMobileBrandState(); + return; + } + if (!this.brandAnimationReady || (mainPage && mainPage.style.display === 'none')) { this.brandIsCollapsed = false; return; @@ -802,6 +871,11 @@ class CLIProxyManager { } refreshBrandTitleAfterTextChange() { + if (this.isMobileViewport()) { + this.applyMobileBrandState(); + return; + } + if (!this.brandAnimationReady) { return; } diff --git a/styles.css b/styles.css index 782b48f..02d364c 100644 --- a/styles.css +++ b/styles.css @@ -267,6 +267,8 @@ display: inline-flex; align-items: center; height: 36px; + min-width: 36px; + justify-content: center; } /* 登录页面的按钮样式优化 */ @@ -916,6 +918,26 @@ body { position: relative; } +@media (max-width: 768px) { + .top-navbar-brand-toggle { + pointer-events: none; + cursor: default; + } + + .brand-texts { + transition: none; + } + + .top-navbar-brand-toggle .brand-text-full { + display: none; + } + + .top-navbar-brand-toggle .brand-text-short { + position: relative; + opacity: 1; + } +} + .top-navbar-actions { display: flex; align-items: center; @@ -926,63 +948,99 @@ body { .top-navbar-actions>* { display: inline-flex; align-items: center; + justify-content: center; height: 36px; + min-width: 44px; } .top-navbar .header-controls { display: inline-flex; align-items: center; gap: 8px; - height: 100%; + height: auto; } .top-navbar .language-btn, .top-navbar .theme-btn { - width: 36px; height: 36px; min-height: 36px; - padding: 0; + min-width: 44px; + padding: 0 12px; justify-content: center; + line-height: 1; } .top-navbar-actions .btn { height: 36px; min-height: 36px; + min-width: 44px; + padding: 0 12px; + justify-content: center; + line-height: 1; } @media (max-width: 768px) { + .top-navbar { + flex-direction: column; + align-items: stretch; + gap: 8px; + height: auto; + min-height: var(--navbar-height, 69px); + } + + .top-navbar-left { + width: 100%; + justify-content: flex-start; + } + .top-navbar-actions { + width: 100%; flex-wrap: wrap; justify-content: flex-end; gap: 8px; + margin-left: 0; + align-items: center; } .top-navbar .header-controls { - width: 100%; + width: auto; + order: 0; justify-content: flex-end; - order: 99; gap: 8px; + height: auto; + align-items: center; } .top-navbar-actions>* { - height: 34px; - min-height: 34px; + height: 36px; + min-height: 36px; + min-width: 44px; + justify-content: center; } .top-navbar .language-btn, .top-navbar .theme-btn { - width: 34px; - height: 34px; + height: 36px; + min-height: 36px; + min-width: 44px; + padding: 0 12px; + justify-content: center; + line-height: 1; } .top-navbar-actions .btn { - height: 34px; - min-height: 34px; - padding: 0 10px; + height: 36px; + min-height: 36px; + min-width: 44px; + padding: 0 12px; + justify-content: center; + line-height: 1; } - .top-navbar-actions .btn span { - display: none; + .top-navbar .language-btn i, + .top-navbar .theme-btn i, + .top-navbar-actions .btn i { + margin: 0; } } @@ -3048,38 +3106,51 @@ input:checked+.slider:before { @media (max-width: 768px) { .top-navbar { padding: 12px 16px; + flex-direction: column; + align-items: stretch; + gap: 8px; + height: auto; + min-height: var(--navbar-height, 69px); } .top-navbar-title { font-size: 18px; } + .top-navbar-left { + width: 100%; + justify-content: flex-start; + } + .top-navbar-actions { gap: 6px; flex-wrap: wrap; justify-content: flex-end; + width: 100%; + margin-left: 0; } .top-navbar-actions>* { - height: 34px; - min-height: 34px; + height: 36px; + min-height: 36px; + min-width: 44px; } .top-navbar .header-controls { - height: 34px; - gap: 6px; + height: 36px; + gap: 8px; + width: auto; + order: 0; + justify-content: flex-end; } .top-navbar-actions .btn, .top-navbar .language-btn, .top-navbar .theme-btn { - height: 34px; - min-height: 34px; - padding: 0 10px; - } - - .top-navbar-actions .btn span { - display: none; + height: 36px; + min-height: 36px; + min-width: 44px; + padding: 8px 12px; } .btn {