From 4581e7c4b84185098c440f90a83f327a3153bf62 Mon Sep 17 00:00:00 2001 From: GCWing Date: Mon, 30 Mar 2026 01:02:16 +0800 Subject: [PATCH] feat(web-ui): theme tokens, nav/flow-chat UI, and tool card refresh - Extend theme presets and ThemeService; add btn-primary tokens and Monaco sync tweaks - NavPanel, SceneBar, skills, context menu, and gallery styling updates - Refactor flow chat tool cards (BaseToolCard, TaskToolDisplay, etc.) and chat input - Add useWorkspaceManagerSync; mermaid editor tokens; i18n and Vite adjustments --- .../GalleryLayout/GalleryLayout.scss | 11 +- .../src/app/components/NavPanel/MainNav.tsx | 7 +- .../src/app/components/NavPanel/NavPanel.scss | 121 +++++-- .../components/NavPanel/NavSearchDialog.scss | 248 +++++++++---- .../components/BranchQuickSwitch.scss | 8 +- .../components/PersistentFooterActions.tsx | 43 ++- .../sections/sessions/SessionsSection.scss | 44 ++- .../workspaces/WorkspaceListSection.scss | 22 +- .../src/app/components/SceneBar/SceneBar.scss | 57 ++- .../TitleBar/NotificationButton.tsx | 24 +- src/web-ui/src/app/scenes/SceneViewport.scss | 4 +- .../app/scenes/profile/views/NurseryView.scss | 3 +- .../src/app/scenes/settings/SettingsNav.scss | 46 ++- .../src/app/scenes/skills/SkillsScene.scss | 20 +- .../scenes/skills/hooks/useInstalledSkills.ts | 4 +- .../app/scenes/skills/hooks/useSkillMarket.ts | 4 +- .../components/Badge/Badge.scss | 2 +- .../components/Button/Button.scss | 15 +- .../components/FilterPill/FilterPill.scss | 10 +- .../components/Markdown/Markdown.scss | 12 +- .../components/Switch/Switch.scss | 18 +- .../component-library/components/Tag/Tag.scss | 6 +- .../src/component-library/preview/main.tsx | 5 +- .../styles/btn-primary-tokens.scss | 21 ++ .../styles/flowchat-markdown-code-vars.scss | 4 +- .../src/flow_chat/components/ChatInput.scss | 49 ++- .../src/flow_chat/components/ChatInput.tsx | 5 +- .../components/ScrollToBottomButton.scss | 59 ++- .../components/ScrollToBottomButton.tsx | 6 +- .../src/flow_chat/components/UserMessage.scss | 9 - .../components/modern/UserMessageItem.scss | 7 - .../flow_chat/tool-cards/BaseToolCard.scss | 117 +++++- .../src/flow_chat/tool-cards/BaseToolCard.tsx | 115 +++++- .../flow_chat/tool-cards/CompactToolCard.scss | 24 ++ .../flow_chat/tool-cards/CompactToolCard.tsx | 10 +- .../tool-cards/ContextCompressionDisplay.scss | 6 - .../tool-cards/ContextCompressionDisplay.tsx | 25 +- .../tool-cards/CreatePlanDisplay.scss | 55 ++- .../tool-cards/CreatePlanDisplay.tsx | 85 +++-- .../tool-cards/FileOperationToolCard.scss | 114 ++++-- .../tool-cards/FileOperationToolCard.tsx | 74 +++- .../tool-cards/GetFileDiffDisplay.scss | 18 - .../tool-cards/GetFileDiffDisplay.tsx | 22 +- .../flow_chat/tool-cards/GitToolDisplay.scss | 20 -- .../flow_chat/tool-cards/GitToolDisplay.tsx | 35 +- .../flow_chat/tool-cards/MCPToolDisplay.scss | 34 +- .../flow_chat/tool-cards/MCPToolDisplay.tsx | 10 +- .../tool-cards/MermaidInteractiveDisplay.tsx | 2 + .../flow_chat/tool-cards/SkillDisplay.scss | 20 -- .../src/flow_chat/tool-cards/SkillDisplay.tsx | 29 +- .../flow_chat/tool-cards/TaskToolDisplay.scss | 340 +++++++++++------- .../flow_chat/tool-cards/TaskToolDisplay.tsx | 243 ++++++++----- .../tool-cards/TerminalToolCard.scss | 10 +- .../flow_chat/tool-cards/TerminalToolCard.tsx | 1 + src/web-ui/src/flow_chat/tool-cards/index.ts | 19 +- .../config/components/AIModelConfig.tsx | 6 +- src/web-ui/src/infrastructure/hooks/index.ts | 1 + .../hooks/useWorkspaceManagerSync.ts | 30 ++ .../infrastructure/theme/core/ThemeService.ts | 38 +- .../theme/integrations/MonacoThemeSync.ts | 12 +- .../theme/presets/china-style-theme.ts | 12 +- .../theme/presets/light-theme.ts | 143 ++++---- .../theme/presets/slate-theme.ts | 115 +++--- .../src/infrastructure/theme/types/index.ts | 8 + src/web-ui/src/locales/en-US/flow-chat.json | 13 +- src/web-ui/src/locales/zh-CN/flow-chat.json | 15 +- .../components/ui/ContextMenu.scss | 204 +++++------ .../providers/SelectionMenuProvider.ts | 35 -- .../tools/mermaid-editor/theme/_tokens.scss | 48 +-- .../mermaid-editor/theme/mermaidTheme.ts | 17 +- src/web-ui/vite.config.ts | 1 + 71 files changed, 1912 insertions(+), 1108 deletions(-) create mode 100644 src/web-ui/src/component-library/styles/btn-primary-tokens.scss create mode 100644 src/web-ui/src/infrastructure/hooks/useWorkspaceManagerSync.ts diff --git a/src/web-ui/src/app/components/GalleryLayout/GalleryLayout.scss b/src/web-ui/src/app/components/GalleryLayout/GalleryLayout.scss index 91d4727a..b669cdfb 100644 --- a/src/web-ui/src/app/components/GalleryLayout/GalleryLayout.scss +++ b/src/web-ui/src/app/components/GalleryLayout/GalleryLayout.scss @@ -1,4 +1,5 @@ @use '../../../component-library/styles/tokens' as *; +@use '../../../component-library/styles/btn-primary-tokens.scss' as btn-primary; $gutter: clamp(40px, 6vw, 80px); $content-max: 1480px; @@ -271,12 +272,14 @@ $content-max: 1480px; font-weight: $font-weight-medium; &--primary { - color: var(--color-text-primary); - background: color-mix(in srgb, var(--color-accent-500) 10%, var(--element-bg-soft)); + @include btn-primary.btn-primary-surface-default; &:hover:not(:disabled) { - background: color-mix(in srgb, var(--color-accent-500) 16%, var(--element-bg-medium)); - color: var(--color-text-primary); + @include btn-primary.btn-primary-surface-hover; + } + + &:active:not(:disabled) { + @include btn-primary.btn-primary-surface-active; } } } diff --git a/src/web-ui/src/app/components/NavPanel/MainNav.tsx b/src/web-ui/src/app/components/NavPanel/MainNav.tsx index f6c85d01..b2c801c9 100644 --- a/src/web-ui/src/app/components/NavPanel/MainNav.tsx +++ b/src/web-ui/src/app/components/NavPanel/MainNav.tsx @@ -411,11 +411,14 @@ const MainNav: React.FC = ({ onClick={() => setSearchOpen(true)} aria-label={t('nav.search.triggerTooltip')} > - + {t('nav.search.triggerPlaceholder')} - ⌘K setSearchOpen(false)} /> diff --git a/src/web-ui/src/app/components/NavPanel/NavPanel.scss b/src/web-ui/src/app/components/NavPanel/NavPanel.scss index 774d6087..0b366f4c 100644 --- a/src/web-ui/src/app/components/NavPanel/NavPanel.scss +++ b/src/web-ui/src/app/components/NavPanel/NavPanel.scss @@ -7,6 +7,7 @@ */ @use '../../../component-library/styles/tokens.scss' as *; +@use '../../../component-library/styles/btn-primary-tokens.scss' as btn-primary; $_nav-width: 240px; // Scene-inner fade: used when switching between different SceneNav components @@ -353,7 +354,7 @@ $_section-header-height: 24px; border: none; border-radius: $size-radius-base 0 0 $size-radius-base; background: var(--element-bg-soft); - color: var(--color-primary); + color: var(--color-text-primary); font-size: 12px; font-weight: 600; cursor: pointer; @@ -417,7 +418,7 @@ $_section-header-height: 24px; border: none; border-radius: 0 $size-radius-base $size-radius-base 0; background: var(--element-bg-soft); - color: var(--color-text-muted); + color: var(--color-text-primary); cursor: pointer; transition: background $motion-fast $easing-standard, color $motion-fast $easing-standard, @@ -430,7 +431,7 @@ $_section-header-height: 24px; &.is-active { background: var(--element-bg-medium); - color: var(--color-primary); + color: var(--color-text-primary); } &:active { transform: translateY(1px); } @@ -490,12 +491,9 @@ $_section-header-height: 24px; &__mode-dropdown-item-icon { flex-shrink: 0; - &.is-code { - color: color-mix(in srgb, var(--color-primary) 75%, var(--color-text-muted)); - } - + &.is-code, &.is-cowork { - color: color-mix(in srgb, var(--color-accent-500) 75%, var(--color-text-muted)); + color: color-mix(in srgb, var(--color-text-secondary) 82%, var(--color-text-muted)); } } @@ -508,7 +506,7 @@ $_section-header-height: 24px; &__mode-dropdown-item-check { flex-shrink: 0; - color: var(--color-primary); + color: var(--color-text-primary); margin-left: auto; } @@ -579,10 +577,10 @@ $_section-header-height: 24px; &__section-label { font-size: 11px; - font-weight: 700; - letter-spacing: 0.06em; + font-weight: 600; + letter-spacing: 0.05em; text-transform: uppercase; - color: var(--color-text-primary); + color: var(--color-text-muted); flex: 1; white-space: nowrap; overflow: hidden; @@ -680,7 +678,7 @@ $_section-header-height: 24px; border: none; border-radius: 10px; background: transparent; - color: var(--color-text-primary); + color: var(--color-text-secondary); cursor: pointer; text-align: left; transition: background $motion-fast $easing-standard, @@ -766,28 +764,45 @@ $_section-header-height: 24px; box-shadow: none; overflow: hidden; transition: transform $motion-fast $easing-standard, - box-shadow $motion-fast $easing-standard; + box-shadow $motion-fast $easing-standard, + filter $motion-fast $easing-standard, + opacity $motion-fast $easing-standard; & + & { margin-left: -8px; } + &:not(.is-active):not(.bitfun-nav-panel__miniapp-bubble--more) { + filter: saturate(0.72); + opacity: 0.9; + } + &:hover { transform: translateY(-2px) scale(1.06); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.24); + filter: saturate(1); + opacity: 1; } &.is-active { + filter: saturate(1); + opacity: 1; box-shadow: 0 8px 18px rgba(0, 0, 0, 0.22), 0 0 0 3px color-mix(in srgb, var(--color-primary) 28%, transparent); } &--more { background: color-mix(in srgb, var(--element-bg-medium) 92%, transparent); - color: var(--color-text-primary); + color: var(--color-text-secondary); font-size: 10px; font-weight: 700; letter-spacing: 0.01em; + filter: none; + opacity: 1; + + &:hover { + color: var(--color-text-primary); + } } } @@ -826,7 +841,7 @@ $_section-header-height: 24px; border: none; border-radius: 4px; background: transparent; - color: var(--color-text-muted); + color: var(--color-text-primary); cursor: pointer; transition: color $motion-fast $easing-standard, background $motion-fast $easing-standard; @@ -1148,12 +1163,12 @@ $_section-header-height: 24px; transform: translateY(-50%); width: 2px; height: 16px; - background: var(--color-primary); + background: var(--btn-primary-bg, var(--color-text-primary)); border-radius: 0 2px 2px 0; } .bitfun-nav-panel__item-icon { - color: var(--color-primary); + color: var(--color-text-primary); opacity: 1; } } @@ -1244,13 +1259,13 @@ $_section-header-height: 24px; height: 22px; margin-left: auto; border-radius: $size-radius-sm; - color: var(--color-text-muted); + color: var(--color-text-primary); cursor: pointer; transition: color $motion-fast $easing-standard, background $motion-fast $easing-standard; &:hover { - color: var(--color-primary); + color: var(--color-text-secondary); background: var(--element-bg-soft); } @@ -1405,6 +1420,13 @@ $_section-header-height: 24px; color: #ca8a04; } +.bitfun-nav-panel__footer .bitfun-notification-btn.bitfun-notification-btn--nav-hover-icon:not(.bitfun-notification-btn--has-progress) { + width: 28px; + height: 28px; + padding: 0; + justify-content: center; +} + .bitfun-nav-panel__footer-btn--icon { display: flex; align-items: center; @@ -1436,6 +1458,48 @@ $_section-header-height: 24px; } } +// Footer icon buttons: default icon fades to alternate on hover / focus-visible +.bitfun-nav-panel__footer-btn-icon-swap { + position: relative; + width: 15px; + height: 15px; + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + + > svg { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + transition: opacity $motion-fast $easing-standard; + } +} + +.bitfun-nav-panel__footer-btn-icon-swap-default { + opacity: 1; +} + +.bitfun-nav-panel__footer-btn-icon-swap-hover { + opacity: 0; +} + +// is-hover-open: multimodal submenu is open but pointer may be over the menu, not the button — keep “hover” icon +.bitfun-nav-panel__footer-btn--icon:hover .bitfun-nav-panel__footer-btn-icon-swap, +.bitfun-nav-panel__footer-btn--icon:focus-visible .bitfun-nav-panel__footer-btn-icon-swap, +.bitfun-nav-panel__footer-btn--icon.is-hover-open .bitfun-nav-panel__footer-btn-icon-swap, +.bitfun-nav-panel__footer .bitfun-notification-btn--nav-hover-icon:hover .bitfun-nav-panel__footer-btn-icon-swap, +.bitfun-nav-panel__footer .bitfun-notification-btn--nav-hover-icon:focus-visible .bitfun-nav-panel__footer-btn-icon-swap { + .bitfun-nav-panel__footer-btn-icon-swap-default { + opacity: 0; + } + + .bitfun-nav-panel__footer-btn-icon-swap-hover { + opacity: 1; + } +} + // ────────────────────────────────────────────── // More-options popup menu // ────────────────────────────────────────────── @@ -1527,7 +1591,7 @@ $_section-header-height: 24px; background: var(--element-bg-soft); .bitfun-nav-panel__footer-multimodal-item-icon { - color: var(--color-primary); + color: var(--color-text-primary); opacity: 1; } } @@ -1761,7 +1825,7 @@ $_section-header-height: 24px; .bitfun-nav-panel__brand-header { display: flex; flex-direction: column; - padding: $size-gap-2 $size-gap-2 $size-gap-1; + padding: 0 $size-gap-2 $size-gap-1; flex-shrink: 0; } @@ -1886,7 +1950,7 @@ $_section-header-height: 24px; &.is-active { background: var(--element-bg-soft); - color: var(--color-primary); + color: var(--color-text-primary); } &--sub { @@ -1945,17 +2009,20 @@ $_section-header-height: 24px; align-items: center; justify-content: center; border-radius: 50%; - background: var(--element-bg-medium); - color: var(--color-text-muted); + @include btn-primary.btn-primary-surface-default; transform: scale(1); transform-origin: center; transition: background $motion-fast $easing-standard, color $motion-fast $easing-standard, + box-shadow $motion-fast $easing-standard, transform $motion-fast $easing-standard; .bitfun-nav-panel__top-action-btn:hover & { - background: var(--element-bg-strong); - color: var(--color-primary); + @include btn-primary.btn-primary-surface-hover; transform: scale(1.07); } + + .bitfun-nav-panel__top-action-btn:active & { + @include btn-primary.btn-primary-surface-active; + } } diff --git a/src/web-ui/src/app/components/NavPanel/NavSearchDialog.scss b/src/web-ui/src/app/components/NavPanel/NavSearchDialog.scss index d6954e2f..5d44e447 100644 --- a/src/web-ui/src/app/components/NavPanel/NavSearchDialog.scss +++ b/src/web-ui/src/app/components/NavPanel/NavSearchDialog.scss @@ -1,73 +1,89 @@ @use '../../../component-library/styles/tokens.scss' as *; -// ── Overlay ────────────────────────────────────────────────────────────────── - .bitfun-nav-search-dialog__overlay { position: fixed; inset: 0; z-index: 600; - background: rgba(0, 0, 0, 0.35); + background: transparent; display: flex; align-items: flex-start; justify-content: center; padding-top: 80px; - animation: bitfun-nav-search-overlay-in 0.12s ease; } -@keyframes bitfun-nav-search-overlay-in { - from { opacity: 0; } - to { opacity: 1; } -} - -// ── Card ───────────────────────────────────────────────────────────────────── +// ── Card — matches .bitfun-scene-viewport surface (--color-bg-scene) .bitfun-nav-search-dialog__card { width: 520px; max-width: calc(100vw - 32px); - background: var(--color-bg-elevated); - border-radius: $size-radius-lg; + background: var(--color-bg-scene); + border-radius: $size-radius-base; + border: 1px solid var(--border-subtle); box-shadow: - 0 8px 32px rgba(0, 0, 0, 0.25), - 0 2px 8px rgba(0, 0, 0, 0.15), - inset 0 0 0 1px var(--border-subtle); + 0 1px 2px rgba(15, 23, 42, 0.05), + 0 12px 32px -10px rgba(15, 23, 42, 0.14); overflow: hidden; display: flex; flex-direction: column; max-height: calc(100vh - 120px); - animation: bitfun-nav-search-card-in 0.14s ease; + animation: bitfun-nav-search-card-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +:root[data-theme-type='light'] .bitfun-nav-search-dialog__card { + border-color: var(--border-medium); +} + +:root[data-theme-type='dark'] .bitfun-nav-search-dialog__card { + box-shadow: + 0 1px 0 color-mix(in srgb, #fff 4%, transparent), + 0 14px 40px -12px rgba(0, 0, 0, 0.55); } @keyframes bitfun-nav-search-card-in { - from { opacity: 0; transform: translateY(-8px) scale(0.98); } - to { opacity: 1; transform: translateY(0) scale(1); } + from { + opacity: 0; + transform: translateY(-7px) scale(0.988); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } } // ── Input row ──────────────────────────────────────────────────────────────── .bitfun-nav-search-dialog__input-row { - padding: $size-gap-3; + padding: $size-gap-2; border-bottom: 1px solid var(--border-subtle); flex-shrink: 0; + background: var(--color-bg-scene); } -// Search component — capsule style matching the nav trigger +// Search component — capsule matches .bitfun-nav-panel__search-trigger .bitfun-nav-search-dialog__search { width: 100%; .search__wrapper { height: 32px; + min-height: 32px; + padding: 0 $size-gap-2; + gap: $size-gap-2; + border: none; border-radius: $size-radius-full; - background: var(--element-bg-soft); + background: var(--color-bg-scene); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-subtle) 65%, transparent); + transition: + background 0.2s ease, + box-shadow 0.2s ease; &:hover { - background: var(--element-bg-medium); - box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 50%, transparent); + background: color-mix(in srgb, var(--color-bg-scene) 88%, var(--element-bg-medium)); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 55%, transparent); } &:focus-within { - background: var(--element-bg-medium); - box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 65%, transparent); + background: color-mix(in srgb, var(--color-bg-scene) 82%, var(--element-bg-medium)); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 68%, transparent); } } @@ -84,32 +100,63 @@ } } +@keyframes bitfun-nav-search-fade-rise { + from { + opacity: 0; + transform: translateY(5px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + // ── Results ────────────────────────────────────────────────────────────────── .bitfun-nav-search-dialog__results { overflow-y: auto; flex: 1; - padding: $size-gap-1 0; + padding: $size-gap-1 $size-gap-2 $size-gap-2; &::-webkit-scrollbar { - width: 4px; + width: 3px; } + &::-webkit-scrollbar-thumb { - background: var(--border-medium); + background: var(--border-subtle); border-radius: 2px; } + + &::-webkit-scrollbar-track { + background: transparent; + } } .bitfun-nav-search-dialog__empty { - padding: $size-gap-4; + padding: $size-gap-4 $size-gap-2; text-align: center; color: var(--color-text-muted); font-size: $font-size-sm; + animation: bitfun-nav-search-fade-rise 0.32s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both; } // ── Groups ─────────────────────────────────────────────────────────────────── .bitfun-nav-search-dialog__group { + animation: bitfun-nav-search-fade-rise 0.34s cubic-bezier(0.22, 1, 0.36, 1) both; + + &:nth-of-type(1) { + animation-delay: 0.04s; + } + + &:nth-of-type(2) { + animation-delay: 0.08s; + } + + &:nth-of-type(3) { + animation-delay: 0.12s; + } + & + & { margin-top: $size-gap-1; border-top: 1px solid var(--border-subtle); @@ -118,13 +165,14 @@ } .bitfun-nav-search-dialog__group-label { - padding: $size-gap-1 $size-gap-3; - font-size: $font-size-xs; - font-weight: 600; + padding: $size-gap-1 $size-gap-1 $size-gap-1 2px; + font-size: 10px; + font-weight: 700; color: var(--color-text-muted); text-transform: uppercase; - letter-spacing: 0.05em; + letter-spacing: 0.06em; user-select: none; + opacity: 0.88; } // ── Result item ────────────────────────────────────────────────────────────── @@ -134,13 +182,14 @@ align-items: center; gap: $size-gap-2; width: 100%; - padding: 5px $size-gap-3; + padding: 6px $size-gap-2; border: none; + border-radius: 4px; background: transparent; cursor: pointer; text-align: left; color: var(--color-text-primary); - transition: background 0.08s ease; + transition: background 0.2s cubic-bezier(0.22, 1, 0.36, 1); &:hover { background: var(--element-bg-soft); @@ -152,10 +201,17 @@ } .bitfun-nav-search-dialog__item-icon { - color: var(--color-text-muted); + color: var(--color-text-primary); display: flex; align-items: center; flex-shrink: 0; + opacity: 0.82; + transition: opacity 0.2s ease; + + .bitfun-nav-search-dialog__item:hover &, + .bitfun-nav-search-dialog__item--active & { + opacity: 1; + } } .bitfun-nav-search-dialog__item-content { @@ -183,6 +239,22 @@ } // ── Trigger button (in NavPanel brand-header) ──────────────────────────────── +// Hover: (C) capsule “breath” via horizontal padding + (A) one-shot icon wiggle on inner span. + +@keyframes bitfun-search-trigger-icon-wiggle { + 0% { + transform: rotate(0deg); + } + 22% { + transform: rotate(-5.5deg); + } + 52% { + transform: rotate(4deg); + } + 100% { + transform: rotate(0deg); + } +} .bitfun-nav-panel__search-trigger { display: flex; @@ -192,37 +264,57 @@ min-height: 32px; padding: 0 $size-gap-2; border: none; - // Capsule shape border-radius: $size-radius-full; - background: var(--element-bg-soft); + background: var(--color-bg-scene); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-subtle) 65%, transparent); cursor: text; - color: var(--color-text-muted); + color: var(--color-text-primary); font-size: $font-size-xs; text-align: left; + box-sizing: border-box; transition: - background 0.15s ease, - box-shadow 0.15s ease, - transform 0.12s ease, - color 0.15s ease; + background 0.2s ease, + box-shadow 0.2s ease, + color 0.2s ease, + padding 0.42s cubic-bezier(0.22, 1, 0.36, 1); &:hover { - background: var(--element-bg-medium); + padding: 0 calc(#{$size-gap-2} + 2px); + background: color-mix(in srgb, var(--color-bg-scene) 88%, var(--element-bg-medium)); box-shadow: - inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 55%, transparent), - 0 2px 8px rgba(0, 0, 0, 0.12), - 0 1px 3px rgba(0, 0, 0, 0.08); - transform: translateY(-1px); - color: var(--color-text-secondary); + inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 55%, transparent); + color: var(--color-text-primary); cursor: text; } &:active { - transform: translateY(0); + padding: 0 calc(#{$size-gap-2} + 1px); box-shadow: - inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 45%, transparent), - 0 1px 3px rgba(0, 0, 0, 0.08); + inset 0 0 0 1px color-mix(in srgb, var(--border-medium) 45%, transparent); + } + + &__icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1); + } + + &:hover &__icon { + transform: translateX(2px); + } + + &__icon-inner { + display: inline-flex; + align-items: center; + justify-content: center; + transform-origin: 50% 62%; + } + + &:hover &__icon-inner { + animation: bitfun-search-trigger-icon-wiggle 0.58s cubic-bezier(0.34, 1.12, 0.52, 1) 1 both; } } @@ -238,19 +330,45 @@ } } -.bitfun-nav-panel__search-trigger__kbd { - flex-shrink: 0; - font-size: 10px; - color: var(--color-text-muted); - background: var(--element-bg-subtle); - border: 1px solid var(--border-subtle); - border-radius: $size-radius-sm; - padding: 1px 5px; - line-height: 1.4; - opacity: 0.6; - transition: opacity 0.15s ease; +@media (prefers-reduced-motion: reduce) { + .bitfun-nav-search-dialog__card, + .bitfun-nav-search-dialog__group, + .bitfun-nav-search-dialog__empty { + animation: none !important; + } - .bitfun-nav-panel__search-trigger:hover & { - opacity: 0.85; + .bitfun-nav-search-dialog__group { + animation-delay: 0s !important; + opacity: 1; + transform: none; + } + + .bitfun-nav-search-dialog__empty { + opacity: 1; + transform: none; + } + + .bitfun-nav-search-dialog__item { + transition: background 0.12s ease; + } + + .bitfun-nav-panel__search-trigger { + transition: + background 0.15s ease, + box-shadow 0.15s ease, + color 0.15s ease; + + &:hover, + &:active { + padding: 0 $size-gap-2; + } + + &:hover .bitfun-nav-panel__search-trigger__icon { + transform: none; + } + + &:hover .bitfun-nav-panel__search-trigger__icon-inner { + animation: none; + } } } diff --git a/src/web-ui/src/app/components/NavPanel/components/BranchQuickSwitch.scss b/src/web-ui/src/app/components/NavPanel/components/BranchQuickSwitch.scss index c2537cc1..bfa45ffc 100644 --- a/src/web-ui/src/app/components/NavPanel/components/BranchQuickSwitch.scss +++ b/src/web-ui/src/app/components/NavPanel/components/BranchQuickSwitch.scss @@ -95,8 +95,8 @@ background: var(--color-accent-100); cursor: default; - .branch-quick-switch__item-icon { color: var(--color-accent-500); } - .branch-quick-switch__item-name { color: var(--color-accent-600); font-weight: 500; } + .branch-quick-switch__item-icon { color: var(--color-text-secondary); } + .branch-quick-switch__item-name { color: var(--color-text-primary); font-weight: 500; } } &--switching { @@ -105,9 +105,9 @@ } } -.branch-quick-switch__item-icon { flex-shrink: 0; color: var(--color-text-muted); } +.branch-quick-switch__item-icon { flex-shrink: 0; color: var(--color-text-primary); } .branch-quick-switch__item-name { flex: 1; font-size: 12px; color: var(--color-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.branch-quick-switch__item-check { flex-shrink: 0; color: var(--color-accent-500); } +.branch-quick-switch__item-check { flex-shrink: 0; color: var(--color-text-primary); } .branch-quick-switch__spinner { animation: branch-quick-switch-spin 1s linear infinite; diff --git a/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx b/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx index d52a3025..0ac90872 100644 --- a/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx +++ b/src/web-ui/src/app/components/NavPanel/components/PersistentFooterActions.tsx @@ -1,5 +1,20 @@ import React, { useState, useCallback, useRef } from 'react'; -import { Settings, Info, MoreVertical, PictureInPicture2, SquareTerminal, Smartphone, Globe, Network, Layers, BarChart3 } from 'lucide-react'; +import { + Settings, + Info, + MoreVertical, + PictureInPicture2, + SquareTerminal, + Terminal, + Smartphone, + Globe, + Network, + Layers, + PanelsTopLeft, + BarChart3, + LineChart, + ChevronUp, +} from 'lucide-react'; import { Tooltip, Modal } from '@/component-library'; import { useI18n } from '@/infrastructure/i18n/hooks/useI18n'; import { useSceneManager } from '../../../hooks/useSceneManager'; @@ -181,7 +196,14 @@ const PersistentFooterActions: React.FC = () => { aria-expanded={menuOpen} onClick={toggleMenu} > - + {menuOpen ? ( +