-
Notifications
You must be signed in to change notification settings - Fork 614
refactor: update vue-renderer-markdown to 0.0.54-beta.6 and remove Re… #934
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
…ferenceNode component
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... 📒 Files selected for processing (1)
Tip You can generate walkthrough in a markdown collapsible section to save space.Enable the WalkthroughUpdates vue-renderer-markdown dependency and migrates Markdown rendering to use global setCustomComponents. Moves reference interaction logic into registered custom component with click/hover behavior tied to presenter and stores. Removes local ReferenceNode component and stops passing custom-components/typewriterEffect props to NodeRenderer. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant MR as MarkdownRenderer.vue
participant VRM as vue-renderer-markdown<br/>setCustomComponents
participant RC as Custom Reference Component
participant TP as Presenter
participant RS as ReferenceStore
participant AS as ArtifactStore
U->>MR: Render markdown
MR->>VRM: setCustomComponents({ reference, code_block })
Note right of VRM: Global registration active
U->>RC: Click reference
RC->>TP: getSearchResults(messageId)
TP-->>RC: results
alt result URL available
RC->>U: open new tab (navigate)
else no result
RC->>RC: no-op/log
end
U->>RC: Mouse enter
RC->>RS: hide()
RC->>TP: getSearchResults(messageId)
TP-->>RC: results
alt valid index
RC->>RS: show({ anchorEl: referenceNode, index })
else invalid
RC->>RS: hide()
end
U->>RC: Mouse leave
RC->>RS: hide()
Note over MR,AS: code_block
MR->>AS: onPreviewCode({ messageId, threadId, code })
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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: 3
🧹 Nitpick comments (1)
src/renderer/src/components/markdown/MarkdownRenderer.vue (1)
33-80: Avoid re-registering global custom components per-render.
setCustomComponentsis global; calling it in every component instance can cause redundant registrations under HMR and multiple mounts. Guard it so it runs once.-setCustomComponents( { +const __key = '__deepchatMarkdownComponentsConfigured__' +if (!(globalThis as any)[__key]) { +setCustomComponents({ @@ -}) +}) +;(globalThis as any)[__key] = true +}Please verify that
ReferenceNodeforwards DOM mouse events soonMouseEnterreceives a MouseEvent. If it emits a custom event instead, adjust the listener name to match the component’s emitted event name.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
package.json(1 hunks)src/renderer/src/components/markdown/MarkdownRenderer.vue(3 hunks)src/renderer/src/components/markdown/ReferenceNode.vue(0 hunks)
💤 Files with no reviewable changes (1)
- src/renderer/src/components/markdown/ReferenceNode.vue
🧰 Additional context used
📓 Path-based instructions (15)
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/markdown/MarkdownRenderer.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.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/markdown/MarkdownRenderer.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue components in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
🧠 Learnings (10)
📓 Common learnings
Learnt from: neoragex2002
PR: ThinkInAIXYZ/deepchat#807
File: src/renderer/src/components/markdown/MarkdownRenderer.vue:58-58
Timestamp: 2025-08-28T08:07:05.182Z
Learning: In src/renderer/src/components/markdown/MarkdownRenderer.vue, the unscoped <style> tag is intentionally used for global prose styles and the anchor .markdown-renderer fix, as confirmed by user neoragex2002.
📚 Learning: 2025-08-28T08:07:05.182Z
Learnt from: neoragex2002
PR: ThinkInAIXYZ/deepchat#807
File: src/renderer/src/components/markdown/MarkdownRenderer.vue:58-58
Timestamp: 2025-08-28T08:07:05.182Z
Learning: In src/renderer/src/components/markdown/MarkdownRenderer.vue, the unscoped <style> tag is intentionally used for global prose styles and the anchor .markdown-renderer fix, as confirmed by user neoragex2002.
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
📚 Learning: 2025-07-21T01:47:28.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:47:28.817Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx,js,jsx} : Use the Composition API for better code organization and reusability
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
📚 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} : Use <script setup> syntax for concise component definitions.
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
📚 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} : Use Shadcn Vue, Radix Vue, and Tailwind for components and styling.
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vuepackage.json
📚 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} : Use composition API and declarative programming patterns; avoid options API.
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
📚 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} : Use template syntax for declarative rendering.
Applied to files:
src/renderer/src/components/markdown/MarkdownRenderer.vue
📚 Learning: 2025-09-16T07:06:30.939Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: AGENTS.md:0-0
Timestamp: 2025-09-16T07:06:30.939Z
Learning: Applies to test/{main,renderer}/**/*.{test,spec}.ts : Write tests with Vitest (jsdom) and Vue Test Utils
Applied to files:
package.json
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : Use the 'vue-i18n' framework for all internationalization in the renderer
Applied to files:
package.json
📚 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} : Use Vue 3 with TypeScript, leveraging defineComponent and PropType.
Applied to files:
package.json
🪛 GitHub Actions: PR Check
src/renderer/src/components/markdown/MarkdownRenderer.vue
[warning] 1-1: Code style issues found by Prettier. Run 'prettier --write' to fix.
🔇 Additional comments (2)
src/renderer/src/components/markdown/MarkdownRenderer.vue (1)
85-114: Unscoped prose styles acknowledged.Leaving styles unscoped here is intentional for global prose/anchor fixes. No change requested.
Based on learnings
package.json (1)
160-160: Dependency bump LGTM; APIs are exposed
v0.0.54-beta.6 exports setCustomComponents, ReferenceNode, and CodeBlockNode as required.
| import { usePresenter } from '@/composables/usePresenter'; | ||
| import { useArtifactStore } from '@/stores/artifact'; | ||
| import { useReferenceStore } from '@/stores/reference'; | ||
| import { nanoid } from 'nanoid'; | ||
| import { h, ref } from 'vue'; | ||
| import NodeRenderer, { CodeBlockNode, ReferenceNode, setCustomComponents } from 'vue-renderer-markdown'; |
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.
Fix Prettier violations (no semicolons) and drop unused import.
CI flagged Prettier. Also ref becomes unused after removing referenceNode.
-import { usePresenter } from '@/composables/usePresenter';
-import { useArtifactStore } from '@/stores/artifact';
-import { useReferenceStore } from '@/stores/reference';
-import { nanoid } from 'nanoid';
-import { h, ref } from 'vue';
-import NodeRenderer, { CodeBlockNode, ReferenceNode, setCustomComponents } from 'vue-renderer-markdown';
+import { usePresenter } from '@/composables/usePresenter'
+import { useArtifactStore } from '@/stores/artifact'
+import { useReferenceStore } from '@/stores/reference'
+import { nanoid } from 'nanoid'
+import { h } from 'vue'
+import NodeRenderer, { CodeBlockNode, ReferenceNode, setCustomComponents } from 'vue-renderer-markdown'Please run: pnpm format
📝 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.
| import { usePresenter } from '@/composables/usePresenter'; | |
| import { useArtifactStore } from '@/stores/artifact'; | |
| import { useReferenceStore } from '@/stores/reference'; | |
| import { nanoid } from 'nanoid'; | |
| import { h, ref } from 'vue'; | |
| import NodeRenderer, { CodeBlockNode, ReferenceNode, setCustomComponents } from 'vue-renderer-markdown'; | |
| import { usePresenter } from '@/composables/usePresenter' | |
| import { useArtifactStore } from '@/stores/artifact' | |
| import { useReferenceStore } from '@/stores/reference' | |
| import { nanoid } from 'nanoid' | |
| import { h } from 'vue' | |
| import NodeRenderer, { CodeBlockNode, ReferenceNode, setCustomComponents } from 'vue-renderer-markdown' |
🤖 Prompt for AI Agents
In src/renderer/src/components/markdown/MarkdownRenderer.vue around lines 12 to
17, Prettier flagged semicolon violations and the import `ref` is now unused;
remove the trailing semicolons in these import lines and delete the unused `ref`
from the import list, then run the formatter (pnpm format) to apply consistent
styling.
| reference: ReferenceNode, | ||
| const referenceStore = useReferenceStore() | ||
| const threadPresenter = usePresenter('threadPresenter') | ||
| const referenceNode = ref<HTMLElement | null>(null) |
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.
Remove unused ref; switch to event target for bounding box.
referenceNode is never assigned, so hover never shows references. The proposed change uses the event target’s bounding rect; remove this ref to avoid dead code.
-const referenceNode = ref<HTMLElement | null>(null)📝 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.
| const referenceNode = ref<HTMLElement | null>(null) | |
| -const referenceNode = ref<HTMLElement | null>(null) |
🤖 Prompt for AI Agents
In src/renderer/src/components/markdown/MarkdownRenderer.vue around line 31,
remove the unused declaration "const referenceNode = ref<HTMLElement |
null>(null)" and update the hover handler to use the event target’s
boundingClientRect instead of relying on that ref; ensure you cast/check
event.target as an HTMLElement before calling getBoundingClientRect(), handle
potential nulls, and remove any now-unused imports or references to
referenceNode to avoid dead code.
| setCustomComponents( { | ||
| reference: (_props) => | ||
| h(ReferenceNode, { | ||
| ..._props, | ||
| messageId, | ||
| threadId, | ||
| onClick(){ | ||
| threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => { | ||
| const index = parseInt(_props.node.id) | ||
| if (index < results.length) { | ||
| window.open(results[index - 1].url, '_blank', 'noopener,noreferrer') | ||
| } | ||
| }) | ||
| }, | ||
| onMouseEnter(){ | ||
| console.log('Mouse entered') | ||
| referenceStore.hideReference() | ||
| threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => { | ||
| const index = parseInt(_props.node.id) | ||
| if (index - 1 < results.length && referenceNode.value) { | ||
| referenceStore.showReference(results[index - 1], referenceNode.value.getBoundingClientRect()) | ||
| } | ||
| }) | ||
| }, | ||
| onMouseLeave(){ | ||
| console.log('Mouse left') | ||
| referenceStore.hideReference() | ||
| } | ||
| }), |
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.
Fix off-by-one and missing bounds checks when opening references.
Currently checks index < results.length but then uses results[index - 1], which can skip the last item and underflow for id="1". Also add radix/NaN safety and use the local messageId to avoid empty-string fallbacks.
Apply this diff:
- onClick(){
- threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => {
- const index = parseInt(_props.node.id)
- if (index < results.length) {
- window.open(results[index - 1].url, '_blank', 'noopener,noreferrer')
- }
- })
- },
+ onClick: () => {
+ threadPresenter.getSearchResults(messageId).then((results) => {
+ const idx = Number(_props.node.id) - 1
+ if (Number.isInteger(idx) && idx >= 0 && idx < results.length) {
+ window.open(results[idx].url, '_blank', 'noopener,noreferrer')
+ }
+ })
+ },
- onMouseEnter(){
- console.log('Mouse entered')
- referenceStore.hideReference()
- threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => {
- const index = parseInt(_props.node.id)
- if (index - 1 < results.length && referenceNode.value) {
- referenceStore.showReference(results[index - 1], referenceNode.value.getBoundingClientRect())
- }
- })
- },
- onMouseLeave(){
- console.log('Mouse left')
- referenceStore.hideReference()
- }
+ onMouseEnter: (e: MouseEvent) => {
+ referenceStore.hideReference()
+ const target = e.currentTarget as HTMLElement | null
+ threadPresenter.getSearchResults(messageId).then((results) => {
+ const idx = Number(_props.node.id) - 1
+ if (target && Number.isInteger(idx) && idx >= 0 && idx < results.length) {
+ referenceStore.showReference(results[idx], target.getBoundingClientRect())
+ }
+ })
+ },
+ onMouseLeave: () => {
+ referenceStore.hideReference()
+ }📝 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.
| setCustomComponents( { | |
| reference: (_props) => | |
| h(ReferenceNode, { | |
| ..._props, | |
| messageId, | |
| threadId, | |
| onClick(){ | |
| threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => { | |
| const index = parseInt(_props.node.id) | |
| if (index < results.length) { | |
| window.open(results[index - 1].url, '_blank', 'noopener,noreferrer') | |
| } | |
| }) | |
| }, | |
| onMouseEnter(){ | |
| console.log('Mouse entered') | |
| referenceStore.hideReference() | |
| threadPresenter.getSearchResults(_props.messageId ?? '').then((results) => { | |
| const index = parseInt(_props.node.id) | |
| if (index - 1 < results.length && referenceNode.value) { | |
| referenceStore.showReference(results[index - 1], referenceNode.value.getBoundingClientRect()) | |
| } | |
| }) | |
| }, | |
| onMouseLeave(){ | |
| console.log('Mouse left') | |
| referenceStore.hideReference() | |
| } | |
| }), | |
| setCustomComponents({ | |
| reference: (_props) => | |
| h(ReferenceNode, { | |
| ..._props, | |
| messageId, | |
| threadId, | |
| onClick: () => { | |
| threadPresenter.getSearchResults(messageId).then((results) => { | |
| const idx = Number(_props.node.id) - 1 | |
| if (Number.isInteger(idx) && idx >= 0 && idx < results.length) { | |
| window.open(results[idx].url, '_blank', 'noopener,noreferrer') | |
| } | |
| }) | |
| }, | |
| onMouseEnter: (e: MouseEvent) => { | |
| referenceStore.hideReference() | |
| const target = e.currentTarget as HTMLElement | null | |
| threadPresenter.getSearchResults(messageId).then((results) => { | |
| const idx = Number(_props.node.id) - 1 | |
| if (target && Number.isInteger(idx) && idx >= 0 && idx < results.length) { | |
| referenceStore.showReference(results[idx], target.getBoundingClientRect()) | |
| } | |
| }) | |
| }, | |
| onMouseLeave: () => { | |
| referenceStore.hideReference() | |
| } | |
| }), |
🤖 Prompt for AI Agents
In src/renderer/src/components/markdown/MarkdownRenderer.vue around lines 33 to
61, fix the off-by-one and bounds issues and improve safety: parse the node id
with radix (e.g. parseInt(_props.node.id, 10)), validate it (ensure it's a
number and > 0), and use index-1 to access results only when index <=
results.length; also use the local messageId variable instead of
_props.messageId fallback and add the same validated index/bounds check in both
onClick and onMouseEnter before accessing results and
referenceNode.value.getBoundingClientRect().
* fix: katex style (#926) * refactor: reorganize artifact processing logic and improve attribute parsing (#927) * fix(thinkingBlock): pre style (#930) * refactor: remove DOMPurify dependency and replace MessageBlockThink `v-html` with vue-markdown-renderer (#931) * refactor: remove DOMPurify dependency and replace MessageBlockThink `v-html` with vue-markdown-renderer * chore: update * feat: add Qwen3-VL and Qwen3-Max 0924 (#932) * refactor: update vue-renderer-markdown to 0.0.54-beta.6 and remove Re… (#934) * refactor: update vue-renderer-markdown to 0.0.54-beta.6 and remove ReferenceNode component * chore: format * chore: version 0.3.7 --------- Co-authored-by: Simon He <57086651+Simon-He95@users.noreply.github.com> Co-authored-by: yyhhyyyyyy <yyhhyyyyyy8@gmail.com>
…ferenceNode component
Pull Request Description
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is.
*For example: I'm always frustrated when [...] *
Describe the solution you'd like
A clear and concise description of what you want to happen.
UI/UX changes for Desktop Application
If this PR introduces UI/UX changes, please describe them in detail.
Platform Compatibility Notes
If this PR has specific platform compatibility considerations (Windows, macOS, Linux), please describe them here.
Additional context
Add any other context about the pull request here.
Pull Request Description (中文)
你的功能请求是否与某个问题有关?请描述一下。
请对问题进行清晰扼要的描述。
*例如:我增加了 [...] 的功能 *
请描述你希望的解决方案
请对你希望实现的效果进行清晰扼要的描述。
桌面应用程序的 UI/UX 更改
如果此 PR 引入了 UI/UX 更改,请详细描述它们。
平台兼容性注意事项
如果此 PR 具有特定的平台兼容性考虑因素(Windows、macOS、Linux),请在此处描述。
附加背景
在此处添加关于此 Pull Request 的任何其他背景信息。
Summary by CodeRabbit
New Features
Chores