From 56e66ea477b8693d60518f18a486af91f71a6dec Mon Sep 17 00:00:00 2001 From: GCWing Date: Fri, 13 Feb 2026 17:40:38 +0800 Subject: [PATCH] feat(i18n): session title generation supports user locale - feat(core): generate session titles in user's preferred language - fix(editor): increase diff editor line number width to 4 chars - fix(lsp): scope SVG selector to direct children only - refactor(onboarding): simplify wizard styles and use component library defaults - refactor(dialog): remove redundant styles from AddKnowledgeDialog --- .../src/agentic/session/session_manager.rs | 17 ++- src/crates/core/src/service/mod.rs | 2 +- .../components/OnboardingWizard.scss | 127 +++++------------- .../components/steps/LanguageStep.tsx | 5 +- .../components/InlineDiffPreview.scss | 16 +-- .../components/InlineDiffPreview.tsx | 4 +- .../tools/editor/components/DiffEditor.tsx | 2 +- .../LspPluginList/LspPluginList.scss | 2 +- .../AddKnowledgeDialog.scss | 21 --- 9 files changed, 67 insertions(+), 129 deletions(-) diff --git a/src/crates/core/src/agentic/session/session_manager.rs b/src/crates/core/src/agentic/session/session_manager.rs index f65a7db9..94c9d92c 100644 --- a/src/crates/core/src/agentic/session/session_manager.rs +++ b/src/crates/core/src/agentic/session/session_manager.rs @@ -652,10 +652,23 @@ impl SessionManager { let max_length = max_length.unwrap_or(20); + // Get current user locale for language setting + let user_language = if let Some(service) = crate::service::get_global_i18n_service().await { + service.get_current_locale().await + } else { + crate::service::LocaleId::ZhCN + }; + + let language_instruction = match user_language { + crate::service::LocaleId::ZhCN => "使用简体中文", + crate::service::LocaleId::EnUS => "Use English", + }; + // Construct system prompt let system_prompt = format!( - "You are a professional session title generation assistant. Based on the user's message content, generate a concise and accurate session title.\n\nRequirements:\n- Title should not exceed {} characters\n- Use English\n- Concise and accurate, reflecting the conversation topic\n- Do not add quotes or other decorative symbols\n- Return only the title text, no other content", - max_length + "You are a professional session title generation assistant. Based on the user's message content, generate a concise and accurate session title.\n\nRequirements:\n- Title should not exceed {} characters\n- {}\n- Concise and accurate, reflecting the conversation topic\n- Do not add quotes or other decorative symbols\n- Return only the title text, no other content", + max_length, + language_instruction ); // Truncate message to save tokens (max 200 characters) diff --git a/src/crates/core/src/service/mod.rs b/src/crates/core/src/service/mod.rs index 56ad825c..9caeaf29 100644 --- a/src/crates/core/src/service/mod.rs +++ b/src/crates/core/src/service/mod.rs @@ -29,7 +29,7 @@ pub use diff::{ }; pub use filesystem::{DirectoryStats, FileSystemService, FileSystemServiceFactory}; pub use git::GitService; -pub use i18n::{I18nConfig, I18nService, LocaleId, LocaleMetadata}; +pub use i18n::{get_global_i18n_service, I18nConfig, I18nService, LocaleId, LocaleMetadata}; pub use lsp::LspManager; pub use mcp::MCPService; pub use project_context::{ContextDocumentStatus, ProjectContextConfig, ProjectContextService}; diff --git a/src/web-ui/src/features/onboarding/components/OnboardingWizard.scss b/src/web-ui/src/features/onboarding/components/OnboardingWizard.scss index 56766834..d463c353 100644 --- a/src/web-ui/src/features/onboarding/components/OnboardingWizard.scss +++ b/src/web-ui/src/features/onboarding/components/OnboardingWizard.scss @@ -164,7 +164,7 @@ align-items: center; justify-content: space-between; gap: $size-gap-4; - padding: $size-gap-4 $size-gap-6; + padding: $size-gap-2 $size-gap-3; border-top: 1px dashed var(--border-medium); } @@ -183,11 +183,11 @@ align-items: center; justify-content: center; gap: $size-gap-2; - min-height: 40px; - padding: 8px 16px; - min-width: 100px; + min-height: 32px; + padding: 6px 16px; + min-width: 80px; border: 1px dashed var(--border-medium); - border-radius: var(--size-radius-base, 8px); + border-radius: 4px; background: transparent; color: var(--color-text-secondary); font-size: $font-size-sm; @@ -376,7 +376,7 @@ gap: $size-gap-2; padding: $size-gap-3 $size-gap-6; border: 1px dashed var(--border-medium); - border-radius: $size-radius-base; + border-radius: 4px; background: transparent; color: var(--color-text-secondary); font-size: $font-size-base; @@ -447,9 +447,9 @@ display: flex; flex-direction: column; align-items: center; - font-size: $font-size-2xl; - font-weight: $font-weight-semibold; - color: var(--color-text-primary); + font-size: $font-size-lg; + font-weight: $font-weight-medium; + color: var(--color-text-muted); margin: $size-gap-4 0 $size-gap-6 0; text-align: center; line-height: 1.6; @@ -852,58 +852,9 @@ flex-direction: column; gap: $size-gap-2; - // Adapt component library Select for onboarding (class is .select, not .bitfun-select) + // Use component library default Select styles .select { width: 100%; - - .select__label { - font-size: $font-size-sm; - font-weight: $font-weight-medium; - color: var(--color-text-primary); - margin-bottom: $size-gap-2; - } - - .select__trigger { - min-height: 40px; - padding: 8px 12px; - border: 1px solid var(--border-base, rgba(255, 255, 255, 0.08)); - border-radius: var(--size-radius-base, 8px); - background: var(--element-bg-subtle, rgba(255, 255, 255, 0.04)); - - &:hover:not(.select--disabled &) { - border-color: var(--border-medium, rgba(255, 255, 255, 0.15)); - background: var(--glass-blue-subtle, rgba(96, 165, 250, 0.05)); - } - } - - &.select--open .select__trigger { - border-color: var(--color-accent-500, #60a5fa); - background: var(--element-bg-soft, rgba(255, 255, 255, 0.06)); - box-shadow: 0 0 0 3px var(--color-accent-200, rgba(96, 165, 250, 0.15)); - } - - // Dropdown - tighter corners - .select__dropdown { - border-radius: var(--size-radius-base, 8px); - margin-top: 4px; - } - - // Options list - tighter padding - .select__options { - padding: 4px; - } - - // Option item - tighter gap and padding - .select__option { - padding: 6px 10px; - gap: 8px; - font-size: $font-size-sm; - border-radius: var(--size-radius-sm, 6px); - } - - .select__option-content { - gap: 8px; - } } } @@ -913,16 +864,16 @@ color: var(--color-text-primary); } - // Inputs - match Select sizing + // Inputs - match component library Select sizing &__input { width: 100%; - min-height: 40px; - padding: 8px 12px; - border: 1px solid var(--border-base, rgba(255, 255, 255, 0.08)); - border-radius: var(--size-radius-base, 8px); - background: var(--element-bg-subtle, rgba(255, 255, 255, 0.04)); + min-height: 36px; + padding: 6px 12px; + border: 1px solid var(--border-base, rgba(255, 255, 255, 0.14)); + border-radius: var(--size-radius-sm, 6px); + background: transparent; color: var(--color-text-primary); - font-size: $font-size-sm; + font-size: var(--font-size-sm, 14px); font-family: $font-family-sans; box-sizing: border-box; transition: all $motion-base $easing-standard; @@ -931,16 +882,14 @@ color: var(--color-text-muted); } - &:hover { - border-color: var(--border-medium, rgba(255, 255, 255, 0.15)); - background: var(--glass-blue-subtle, rgba(96, 165, 250, 0.05)); + &:hover:not(:disabled) { + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.05)); + border-color: var(--border-strong, rgba(255, 255, 255, 0.26)); } &:focus { outline: none; border-color: var(--color-accent-500, #60a5fa); - background: var(--element-bg-soft, rgba(255, 255, 255, 0.06)); - box-shadow: 0 0 0 3px var(--color-accent-200, rgba(96, 165, 250, 0.15)); } } @@ -1069,11 +1018,11 @@ width: 100%; min-height: 80px; padding: 8px 12px; - border: 1px solid var(--border-base, rgba(255, 255, 255, 0.08)); - border-radius: var(--size-radius-base, 8px); - background: var(--element-bg-subtle, rgba(255, 255, 255, 0.04)); + border: 1px solid var(--border-base, rgba(255, 255, 255, 0.14)); + border-radius: var(--size-radius-sm, 6px); + background: transparent; color: var(--color-text-primary); - font-size: $font-size-xs; + font-size: var(--font-size-sm, 14px); font-family: monospace; line-height: 1.5; box-sizing: border-box; @@ -1084,16 +1033,14 @@ color: var(--color-text-muted); } - &:hover { - border-color: var(--border-medium, rgba(255, 255, 255, 0.15)); - background: var(--glass-blue-subtle, rgba(96, 165, 250, 0.05)); + &:hover:not(:disabled) { + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.05)); + border-color: var(--border-strong, rgba(255, 255, 255, 0.26)); } &:focus { outline: none; border-color: var(--color-accent-500, #60a5fa); - background: var(--element-bg-soft, rgba(255, 255, 255, 0.06)); - box-shadow: 0 0 0 3px var(--color-accent-200, rgba(96, 165, 250, 0.15)); } } @@ -1121,13 +1068,13 @@ align-items: center; justify-content: center; gap: $size-gap-2; - min-height: 40px; - padding: 8px 12px; - border: 1px dashed var(--border-medium); - border-radius: var(--size-radius-base, 8px); + min-height: 36px; + padding: 6px 12px; + border: 1px solid var(--border-base, rgba(255, 255, 255, 0.14)); + border-radius: var(--size-radius-sm, 6px); background: transparent; color: var(--color-text-secondary); - font-size: $font-size-sm; + font-size: var(--font-size-sm, 14px); font-weight: $font-weight-medium; font-family: $font-family-sans; cursor: pointer; @@ -1135,8 +1082,8 @@ transition: all $motion-base $easing-standard; &:hover:not(:disabled) { - border-style: solid; - background: var(--element-bg-subtle); + background: var(--element-bg-subtle, rgba(255, 255, 255, 0.05)); + border-color: var(--border-strong, rgba(255, 255, 255, 0.26)); color: var(--color-text-primary); } @@ -1333,10 +1280,10 @@ display: flex; align-items: center; justify-content: center; - min-height: 40px; - padding: 8px 16px; + min-height: 32px; + padding: 6px 16px; border: 1px dashed var(--border-medium); - border-radius: var(--size-radius-base, 8px); + border-radius: 4px; background: transparent; color: var(--color-text-secondary); font-size: $font-size-sm; diff --git a/src/web-ui/src/features/onboarding/components/steps/LanguageStep.tsx b/src/web-ui/src/features/onboarding/components/steps/LanguageStep.tsx index c9abc5e4..85bc90fa 100644 --- a/src/web-ui/src/features/onboarding/components/steps/LanguageStep.tsx +++ b/src/web-ui/src/features/onboarding/components/steps/LanguageStep.tsx @@ -34,10 +34,9 @@ export const LanguageStep: React.FC = ({ BitFun - {/* Subtitle - always show both languages */} + {/* Subtitle - both languages on one line with / separator */}
- 选择界面语言 - Choose Your Language + 选择界面语言 / Choose Your Language
{/* Language options */} diff --git a/src/web-ui/src/flow_chat/components/InlineDiffPreview.scss b/src/web-ui/src/flow_chat/components/InlineDiffPreview.scss index fe6f6e51..9c8b56be 100644 --- a/src/web-ui/src/flow_chat/components/InlineDiffPreview.scss +++ b/src/web-ui/src/flow_chat/components/InlineDiffPreview.scss @@ -140,18 +140,18 @@ background: var(--color-bg-secondary, rgba(255, 255, 255, 0.03)); user-select: none; border-right: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.05)); - + &--single { padding: 0 4px; gap: 0; - + .diff-line__num { min-width: 24px; padding: 0 4px; } } } - + &__num { min-width: 32px; padding: 0 6px; @@ -159,17 +159,17 @@ color: var(--color-text-muted, #666); opacity: 0.6; font-size: 11px; - + &--original { border-right: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.08)); padding-right: 8px; } - + &--modified { padding-left: 8px; } } - + &__prefix { display: flex; align-items: center; @@ -245,10 +245,10 @@ background: rgba(0, 0, 0, 0.03); border-right-color: rgba(0, 0, 0, 0.08); } - + .diff-line__num { color: #6e7781; - + &--original { border-right-color: rgba(0, 0, 0, 0.1); } diff --git a/src/web-ui/src/flow_chat/components/InlineDiffPreview.tsx b/src/web-ui/src/flow_chat/components/InlineDiffPreview.tsx index 483c7064..2dffafa8 100644 --- a/src/web-ui/src/flow_chat/components/InlineDiffPreview.tsx +++ b/src/web-ui/src/flow_chat/components/InlineDiffPreview.tsx @@ -284,9 +284,9 @@ export const InlineDiffPreview: React.FC = memo(({ const origNum = line.originalLineNumber ?? ''; const modNum = line.modifiedLineNumber ?? ''; - + const prefix = line.type === 'added' ? '+' : line.type === 'removed' ? '-' : ' '; - + return (
= ({ glyphMargin: false, folding: false, - lineNumbersMinChars: 2, + lineNumbersMinChars: 4, lineDecorationsWidth: 10, padding: { top: 4, bottom: 4 }, diff --git a/src/web-ui/src/tools/lsp/components/LspPluginList/LspPluginList.scss b/src/web-ui/src/tools/lsp/components/LspPluginList/LspPluginList.scss index 6d5bccd2..6cd27e39 100644 --- a/src/web-ui/src/tools/lsp/components/LspPluginList/LspPluginList.scss +++ b/src/web-ui/src/tools/lsp/components/LspPluginList/LspPluginList.scss @@ -345,7 +345,7 @@ padding: $size-gap-5; gap: $size-gap-3; - svg { + > svg { width: 48px; height: 48px; } diff --git a/src/web-ui/src/tools/project-context/components/AddKnowledgeDialog/AddKnowledgeDialog.scss b/src/web-ui/src/tools/project-context/components/AddKnowledgeDialog/AddKnowledgeDialog.scss index db402399..6c1ba220 100644 --- a/src/web-ui/src/tools/project-context/components/AddKnowledgeDialog/AddKnowledgeDialog.scss +++ b/src/web-ui/src/tools/project-context/components/AddKnowledgeDialog/AddKnowledgeDialog.scss @@ -17,29 +17,8 @@ // ==================== Dialog ==================== .bitfun-add-knowledge-dialog { position: relative; - background: var(--color-bg-primary); - border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1)); - border-radius: 10px; - width: 420px; - max-width: calc(100vw - 48px); - max-height: 85vh; display: flex; flex-direction: column; - box-shadow: - 0 20px 60px rgba(0, 0, 0, 0.35), - 0 0 0 1px rgba(255, 255, 255, 0.04); - animation: bitfun-dialog-enter 0.2s cubic-bezier(0.16, 1, 0.3, 1); - - @keyframes bitfun-dialog-enter { - from { - opacity: 0; - transform: translateY(16px) scale(0.98); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } - } // ==================== Header ==================== &__header {