-
Notifications
You must be signed in to change notification settings - Fork 625
Fix appbar style on windows and linux #989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughIntroduces Windows-specific window material (mica) in shell creation. Expands OS detection in App.vue and adjusts AppBar background behavior. Updates CSS variable for window background opacity. Applies multiple UI/style tweaks across message views, removes a sidebar toggle, refactors ModelChooser layout, and simplifies PromptInput web search UI and context length calculation. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant PromptInput as PromptInput UI
participant Store as Stores (Settings/Files)
participant Emitter as Event Bus
User->>PromptInput: Click "Web Search" Button
PromptInput->>Store: Toggle webSearch flag
Note right of PromptInput: UI updates class (text-primary when enabled)
User->>PromptInput: Type text / select files
PromptInput->>Store: Read input text tokens
PromptInput->>Store: Read selectedFiles tokens
PromptInput->>PromptInput: Compute currentContextLength = text + files
User->>PromptInput: Choose model
PromptInput->>Emitter: emit("update:model", modelId)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/renderer/src/components/mcpToolsList.vue (2)
24-24: Replace Chinese comments with English.The coding guidelines require all logs and comments to be in English. Please translate the Chinese comments throughout this file.
As per coding guidelines.
Example translations:
- Line 24:
// 计算属性→// Computed properties- Line 31:
// 处理MCP开关状态变化→// Handle MCP enabled state change- Line 40:
// 获取每个mcp服务的可用工具数量→// Get enabled tool count by server- Line 50:
// 获取可用工具总数→// Get total enabled tool count- Line 60:
// 处理单个服务开关状态变化→// Handle individual server toggle- Line 65:
// 处理单个工具开关状态变化→// Handle individual tool enabled state change- Line 74:
// 获取单个工具开关状态→// Get individual tool enabled state- Line 79:
// 获取内置服务器的本地化名称和描述→// Get localized server name and description- Line 83:
// 生命周期钩子→// Lifecycle hooksAlso applies to: 31-31, 40-40, 50-50, 60-60, 65-65, 74-74, 79-79, 83-83
152-157: Remove commented-out code.The commented-out loading and error handling code is redundant since the error handling is already implemented at lines 158-160. Removing dead code improves maintainability.
Apply this diff to remove the commented-out code:
- <!-- <div v-else-if="isLoading" class="flex justify-center items-center py-8"> - <Icon icon="lucide:loader" class="w-6 h-6 animate-spin" /> - </div> - <div v-else-if="isError" class="p-2 text-sm text-destructive"> - {{ t('mcp.tools.loadError') }}: {{ errorMessage }} - </div> --> <div v-else-if="isError" class="p-2 text-sm text-destructive">src/renderer/src/components/message/MessageItemUser.vue (2)
122-125: Eliminateanytype assertions for strict typing.Casting
originalContent.valuetoanyviolates the strict TypeScript guidelines. Properly type the ref instead.As per coding guidelines.
Apply this diff to use proper typing:
-const originalContent = ref(null) +const originalContent = ref<HTMLElement | null>(null)Then remove the
anycasts and eslint-disable comments:- // eslint-disable-next-line @typescript-eslint/no-explicit-any - originalContentHeight.value = (originalContent.value as any).offsetHeight - // eslint-disable-next-line @typescript-eslint/no-explicit-any - originalContentWidth.value = (originalContent.value as any).offsetWidth + originalContentHeight.value = originalContent.value?.offsetHeight ?? 0 + originalContentWidth.value = originalContent.value?.offsetWidth ?? 0Repeat the same pattern for lines 131-134.
Also applies to: 131-134
17-17: Replace hardcoded fallback with i18n translation
In MessageItemUser.vue (line 17), change:name="message.name ?? 'user'"to something like
:name="message.name ?? t('message.fallbackUser')"
🧹 Nitpick comments (4)
src/renderer/src/components/prompt-input/ModelChooser.vue (1)
3-3: Consider extracting or splitting long Tailwind class strings.Several template elements have very long class strings that exceed readability thresholds. While common with Tailwind, these could be improved by:
- Splitting across multiple lines
- Extracting to computed class properties
- Using
@applyin a scoped style section (though this reduces Tailwind's utility-first benefits)Example for line 27 (split across lines):
<Button v-for="model in provider.models" :key="`${provider.id}-${model.id}`" type="button" variant="outline" - class="group w-full justify-start gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition data-[selected=true]:border-primary data-[selected=true]:bg-primary/10 data-[selected=true]:text-foreground/90 dark:data-[selected=true]:bg-primary/15" + class=" + group w-full justify-start gap-3 rounded-lg px-3 py-2 + text-left text-sm font-medium transition + data-[selected=true]:border-primary data-[selected=true]:bg-primary/10 + data-[selected=true]:text-foreground/90 + dark:data-[selected=true]:bg-primary/15 + " role="option"Also applies to: 17-17, 27-27, 34-34
src/renderer/src/components/message/MessageItemUser.vue (2)
60-72: Remove commented-out code.Dead code clutters the codebase. If these features are no longer needed, remove them entirely. If they might be re-enabled later, track them in an issue instead.
Apply this diff to remove the commented code:
- <!-- <div - v-else-if="message.content.continue" - class="text-sm whitespace-pre-wrap break-all flex flex-row flex-wrap items-center gap-2" - > - <Icon icon="lucide:info" class="w-4 h-4" /> - <span>用户选择继续对话</span> - </div> - --> - <!-- disable for now --> - <!-- <div class="flex flex-row gap-1.5 text-xs text-muted-foreground"> - <span v-if="message.content.search">联网搜索</span> - <span v-if="message.content.reasoning_content">深度思考</span> - </div> -->
202-202: Replace console.log with proper logging.For production code, consider using a proper logging utility instead of
console.log, or remove if this is debug-only code.If this logging is needed, consider creating a logger utility. Otherwise, remove it:
- console.log('Mention clicked:', block) + // TODO: Implement mention click handling logicsrc/renderer/shell/App.vue (1)
2-2: Consider clearer naming and verify OS detection consistency.The variable name
isWinMacOS(line 14) is a bit ambiguous—it could be read as "is Windows Mac OS". Consider renaming to something clearer likeuseNativeWindowChromeorisWindowsOrMacOS.Additionally, ensure OS detection is consistent across components. Note that
src/renderer/shell/components/AppBar.vue(line 472) usesisMacOSand only checks for'darwin', not'win32'. Verify whether AppBar should also detect Windows for consistent styling behavior.Also applies to: 14-14, 19-19
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/main/presenter/windowPresenter/index.ts(1 hunks)src/renderer/shell/App.vue(2 hunks)src/renderer/shell/components/AppBar.vue(2 hunks)src/renderer/src/assets/style.css(3 hunks)src/renderer/src/components/NewThread.vue(0 hunks)src/renderer/src/components/mcpToolsList.vue(2 hunks)src/renderer/src/components/message/MessageItemUser.vue(3 hunks)src/renderer/src/components/message/MessageList.vue(1 hunks)src/renderer/src/components/message/MessageToolbar.vue(1 hunks)src/renderer/src/components/prompt-input/ModelChooser.vue(1 hunks)src/renderer/src/components/prompt-input/PromptInput.vue(3 hunks)
💤 Files with no reviewable changes (1)
- src/renderer/src/components/NewThread.vue
🧰 Additional context used
📓 Path-based instructions (23)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/assets/style.csssrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/main/presenter/windowPresenter/index.tssrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/main/presenter/windowPresenter/index.tssrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Put application code for the Vue app under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/assets/style.csssrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings in the renderer must use vue-i18n keys defined in src/renderer/src/i18n
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
**/*.{js,jsx,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting: single quotes, no semicolons, max width 100
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/main/presenter/windowPresenter/index.tssrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue components in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/message/MessageList.vuesrc/renderer/src/components/message/MessageToolbar.vuesrc/renderer/shell/App.vuesrc/renderer/src/components/mcpToolsList.vuesrc/renderer/src/components/message/MessageItemUser.vuesrc/renderer/src/components/prompt-input/ModelChooser.vuesrc/renderer/shell/components/AppBar.vuesrc/renderer/src/components/prompt-input/PromptInput.vue
src/renderer/shell/**
📄 CodeRabbit inference engine (AGENTS.md)
Keep shell UI code in src/renderer/shell/
Files:
src/renderer/shell/App.vuesrc/renderer/shell/components/AppBar.vue
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
**/*.{js,jsx,ts,tsx}: Use OxLint for JS/TS code; pre-commit hooks run lint-staged and typecheck
Use camelCase for variables and functions
Use PascalCase for types and classes
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/windowPresenter/index.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/windowPresenter/index.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/windowPresenter/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/windowPresenter/index.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/windowPresenter/index.ts
src/main/**
📄 CodeRabbit inference engine (AGENTS.md)
Place all Electron main-process code under src/main/
Files:
src/main/presenter/windowPresenter/index.ts
src/main/presenter/**
📄 CodeRabbit inference engine (AGENTS.md)
src/main/presenter/**: Organize main-process presenters under src/main/presenter/ (Window/Tab/Thread/Mcp/Config/LLMProvider)
Follow the Presenter pattern for main-process modules
Files:
src/main/presenter/windowPresenter/index.ts
🧠 Learnings (1)
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Import Icon component from Iconify/Vue.
Applied to files:
src/renderer/src/components/prompt-input/PromptInput.vue
🔇 Additional comments (11)
src/renderer/src/components/message/MessageList.vue (1)
10-10: Padding tweak looks good.The added
pt-4gives the message list breathing room without affecting functionality. 👍src/renderer/src/components/mcpToolsList.vue (1)
102-103: Verify visual feedback for MCP enabled/disabled states.The simplified styling aligns with the PR's cross-platform consistency objective. However, the visual distinction between enabled and disabled states has been reduced:
- The button now only applies
text-primarywhen enabled (line 103), removing the previous complex conditional styling- The count display no longer has dynamic coloring based on MCP state (lines 115-117)
Please verify that users can still easily distinguish the enabled vs disabled state with the simplified styling, especially across Windows and Linux.
Also applies to: 115-117
src/renderer/src/components/prompt-input/ModelChooser.vue (1)
60-150: Script logic looks solid.The Composition API setup, TypeScript typing, store integration, and computed properties are all well-implemented. The filtering logic is clear and efficient, and the component properly uses Pinia stores and vue-i18n as per coding guidelines.
src/renderer/src/components/message/MessageItemUser.vue (2)
5-5: LGTM: Intentional padding adjustment.The removal of vertical padding (
py-4) aligns with the PR's UI refinements for Windows and Linux appbar styling.
21-21: LGTM: Consistent background styling.The shift from
blue-50tobg-mutedfor both the message content and textarea creates a unified, neutral appearance for user messages. This aligns with the PR's cross-platform styling improvements.Also applies to: 38-38
src/renderer/src/components/message/MessageToolbar.vue (1)
5-5: LGTM!The height reduction from
h-8toh-7is a reasonable UI refinement that aligns with the broader styling updates in this PR.src/renderer/src/components/prompt-input/PromptInput.vue (2)
68-79: LGTM! Simplified web search UI.The refactor from a complex Select-based UI to a simple Button with conditional styling reduces complexity while maintaining functionality. The visual feedback via
text-primarywhen web search is enabled is clear and intuitive.
367-374: Good fix: Context length now includes file tokens.The updated
currentContextLengthcomputation now correctly accounts for tokens fromselectedFiles, which was previously missing. This ensures accurate context length calculations when files are attached.src/renderer/shell/components/AppBar.vue (2)
10-10: LGTM! z-10 elevates the border.Adding
z-10ensures the border appears above overlapping content, which is a good fix for visual layering.
108-108: LGTM! Improved close button UX.The updated hover state (
hover:bg-red-700/80 hover:text-white) provides clearer visual feedback that the close button is destructive, which is a standard UX pattern.src/renderer/src/assets/style.css (1)
123-123: LGTM! Window background opacity adjustments.The updated
--bg-window-backgroundvalues across themes support the Windows/macOS native chrome styling introduced in this PR:
- Light mode: increased from 10% to 50% opacity for better visibility
- Dark mode: unified to 50% opacity across different dark theme contexts for consistency
These changes align with the Windows 'mica' material and dynamic background behavior in App.vue and AppBar.vue.
Also applies to: 181-181, 257-257
| titleBarStyle: 'hiddenInset', // macOS 风格标题栏 | ||
| transparent: process.platform === 'darwin', // macOS 标题栏透明 | ||
| vibrancy: process.platform === 'darwin' ? 'hud' : undefined, // macOS 磨砂效果 | ||
| backgroundMaterial: process.platform === 'win32' ? 'mica' : undefined, // Windows 11 材质效果 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use English for comments.
The comment contains Chinese text, which violates the coding guidelines.
As per coding guidelines
Apply this diff to use English:
- backgroundMaterial: process.platform === 'win32' ? 'mica' : undefined, // Windows 11 材质效果
+ backgroundMaterial: process.platform === 'win32' ? 'mica' : undefined, // Windows 11 mica material effect📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| backgroundMaterial: process.platform === 'win32' ? 'mica' : undefined, // Windows 11 材质效果 | |
| backgroundMaterial: process.platform === 'win32' ? 'mica' : undefined, // Windows 11 mica material effect |
🤖 Prompt for AI Agents
In src/main/presenter/windowPresenter/index.ts around line 657, the inline
comment contains Chinese text; replace it with an English comment that conveys
the same meaning (e.g., "Windows 11 material effect" or "Windows 11 acrylic/mica
material effect") so the codebase follows the English-only comment guideline;
update only the comment text and preserve the code behavior.
| class="flex flex-row h-9 min-h-9 border border-b-0 border-window-inner-border box-border rounded-t-[10px] relative overflow-hidden" | ||
| :class="[ | ||
| !isFullscreened && isMacOS ? '' : ' rounded-t-none', | ||
| isMacOS ? 'bg-window-background' : 'bg-window-background/10' | ||
| ]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Verify Windows background styling consistency.
The AppBar applies bg-window-background only when isMacOS is true, and bg-window-background/10 otherwise. However, src/renderer/shell/App.vue treats both Windows and macOS the same (via isWinMacOS).
Since Windows now uses the 'mica' material (per windowPresenter/index.ts line 657), verify whether AppBar should also apply bg-window-background (not /10) for Windows to ensure visual consistency with the mica effect.
Run the following script to check how Windows is handled in both files:
🏁 Script executed:
#!/bin/bash
# Check OS detection patterns in App.vue and AppBar.vue
echo "=== App.vue OS detection ==="
rg -n "isWinMacOS|darwin|win32" src/renderer/shell/App.vue
echo ""
echo "=== AppBar.vue OS detection ==="
rg -n "isMacOS|darwin|win32" src/renderer/shell/components/AppBar.vue
echo ""
echo "=== Background styling usage ==="
rg -n "bg-window-background" src/renderer/shell/Length of output: 895
Use full background on Windows in AppBar.vue
Replace the isMacOS check with a combined darwin || win32 condition (e.g. isWinMacOS) so Windows also applies bg-window-background instead of bg-window-background/10.
🤖 Prompt for AI Agents
In src/renderer/shell/components/AppBar.vue around lines 3 to 7, the template
uses only isMacOS to decide the background class so Windows still gets
bg-window-background/10; add a combined platform check (e.g. isWinMacOS =
isMacOS || isWin32 or check process.platform === 'darwin' || process.platform
=== 'win32' where platform flags are defined) and replace the two isMacOS checks
with this new isWinMacOS so both macOS and Windows use bg-window-background
while other platforms keep bg-window-background/10; ensure the new flag is
defined/imported in the component script and used in the same two class
locations.
| class="flex flex-row-reverse group py-4 pl-11 gap-2 user-message-item" | ||
| class="flex flex-row-reverse group pl-11 gap-2 user-message-item" | ||
| > | ||
| <!-- 头像 --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace Chinese comments with English.
Comments must be in English per coding guidelines.
As per coding guidelines.
Apply this diff to translate the comments:
- <!-- 头像 -->
+ <!-- Avatar -->- <!-- 消息内容 -->
+ <!-- Message content -->- // 处理 mention 点击事件,可以根据需要实现具体逻辑
+ // Handle mention click event, implement specific logic as neededAlso applies to: 20-20, 201-201
🤖 Prompt for AI Agents
In src/renderer/src/components/message/MessageItemUser.vue around lines 7, 20
and 201, several inline comments are written in Chinese; replace each Chinese
comment with an equivalent English comment per coding guidelines (e.g.,
translate "头像" to "Avatar" and other Chinese phrases to clear English
descriptions) ensuring wording remains concise and context-appropriate and
preserving comment placement and intent.
| <ScrollArea class="h-72 pr-2"> | ||
| <div class="flex flex-col gap-5"> | ||
| <div v-for="provider in filteredProviders" :key="provider.id" class="flex flex-col gap-2"> | ||
| <Badge | ||
| variant="outline" | ||
| class="w-fit uppercase tracking-[0.18em] text-[10px] font-semibold text-muted-foreground" | ||
| > | ||
| <div | ||
| class="flex h-7 w-7 items-center justify-center rounded-lg border border-border/60 bg-white/80 text-[11px] font-semibold uppercase text-muted-foreground/80 transition-all duration-200 group-data-[selected=true]:border-transparent group-data-[selected=true]:bg-primary group-data-[selected=true]:text-white/90 dark:border-white/15 dark:bg-white/[0.08] dark:group-data-[selected=true]:bg-[#3c82ff]" | ||
| {{ provider.name }} | ||
| </Badge> | ||
| <div class="flex flex-col gap-1.5" role="listbox" aria-orientation="vertical"> | ||
| <Button | ||
| v-for="model in provider.models" | ||
| :key="`${provider.id}-${model.id}`" | ||
| type="button" | ||
| variant="outline" | ||
| class="group w-full justify-start gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition data-[selected=true]:border-primary data-[selected=true]:bg-primary/10 data-[selected=true]:text-foreground/90 dark:data-[selected=true]:bg-primary/15" | ||
| role="option" | ||
| :aria-selected="isSelected(provider.id, model.id)" | ||
| :data-selected="isSelected(provider.id, model.id)" | ||
| @click="handleModelSelect(provider.id, model)" | ||
| > | ||
| <ModelIcon | ||
| class="h-4 w-4 shrink-0 opacity-70 transition duration-200 group-hover:opacity-100 group-data-[selected=true]:opacity-100" | ||
| :model-id="provider.id" | ||
| :is-dark="themeStore.isDark" | ||
| <div | ||
| class="flex h-7 w-7 items-center justify-center rounded-md border border-border bg-muted/40 text-[11px] font-semibold uppercase text-muted-foreground transition group-data-[selected=true]:border-primary group-data-[selected=true]:bg-primary/20 group-data-[selected=true]:text-primary" | ||
| > | ||
| <ModelIcon | ||
| class="h-4 w-4 shrink-0 opacity-80 transition group-hover:opacity-100 group-data-[selected=true]:opacity-100" | ||
| :model-id="provider.id" | ||
| :is-dark="themeStore.isDark" | ||
| /> | ||
| </div> | ||
| <span class="flex-1 truncate"> | ||
| {{ model.name }} | ||
| </span> | ||
| <Icon | ||
| v-if="isSelected(provider.id, model.id)" | ||
| icon="lucide:check" | ||
| class="h-4 w-4 shrink-0 text-primary dark:text-primary/80" | ||
| aria-hidden="true" | ||
| /> | ||
| </div> | ||
| <span class="flex-1 truncate text-[13px] font-medium"> | ||
| {{ model.name }} | ||
| </span> | ||
| <Icon | ||
| icon="lucide:check" | ||
| class="h-3.5 w-3.5 shrink-0 text-primary opacity-0 transition-opacity duration-200 group-data-[selected=true]:opacity-100 dark:text-[#9db8ff]" | ||
| aria-hidden="true" | ||
| /> | ||
| </button> | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </ScrollArea> | ||
| </div> | ||
| </ScrollArea> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add empty state handling for search results.
When the search keyword doesn't match any models, filteredProviders will be empty and the user sees a blank ScrollArea with no feedback. Consider adding an empty state message to improve UX.
Add an empty state inside the ScrollArea:
<ScrollArea class="h-72 pr-2">
- <div class="flex flex-col gap-5">
+ <div v-if="filteredProviders.length > 0" class="flex flex-col gap-5">
<div v-for="provider in filteredProviders" :key="provider.id" class="flex flex-col gap-2">
<!-- existing content -->
</div>
</div>
+ <div v-else class="flex h-full items-center justify-center text-sm text-muted-foreground">
+ {{ t('model.search.noResults') }}
+ </div>
</ScrollArea>Note: You'll need to add the corresponding i18n key model.search.noResults to your translation files.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <ScrollArea class="h-72 pr-2"> | |
| <div class="flex flex-col gap-5"> | |
| <div v-for="provider in filteredProviders" :key="provider.id" class="flex flex-col gap-2"> | |
| <Badge | |
| variant="outline" | |
| class="w-fit uppercase tracking-[0.18em] text-[10px] font-semibold text-muted-foreground" | |
| > | |
| <div | |
| class="flex h-7 w-7 items-center justify-center rounded-lg border border-border/60 bg-white/80 text-[11px] font-semibold uppercase text-muted-foreground/80 transition-all duration-200 group-data-[selected=true]:border-transparent group-data-[selected=true]:bg-primary group-data-[selected=true]:text-white/90 dark:border-white/15 dark:bg-white/[0.08] dark:group-data-[selected=true]:bg-[#3c82ff]" | |
| {{ provider.name }} | |
| </Badge> | |
| <div class="flex flex-col gap-1.5" role="listbox" aria-orientation="vertical"> | |
| <Button | |
| v-for="model in provider.models" | |
| :key="`${provider.id}-${model.id}`" | |
| type="button" | |
| variant="outline" | |
| class="group w-full justify-start gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition data-[selected=true]:border-primary data-[selected=true]:bg-primary/10 data-[selected=true]:text-foreground/90 dark:data-[selected=true]:bg-primary/15" | |
| role="option" | |
| :aria-selected="isSelected(provider.id, model.id)" | |
| :data-selected="isSelected(provider.id, model.id)" | |
| @click="handleModelSelect(provider.id, model)" | |
| > | |
| <ModelIcon | |
| class="h-4 w-4 shrink-0 opacity-70 transition duration-200 group-hover:opacity-100 group-data-[selected=true]:opacity-100" | |
| :model-id="provider.id" | |
| :is-dark="themeStore.isDark" | |
| <div | |
| class="flex h-7 w-7 items-center justify-center rounded-md border border-border bg-muted/40 text-[11px] font-semibold uppercase text-muted-foreground transition group-data-[selected=true]:border-primary group-data-[selected=true]:bg-primary/20 group-data-[selected=true]:text-primary" | |
| > | |
| <ModelIcon | |
| class="h-4 w-4 shrink-0 opacity-80 transition group-hover:opacity-100 group-data-[selected=true]:opacity-100" | |
| :model-id="provider.id" | |
| :is-dark="themeStore.isDark" | |
| /> | |
| </div> | |
| <span class="flex-1 truncate"> | |
| {{ model.name }} | |
| </span> | |
| <Icon | |
| v-if="isSelected(provider.id, model.id)" | |
| icon="lucide:check" | |
| class="h-4 w-4 shrink-0 text-primary dark:text-primary/80" | |
| aria-hidden="true" | |
| /> | |
| </div> | |
| <span class="flex-1 truncate text-[13px] font-medium"> | |
| {{ model.name }} | |
| </span> | |
| <Icon | |
| icon="lucide:check" | |
| class="h-3.5 w-3.5 shrink-0 text-primary opacity-0 transition-opacity duration-200 group-data-[selected=true]:opacity-100 dark:text-[#9db8ff]" | |
| aria-hidden="true" | |
| /> | |
| </button> | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </ScrollArea> | |
| </div> | |
| </ScrollArea> | |
| <ScrollArea class="h-72 pr-2"> | |
| <div v-if="filteredProviders.length > 0" class="flex flex-col gap-5"> | |
| <div v-for="provider in filteredProviders" :key="provider.id" class="flex flex-col gap-2"> | |
| <Badge | |
| variant="outline" | |
| class="w-fit uppercase tracking-[0.18em] text-[10px] font-semibold text-muted-foreground" | |
| > | |
| {{ provider.name }} | |
| </Badge> | |
| <div class="flex flex-col gap-1.5" role="listbox" aria-orientation="vertical"> | |
| <Button | |
| v-for="model in provider.models" | |
| :key="`${provider.id}-${model.id}`" | |
| type="button" | |
| variant="outline" | |
| class="group w-full justify-start gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition data-[selected=true]:border-primary data-[selected=true]:bg-primary/10 data-[selected=true]:text-foreground/90 dark:data-[selected=true]:bg-primary/15" | |
| role="option" | |
| :aria-selected="isSelected(provider.id, model.id)" | |
| :data-selected="isSelected(provider.id, model.id)" | |
| @click="handleModelSelect(provider.id, model)" | |
| > | |
| <div | |
| class="flex h-7 w-7 items-center justify-center rounded-md border border-border bg-muted/40 text-[11px] font-semibold uppercase text-muted-foreground transition group-data-[selected=true]:border-primary group-data-[selected=true]:bg-primary/20 group-data-[selected=true]:text-primary" | |
| > | |
| <ModelIcon | |
| class="h-4 w-4 shrink-0 opacity-80 transition group-hover:opacity-100 group-data-[selected=true]:opacity-100" | |
| :model-id="provider.id" | |
| :is-dark="themeStore.isDark" | |
| /> | |
| </div> | |
| <span class="flex-1 truncate"> | |
| {{ model.name }} | |
| </span> | |
| <Icon | |
| v-if="isSelected(provider.id, model.id)" | |
| icon="lucide:check" | |
| class="h-4 w-4 shrink-0 text-primary dark:text-primary/80" | |
| aria-hidden="true" | |
| /> | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |
| <div v-else class="flex h-full items-center justify-center text-sm text-muted-foreground"> | |
| {{ t('model.search.noResults') }} | |
| </div> | |
| </ScrollArea> |
🤖 Prompt for AI Agents
In src/renderer/src/components/prompt-input/ModelChooser.vue around lines 12 to
55, the ScrollArea shows nothing when filteredProviders is empty; add an
empty-state block rendered when filteredProviders.length === 0 that displays a
localized message (use i18n key model.search.noResults) inside the ScrollArea
(matching the component styling and spacing), ensure it is
keyboard/screen-reader friendly (e.g. role="status" or aria-live="polite"), and
update translation files with the new model.search.noResults entry.
|
Tested on linux, works fine |
|
@codex review |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting |
Fix appbar style on windows and linux
Summary by CodeRabbit
New Features
Style
Refactor