Skip to content

Conversation

@deepinfect
Copy link
Collaborator

@deepinfect deepinfect commented Oct 13, 2025

Fix appbar style on windows and linux

Summary by CodeRabbit

  • New Features

    • Windows: Shell window adopts Mica background for a native Windows 11 look.
    • Context length now includes tokens from selected files.
  • Style

    • Refined window background opacity across light/dark themes.
    • OS-aware backgrounds for app shell and app bar; improved close-button hover on non‑macOS.
    • Updated message list spacing and user message backgrounds; toolbar height adjusted.
    • Simplified MCP tools toggle styling and count display.
  • Refactor

    • Model chooser redesigned with card-based layout and clearer selection visuals.
    • Prompt input: streamlined web search toggle; removed select-based UI.
    • Removed sidebar toggle from New Thread.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Introduces 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

Cohort / File(s) Summary
Window material (Win11)
src/main/presenter/windowPresenter/index.ts
Sets backgroundMaterial to 'mica' on win32; undefined otherwise.
Shell frame & top bar
src/renderer/shell/App.vue, src/renderer/shell/components/AppBar.vue
App: renames isMacOS → isWinMacOS and applies bg conditionally for Darwin/Win32. AppBar: dynamic bg classes by OS, adds z-10 to border, tweaks non-macOS close hover styling.
Global theme vars
src/renderer/src/assets/style.css
Adjusts --bg-window-background opacity/values across root and dark variants to 0.5-oriented settings.
Message UI tweaks
src/renderer/src/components/message/MessageItemUser.vue, .../MessageList.vue, .../MessageToolbar.vue
MessageItemUser: removes vertical padding, switches to bg-muted for content/textarea. MessageList: adds top padding. MessageToolbar: height from h-8 to h-7.
Prompt input & models
src/renderer/src/components/prompt-input/PromptInput.vue, .../ModelChooser.vue
PromptInput: replaces Select-based web search with a single Button; removes Select logic; includes selectedFiles tokens in context length; cleans imports/comments. ModelChooser: refactors to Card/Badge/Button layout; preserves update:model events.
Misc UI cleanups
src/renderer/src/components/NewThread.vue, src/renderer/src/components/mcpToolsList.vue
NewThread: removes sidebar toggle button/handler. mcpToolsList: simplifies toggle/button styling and count color logic.

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)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • feat(ui): new design tokens  #969 — Also edits windowPresenter/index.ts for DevTools behavior; overlaps in shell/window setup code.
  • UI/refactor #977 — Modifies windowPresenter/index.ts concerning window chrome/appearance; directly related to window creation settings.

Suggested reviewers

  • zerob13

Poem

In windows of mica I thump and I tap,
A hop on the toolbar, a softer UI wrap.
Models in badges, buttons that gleam,
Web search now simple—what a clean little scheme.
I twitch my whiskers, review and delight,
New hues in the dark, all cozy and bright. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately describes the AppBar styling fixes on Windows and Linux by referencing the updates in AppBar.vue that apply OS-specific background classes and hover feedback, but it does not capture the broader set of cross-platform style changes in window background, CSS variables, and other components. Despite this partial scope mismatch, the title remains concise and clearly communicates the core AppBar modification.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/uibooooom

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 hooks

Also 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: Eliminate any type assertions for strict typing.

Casting originalContent.value to any violates 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 any casts 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 ?? 0

Repeat 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 @apply in 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 logic
src/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 like useNativeWindowChrome or isWindowsOrMacOS.

Additionally, ensure OS detection is consistent across components. Note that src/renderer/shell/components/AppBar.vue (line 472) uses isMacOS and 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1f1a5a2 and 74d92ec.

📒 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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/assets/style.css
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/main/presenter/windowPresenter/index.ts
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/main/presenter/windowPresenter/index.ts
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/assets/style.css
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/main/presenter/windowPresenter/index.ts
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/shell/App.vue
  • src/renderer/src/components/mcpToolsList.vue
  • src/renderer/src/components/message/MessageItemUser.vue
  • src/renderer/src/components/prompt-input/ModelChooser.vue
  • src/renderer/shell/components/AppBar.vue
  • src/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.vue
  • src/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-4 gives 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-primary when 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-50 to bg-muted for 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-8 to h-7 is 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-primary when web search is enabled is clear and intuitive.


367-374: Good fix: Context length now includes file tokens.

The updated currentContextLength computation now correctly accounts for tokens from selectedFiles, 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-10 ensures 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-background values 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 材质效果
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines +3 to +7
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'
]"
Copy link
Contributor

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"
>
<!-- 头像 -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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 needed

Also 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.

Comment on lines +12 to +55
<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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
<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.

@zerob13
Copy link
Collaborator

zerob13 commented Oct 13, 2025

Tested on linux, works fine

@zerob13
Copy link
Collaborator

zerob13 commented Oct 13, 2025

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting

@zerob13 zerob13 merged commit d2540f1 into dev Oct 13, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 14, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants