From cd59bbfa410c65a3e27bfdd6e52aaa034bc13c43 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Fri, 21 Nov 2025 00:38:22 +0800 Subject: [PATCH] fix: refine input stadium interactions --- static/app.js | 29 +++++++++++++--- static/index.html | 70 +++++++++++++++++++++----------------- static/style.css | 87 +++++++++++++++++++++++++++++++---------------- 3 files changed, 122 insertions(+), 64 deletions(-) diff --git a/static/app.js b/static/app.js index 7361314..f9a1341 100644 --- a/static/app.js +++ b/static/app.js @@ -204,6 +204,8 @@ async function bootstrapApp() { settingsOpen: false, quickMenuOpen: false, inputLineCount: 1, + inputIsMultiline: false, + inputIsFocused: false, // 思考块滚动锁 thinkingScrollLocks: new Map(), @@ -1327,6 +1329,7 @@ async function bootstrapApp() { this.toolMenuOpen = false; this.quickMenuOpen = false; this.inputLineCount = 1; + this.inputIsMultiline = false; this.toolSettingsLoading = false; this.toolSettings = []; @@ -2458,19 +2461,37 @@ async function bootstrapApp() { this.autoResizeInput(); }, + handleInputFocus() { + this.inputIsFocused = true; + }, + + handleInputBlur() { + this.inputIsFocused = false; + }, + autoResizeInput() { this.$nextTick(() => { const textarea = this.$refs.stadiumInput; if (!textarea) { return; } + const previousHeight = textarea.offsetHeight; textarea.style.height = 'auto'; const computedStyle = window.getComputedStyle(textarea); const lineHeight = parseFloat(computedStyle.lineHeight || '20') || 20; const maxHeight = lineHeight * 6; - const newHeight = Math.min(textarea.scrollHeight, maxHeight); - textarea.style.height = `${newHeight}px`; - this.inputLineCount = Math.max(1, Math.round(newHeight / lineHeight)); + const targetHeight = Math.min(textarea.scrollHeight, maxHeight); + this.inputLineCount = Math.max(1, Math.round(targetHeight / lineHeight)); + this.inputIsMultiline = targetHeight > lineHeight * 1.4; + if (Math.abs(targetHeight - previousHeight) <= 0.5) { + textarea.style.height = `${targetHeight}px`; + return; + } + textarea.style.height = `${previousHeight}px`; + void textarea.offsetHeight; + requestAnimationFrame(() => { + textarea.style.height = `${targetHeight}px`; + }); }); }, @@ -2478,7 +2499,7 @@ async function bootstrapApp() { if (!this.quickMenuOpen) { return; } - const shell = this.$refs.compactInputShell; + const shell = this.$refs.stadiumShellOuter || this.$refs.compactInputShell; if (shell && shell.contains(event.target)) { return; } diff --git a/static/index.html b/static/index.html index ee92ad0..86f0f3e 100644 --- a/static/index.html +++ b/static/index.html @@ -488,35 +488,45 @@
-
- - - - - +
+
+ + + + +
- -
diff --git a/static/style.css b/static/style.css index ad3b10f..b71ae9f 100644 --- a/static/style.css +++ b/static/style.css @@ -1474,39 +1474,70 @@ o-conversations { pointer-events: none; } -.stadium-shell { +.stadium-input-wrapper { position: relative; width: min(900px, 94%); - border: 1px solid var(--claude-border); - border-radius: 999px; - background: rgba(255, 255, 255, 0.96); - box-shadow: 0 18px 36px rgba(61, 57, 41, 0.12); - padding: 10px 70px; - min-height: 56px; - transition: padding 0.25s ease, box-shadow 0.25s ease, border-radius 0.25s ease; pointer-events: auto; } -.stadium-shell.expanded { - padding-top: 18px; - padding-bottom: 18px; - border-radius: 28px; +.stadium-shell { + --stadium-radius: 24px; + position: relative; + width: 100%; + min-height: calc(var(--stadium-radius) * 2.1); + padding: 12px 18px; + border-radius: var(--stadium-radius); + border: 1px solid rgba(15, 23, 42, 0.12); + background: #ffffff; + box-shadow: 0 18px 46px rgba(15, 23, 42, 0.16); + display: flex; + align-items: center; + gap: 12px; + transition: padding 0.2s ease, min-height 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +.stadium-shell.is-multiline { + padding-top: 16px; + padding-bottom: 16px; + min-height: calc(var(--stadium-radius) * 2.7); + border-color: rgba(15, 23, 42, 0.2); + box-shadow: 0 26px 70px rgba(15, 23, 42, 0.22); +} + +.stadium-shell.is-focused, +.stadium-shell.has-text { + border-color: rgba(218, 119, 86, 0.35); + box-shadow: + 0 0 0 1px rgba(218, 119, 86, 0.18), + 0 0 14px rgba(218, 119, 86, 0.18), + 0 18px 40px rgba(15, 23, 42, 0.18); +} + +.stadium-shell.is-multiline.is-focused, +.stadium-shell.is-multiline.has-text { + box-shadow: + 0 0 0 1px rgba(218, 119, 86, 0.2), + 0 0 18px rgba(218, 119, 86, 0.2), + 0 26px 68px rgba(15, 23, 42, 0.24); } .stadium-input { + flex: 1 1 auto; width: 100%; border: none; resize: none; background: transparent; - font-size: 15px; - line-height: 1.6; + font-size: 14px; + line-height: 1.4; font-family: inherit; color: var(--claude-text); - padding: 4px 0; - min-height: 24px; + padding: 0; + min-height: 20px; outline: none; overflow-y: auto; scrollbar-width: none; + transition: height 0.28s cubic-bezier(0.4, 0, 0.2, 1); + will-change: height; } .stadium-input:disabled { @@ -1520,24 +1551,19 @@ o-conversations { } .stadium-btn { - position: absolute; - bottom: 10px; - width: 40px; - height: 40px; + flex: 0 0 36px; + width: 36px; + height: 36px; border: none; border-radius: 50%; background: transparent; color: var(--claude-text); - font-size: 20px; + font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center; - transition: background 0.2s ease, transform 0.2s ease; -} - -.stadium-shell.expanded .stadium-btn { - bottom: 14px; + transition: background 0.2s ease, transform 0.2s ease, margin-top 0.2s ease; } .stadium-btn:disabled { @@ -1550,12 +1576,10 @@ o-conversations { } .add-btn { - left: 12px; - font-size: 26px; + font-size: 22px; } .stadium-btn.send-btn { - right: 12px; background: var(--claude-accent); color: #fffaf0; box-shadow: 0 10px 20px rgba(189, 93, 58, 0.28); @@ -1589,6 +1613,11 @@ o-conversations { border-left-color: rgba(255, 255, 255, 0.4); } +.stadium-shell.is-multiline .stadium-btn { + align-self: flex-end; + margin-top: 0; +} + .file-input-hidden { display: none; }