From 8dd28f69457834972c9e198938ed528bc6df0b9e Mon Sep 17 00:00:00 2001 From: GCWing Date: Mon, 23 Mar 2026 22:53:27 +0800 Subject: [PATCH] fix(web-ui): refine flow chat scroll bar, tool cards, and AI rules config UI --- .../miniapps/components/MiniAppCard.scss | 1 + .../components/ScrollToLatestBar.scss | 87 ++++++++----------- .../components/ScrollToLatestBar.tsx | 8 +- .../flow-chat-manager/MessageModule.ts | 13 +-- .../flow_chat/tool-cards/BaseToolCard.scss | 8 +- .../src/flow_chat/tool-cards/BaseToolCard.tsx | 2 +- .../tool-cards/FileOperationToolCard.scss | 14 +++ .../tool-cards/FileOperationToolCard.tsx | 2 +- .../components/AIRulesMemoryConfig.scss | 18 ---- .../config/components/AIRulesMemoryConfig.tsx | 8 +- 10 files changed, 75 insertions(+), 86 deletions(-) diff --git a/src/web-ui/src/app/scenes/miniapps/components/MiniAppCard.scss b/src/web-ui/src/app/scenes/miniapps/components/MiniAppCard.scss index 7a5512cc..81c27715 100644 --- a/src/web-ui/src/app/scenes/miniapps/components/MiniAppCard.scss +++ b/src/web-ui/src/app/scenes/miniapps/components/MiniAppCard.scss @@ -159,6 +159,7 @@ gap: 4px; margin-top: auto; padding-top: $size-gap-2; + margin-bottom: $size-gap-2; } &__tag { diff --git a/src/web-ui/src/flow_chat/components/ScrollToLatestBar.scss b/src/web-ui/src/flow_chat/components/ScrollToLatestBar.scss index e7883306..4e7040d5 100644 --- a/src/web-ui/src/flow_chat/components/ScrollToLatestBar.scss +++ b/src/web-ui/src/flow_chat/components/ScrollToLatestBar.scss @@ -30,8 +30,7 @@ // Keep content layer within visible area .scroll-to-latest-bar__content { - top: auto; - bottom: 4px; + bottom: 14px; } } @@ -61,9 +60,10 @@ } // ========== Divider content layer ========== + // Default: sit just above ChatInput (~80px tall + 16px bottom gap + 14px clearance) &__content { position: absolute; - top: 4px; + bottom: 110px; left: 0; right: 0; pointer-events: auto; @@ -71,57 +71,47 @@ display: flex; align-items: center; justify-content: center; - gap: 12px; - padding: 0 24px; - transition: opacity 0.2s ease; + transition: bottom 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease; } - // ========== Divider ========== - &__line { - flex: 1; - max-width: 120px; - height: 1px; - background: linear-gradient( - 90deg, - transparent 0%, - rgba(96, 165, 250, 0.35) 50%, - transparent 100% - ); + // ========== Content position: input collapsed ========== + &--input-collapsed &__content { + // Pill ~42px + 16px gap + 14px clearance + bottom: 72px; } - // ========== Hint text ========== - &__text { - font-size: 11px; - font-weight: 400; - color: rgba(96, 165, 250, 0.6); - white-space: nowrap; - letter-spacing: 0.05em; - user-select: none; + // ========== Circle arrow button ========== + &__btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + border: 1.5px solid var(--border-base); + background: var(--color-bg-scene); + color: var(--color-text-muted); + cursor: pointer; + pointer-events: none; + padding: 0; - transition: color 0.2s ease; + transition: border-color 0.2s ease, color 0.2s ease, transform 0.15s ease; } // ========== Hover state ========== &:hover { - .scroll-to-latest-bar__text { - color: rgba(96, 165, 250, 0.85); - } - - .scroll-to-latest-bar__line { - background: linear-gradient( - 90deg, - transparent 0%, - rgba(96, 165, 250, 0.5) 50%, - transparent 100% - ); + .scroll-to-latest-bar__btn { + border-color: var(--border-medium); + color: var(--color-text-primary); + transform: translateY(1px); } } // ========== Active state ========== &:active { - .scroll-to-latest-bar__text { - color: rgba(96, 165, 250, 0.7); + .scroll-to-latest-bar__btn { + transform: translateY(2px); } } @@ -129,8 +119,9 @@ &:focus-visible { outline: none; - .scroll-to-latest-bar__text { - color: rgba(96, 165, 250, 0.9); + .scroll-to-latest-bar__btn { + border-color: var(--border-strong); + color: var(--color-text-primary); } } } @@ -144,17 +135,9 @@ height: 70px; } - &__content { - gap: 10px; - padding: 0 16px; - } - - &__line { - max-width: 80px; - } - - &__text { - font-size: 10px; + &__btn { + width: 26px; + height: 26px; } } } diff --git a/src/web-ui/src/flow_chat/components/ScrollToLatestBar.tsx b/src/web-ui/src/flow_chat/components/ScrollToLatestBar.tsx index 0b4120c4..6e146c9c 100644 --- a/src/web-ui/src/flow_chat/components/ScrollToLatestBar.tsx +++ b/src/web-ui/src/flow_chat/components/ScrollToLatestBar.tsx @@ -63,9 +63,11 @@ export const ScrollToLatestBar: React.FC = ({
- - {t('scroll.clickToLatest')} - +
); diff --git a/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts b/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts index 5bb69af3..00e5048f 100644 --- a/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts +++ b/src/web-ui/src/flow_chat/services/flow-chat-manager/MessageModule.ts @@ -168,18 +168,19 @@ export async function sendMessage( }); const currentAgentType = agentType || session.mode || 'agentic'; - await syncSessionModelSelection(context, sessionId, currentAgentType); - const updatedSession = context.flowChatStore.getState().sessions.get(sessionId); - if (!updatedSession) { - throw new Error(`Session lost after adding dialog turn: ${sessionId}`); - } - try { await ensureBackendSession(context, sessionId); } catch (createError: any) { log.warn('Backend session create/restore failed', { sessionId: sessionId, error: createError }); } + + await syncSessionModelSelection(context, sessionId, currentAgentType); + + const updatedSession = context.flowChatStore.getState().sessions.get(sessionId); + if (!updatedSession) { + throw new Error(`Session lost after adding dialog turn: ${sessionId}`); + } context.contentBuffers.set(sessionId, new Map()); context.activeTextItems.set(sessionId, new Map()); diff --git a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss index f960ba55..258b72e0 100644 --- a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss @@ -29,7 +29,9 @@ inset 0 2px 4px rgba(0, 0, 0, 0.4); } - &.has-expanded { + /* Divider when body below header: success expanded panel or failed error panel */ + &:has(> .base-tool-card-expanded), + &:has(> .base-tool-card-error) { .base-tool-card-header::after { content: ''; position: absolute; @@ -38,6 +40,8 @@ right: 0; height: 1px; background: var(--border-base); + pointer-events: none; + z-index: 2; } } @@ -227,6 +231,8 @@ background: none !important; border: none !important; box-shadow: none !important; + /* Outside the clickable .base-tool-card row; do not inherit pointer from wrapper */ + cursor: default; .error-content { display: flex; diff --git a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.tsx b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.tsx index d21fb95a..98497f56 100644 --- a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.tsx +++ b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.tsx @@ -49,7 +49,7 @@ export const BaseToolCard: React.FC = ({ status !== 'error'; return ( -
+
= ({ } if (isFailed) { - setIsErrorExpanded(!isErrorExpanded); + setIsErrorExpanded(prev => !prev); return; } diff --git a/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.scss b/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.scss index 0eb6068e..6bbde327 100644 --- a/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.scss +++ b/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.scss @@ -179,19 +179,6 @@ gap: $size-gap-2; margin-top: $size-gap-3; } - - &__empty-row { - display: flex; - align-items: center; - justify-content: center; - gap: $size-gap-3; - padding: $size-gap-6 $size-gap-4; - color: var(--color-text-muted); - font-size: $font-size-sm; - p { - margin: 0; - } - } } @keyframes bitfun-ai-rules-config-slide-down { @@ -221,11 +208,6 @@ &__form-body { gap: $size-gap-2; } - &__empty-row { - flex-direction: column; - gap: $size-gap-2; - padding: $size-gap-4; - } &__action-btn { width: 24px; height: 24px; diff --git a/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.tsx b/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.tsx index 7af4ba1c..87eb4485 100644 --- a/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.tsx +++ b/src/web-ui/src/infrastructure/config/components/AIRulesMemoryConfig.tsx @@ -230,10 +230,10 @@ function RulesPanel() { )} {!currentRules.isLoading && rules.length === 0 && ( -
-

{t('list.empty.description')}

-
)}