Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Oct 9, 2025

Summary

  • add the latest shadcn-vue components (button-group, empty, field, input-group, item, kbd, spinner)
  • bump reka-ui to 2.5.1 and regenerate shadcn sources
  • keep the update script in sync with the expanded component set

Testing

  • pnpm run typecheck

https://chatgpt.com/codex/tasks/task_e_68e74c1df198832caf00997c1812e6bd

Summary by CodeRabbit

  • New Features

    • Added Button Group, Empty-state, Field, Input Group, Item, Kbd/KbdGroup, and Spinner UI components plus demos and updated Playground sections; expanded Button size options.
    • Shortcut settings UI updated to use keyboard-style key pills for editing and display.
  • Chores

    • Bumped UI dependency to a patch release.
    • Update script extended to process more component types.
  • Style

    • Minor class/string formatting and keycap styling adjustments.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds multiple new shadcn Vue UI modules (button-group, empty, field, input-group, item, kbd, spinner) with CVA variant configs and index exports; updates demo playground to include demos; extends button size variants; updates scripts to include new components; bumps reka-ui dependency; minor separator formatting tweak; replaces shortcut key UI with Kbd-based recording UI.

Changes

Cohort / File(s) Summary
Dependency bump
package.json
Update reka-ui from ^2.5.0 to ^2.5.1.
Script: shadcn updater
scripts/update-shadcn.js
Extend component list with button-group, empty, field, input-group, item, kbd, spinner; minor trailing comma normalization.
Button variants
src/shadcn/components/ui/button/index.ts
Add "icon-sm" and "icon-lg" size variants to buttonVariants.
Button Group module
src/shadcn/components/ui/button-group/*
New components: ButtonGroup.vue, ButtonGroupSeparator.vue, ButtonGroupText.vue; add index.ts with buttonGroupVariants and ButtonGroupVariants type; export components.
Empty module
src/shadcn/components/ui/empty/*
New components: Empty.vue, EmptyContent.vue, EmptyDescription.vue, EmptyHeader.vue, EmptyMedia.vue, EmptyTitle.vue; add index.ts with emptyMediaVariants and EmptyMediaVariants type; export components.
Field module
src/shadcn/components/ui/field/*
New components: Field.vue, FieldContent.vue, FieldDescription.vue, FieldError.vue, FieldGroup.vue, FieldLabel.vue, FieldLegend.vue, FieldSeparator.vue, FieldSet.vue, FieldTitle.vue; add index.ts with fieldVariants and FieldVariants type; export components.
Input Group module
src/shadcn/components/ui/input-group/*
New components: InputGroup.vue, InputGroupAddon.vue, InputGroupButton.vue, InputGroupInput.vue, InputGroupText.vue, InputGroupTextarea.vue; add index.ts with inputGroupAddonVariants, inputGroupButtonVariants, related types and InputGroupButtonProps; export components.
Item module
src/shadcn/components/ui/item/*
New components: Item.vue, ItemActions.vue, ItemContent.vue, ItemDescription.vue, ItemFooter.vue, ItemGroup.vue, ItemHeader.vue, ItemMedia.vue, ItemSeparator.vue, ItemTitle.vue; add index.ts with itemVariants, itemMediaVariants and types; export components.
Kbd module
src/shadcn/components/ui/kbd/*
New components: Kbd.vue, KbdGroup.vue; add index.ts re-exports.
Spinner module
src/shadcn/components/ui/spinner/*
New Spinner.vue using Loader2Icon; add index.ts re-export.
Separator formatting
src/shadcn/components/ui/separator/Separator.vue
Convert class template literal to single-quoted string; no functional change.
Playground demos & view
src/renderer/src/views/playground/demos/*, src/renderer/src/views/PlaygroundTabView.vue
Add demos and integrate new components: ButtonGroupDemo.vue, EmptyDemo.vue, FieldDemo.vue, InputGroupDemo.vue, ItemDemo.vue, KbdDemo.vue, SpinnerDemo.vue; update PlaygroundTabView.vue sections and demo lists.
Shortcut settings UI
src/renderer/src/components/settings/ShortcutSettings.vue
Replace inline keycap UI with Kbd/KbdGroup-based recording UI; add formatting helpers, recording state rendering, hover controls for edit/clear, and updated event/listener lifecycle and styles for recording/disabled states.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Addon as InputGroupAddon
  participant Doc as Document
  participant Input as FirstInput

  User->>Addon: click
  alt click inside a button in addon
    Note right of Addon #f0f4c3: ignore focus
    Addon-->>User: no-op
  else generic addon click
    Addon->>Doc: querySelector for first input in group
    Doc-->>Addon: returns Input
    Addon->>Input: focus()
    Note right of Input #e8f5e9: input receives focus
  end
Loading
sequenceDiagram
  participant User
  participant ShortcutUI as ShortcutSettings
  participant KbdGroup
  participant Keyboard

  User->>ShortcutUI: click edit
  ShortcutUI->>KbdGroup: enter recording state
  KbdGroup->>Keyboard: listen for key events
  alt keys pressed
    Keyboard->>KbdGroup: emit key sequence
    KbdGroup->>ShortcutUI: update formattedTempShortcut
    ShortcutUI-->>User: show temp Kbd pills live
  else canceled or timeout
    KbdGroup->>ShortcutUI: cancel recording
    ShortcutUI-->>User: revert display
  end
  ShortcutUI->>ShortcutUI: save or clear on action
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • deepinfect

Poem

In burrows bright the widgets sprout,
Buttons gather, spinners shout,
Fields and items hop in line,
Kbd keys tap a rhythmic sign.
A rabbit claps — the UI blooms about! 🐇✨

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 succinctly captures the primary purpose of the pull request by indicating a chore to synchronize the shadcn Vue components, which aligns with the extensive additions and script updates in the changeset. It is concise, avoids generic wording or noise, and clearly signals the nature of the update to maintainers. This phrasing allows teammates scanning the history to quickly understand the main change without ambiguity.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/integrate-new-shadcn-vue-components

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

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ 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

Comment on lines +1 to +20
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { EmptyMediaVariants } from "."
import { cn } from '@shadcn/lib/utils'
import { emptyMediaVariants } from "."

const props = defineProps<{
class?: HTMLAttributes["class"]
variant?: EmptyMediaVariants["variant"]
}>()
</script>

<template>
<div
data-slot="empty-icon"
:data-variant="variant"
:class="cn(emptyMediaVariants({ variant }), props.class)"
>
<slot />
</div>

Choose a reason for hiding this comment

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

P1 Badge EmptyTitle renders media slot instead of title

EmptyTitle.vue is a copy of the media component: it exports EmptyMediaVariants, renders data-slot="empty-icon", and applies emptyMediaVariants. Consumers calling EmptyTitle will not get a heading/empty-title slot at all, so any markup expecting to render text (and CSS targeting [data-slot=empty-title]) never executes. This effectively makes the EmptyTitle component unusable and breaks composed empty states.

Useful? React with 👍 / 👎.

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: 8

🧹 Nitpick comments (6)
src/shadcn/components/ui/item/ItemSeparator.vue (1)

12-18: Consider making orientation configurable.

The component hardcodes orientation="horizontal". Since the underlying Separator component supports different orientations (as seen in SeparatorProps), consider allowing consumers to override this.

Apply this diff to make orientation configurable:

 const props = defineProps<
-  SeparatorProps & { class?: HTMLAttributes["class"] }
+  SeparatorProps & { class?: HTMLAttributes["class"]; orientation?: "horizontal" | "vertical" }
 >()
+
+const { orientation = "horizontal", ...separatorProps } = props
   <Separator
     data-slot="item-separator"
-    orientation="horizontal"
+    v-bind="separatorProps"
+    :orientation="orientation"
     :class="cn('my-0', props.class)"
   />
src/shadcn/components/ui/field/FieldGroup.vue (1)

13-16: Consider breaking up the long class string.

Line 14 exceeds the 100-character max width specified in the coding guidelines. While functionally correct, breaking this into multiple lines would improve readability.

Apply this diff to improve formatting:

     :class="cn(
-      'group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',
+      'group/field-group @container/field-group flex w-full flex-col gap-7',
+      'data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',
       props.class,
     )"
src/shadcn/components/ui/item/ItemMedia.vue (1)

16-17: Inconsistent prop access style.

Line 16 uses props.variant while line 17 uses variant directly. Both work in Vue 3 script setup, but mixing styles reduces consistency.

Apply this diff for consistency:

     data-slot="item-media"
-    :data-variant="props.variant"
-    :class="cn(itemMediaVariants({ variant }), props.class)"
+    :data-variant="variant"
+    :class="cn(itemMediaVariants({ variant }), class)"

Or alternatively, use props. prefix everywhere:

     data-slot="item-media"
     :data-variant="props.variant"
-    :class="cn(itemMediaVariants({ variant }), props.class)"
+    :class="cn(itemMediaVariants({ variant: props.variant }), props.class)"
src/shadcn/components/ui/empty/EmptyTitle.vue (1)

16-17: Consider consistent prop access.

For consistency with the data-variant binding and the pattern used in similar components, consider using props.variant in the class composition.

Apply this diff:

     data-slot="empty-title"
-    :data-variant="variant"
-    :class="cn(emptyMediaVariants({ variant }), props.class)"
+    :data-variant="props.variant"
+    :class="cn(emptyMediaVariants({ variant: props.variant }), props.class)"
src/shadcn/components/ui/field/Field.vue (1)

17-20: Consider consistent prop references.

The component mixes direct prop access (orientation on line 17, 19) with the props prefix (props.class on line 20). While both work in Vue 3 script setup, consistent usage improves readability.

Apply this diff for consistency:

-    :data-orientation="orientation"
+    :data-orientation="props.orientation"
     :class="cn(
-      fieldVariants({ orientation }),
+      fieldVariants({ orientation: props.orientation }),
       props.class,
     )"
src/shadcn/components/ui/item/index.ts (1)

15-34: Optional: Remove trailing space in size variant.

The CVA configuration is correct and follows best practices. However, there's a minor trailing space in the size.default class string at line 25.

Apply this diff to remove the trailing space:

       size: {
-        default: "p-4 gap-4 ",
+        default: "p-4 gap-4",
         sm: "py-3 px-4 gap-2.5",
       },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6922f29 and 299185c.

📒 Files selected for processing (49)
  • package.json (1 hunks)
  • scripts/update-shadcn.js (1 hunks)
  • src/shadcn/components/ui/button-group/ButtonGroup.vue (1 hunks)
  • src/shadcn/components/ui/button-group/ButtonGroupSeparator.vue (1 hunks)
  • src/shadcn/components/ui/button-group/ButtonGroupText.vue (1 hunks)
  • src/shadcn/components/ui/button-group/index.ts (1 hunks)
  • src/shadcn/components/ui/button/index.ts (1 hunks)
  • src/shadcn/components/ui/empty/Empty.vue (1 hunks)
  • src/shadcn/components/ui/empty/EmptyContent.vue (1 hunks)
  • src/shadcn/components/ui/empty/EmptyDescription.vue (1 hunks)
  • src/shadcn/components/ui/empty/EmptyHeader.vue (1 hunks)
  • src/shadcn/components/ui/empty/EmptyMedia.vue (1 hunks)
  • src/shadcn/components/ui/empty/EmptyTitle.vue (1 hunks)
  • src/shadcn/components/ui/empty/index.ts (1 hunks)
  • src/shadcn/components/ui/field/Field.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldContent.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldDescription.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldError.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldGroup.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldLabel.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldLegend.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldSeparator.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldSet.vue (1 hunks)
  • src/shadcn/components/ui/field/FieldTitle.vue (1 hunks)
  • src/shadcn/components/ui/field/index.ts (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroup.vue (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroupAddon.vue (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroupButton.vue (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroupInput.vue (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroupText.vue (1 hunks)
  • src/shadcn/components/ui/input-group/InputGroupTextarea.vue (1 hunks)
  • src/shadcn/components/ui/input-group/index.ts (1 hunks)
  • src/shadcn/components/ui/item/Item.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemActions.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemContent.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemDescription.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemFooter.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemGroup.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemHeader.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemMedia.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemSeparator.vue (1 hunks)
  • src/shadcn/components/ui/item/ItemTitle.vue (1 hunks)
  • src/shadcn/components/ui/item/index.ts (1 hunks)
  • src/shadcn/components/ui/kbd/Kbd.vue (1 hunks)
  • src/shadcn/components/ui/kbd/KbdGroup.vue (1 hunks)
  • src/shadcn/components/ui/kbd/index.ts (1 hunks)
  • src/shadcn/components/ui/separator/Separator.vue (1 hunks)
  • src/shadcn/components/ui/spinner/Spinner.vue (1 hunks)
  • src/shadcn/components/ui/spinner/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/shadcn/components/ui/kbd/index.ts
  • src/shadcn/components/ui/empty/index.ts
  • scripts/update-shadcn.js
  • src/shadcn/components/ui/spinner/index.ts
  • src/shadcn/components/ui/field/index.ts
  • src/shadcn/components/ui/button/index.ts
  • src/shadcn/components/ui/input-group/index.ts
  • src/shadcn/components/ui/button-group/index.ts
  • src/shadcn/components/ui/item/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别

Files:

  • src/shadcn/components/ui/kbd/index.ts
  • src/shadcn/components/ui/empty/index.ts
  • src/shadcn/components/ui/spinner/index.ts
  • src/shadcn/components/ui/field/index.ts
  • src/shadcn/components/ui/button/index.ts
  • src/shadcn/components/ui/input-group/index.ts
  • src/shadcn/components/ui/button-group/index.ts
  • src/shadcn/components/ui/item/index.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/shadcn/components/ui/kbd/index.ts
  • src/shadcn/components/ui/empty/index.ts
  • scripts/update-shadcn.js
  • src/shadcn/components/ui/spinner/index.ts
  • src/shadcn/components/ui/input-group/InputGroupText.vue
  • src/shadcn/components/ui/field/FieldError.vue
  • src/shadcn/components/ui/item/ItemMedia.vue
  • src/shadcn/components/ui/field/FieldGroup.vue
  • src/shadcn/components/ui/kbd/Kbd.vue
  • src/shadcn/components/ui/field/index.ts
  • src/shadcn/components/ui/field/FieldLegend.vue
  • src/shadcn/components/ui/item/ItemActions.vue
  • src/shadcn/components/ui/item/ItemGroup.vue
  • src/shadcn/components/ui/button/index.ts
  • src/shadcn/components/ui/field/FieldContent.vue
  • src/shadcn/components/ui/input-group/InputGroupAddon.vue
  • src/shadcn/components/ui/item/ItemSeparator.vue
  • src/shadcn/components/ui/button-group/ButtonGroup.vue
  • src/shadcn/components/ui/empty/EmptyTitle.vue
  • src/shadcn/components/ui/spinner/Spinner.vue
  • src/shadcn/components/ui/field/Field.vue
  • src/shadcn/components/ui/input-group/index.ts
  • src/shadcn/components/ui/input-group/InputGroup.vue
  • src/shadcn/components/ui/field/FieldSet.vue
  • src/shadcn/components/ui/kbd/KbdGroup.vue
  • src/shadcn/components/ui/input-group/InputGroupButton.vue
  • src/shadcn/components/ui/field/FieldTitle.vue
  • src/shadcn/components/ui/item/ItemContent.vue
  • src/shadcn/components/ui/empty/EmptyDescription.vue
  • src/shadcn/components/ui/input-group/InputGroupTextarea.vue
  • src/shadcn/components/ui/empty/EmptyHeader.vue
  • src/shadcn/components/ui/field/FieldSeparator.vue
  • src/shadcn/components/ui/field/FieldDescription.vue
  • src/shadcn/components/ui/item/ItemFooter.vue
  • src/shadcn/components/ui/item/ItemHeader.vue
  • src/shadcn/components/ui/button-group/index.ts
  • src/shadcn/components/ui/item/ItemTitle.vue
  • src/shadcn/components/ui/item/Item.vue
  • src/shadcn/components/ui/empty/Empty.vue
  • src/shadcn/components/ui/item/index.ts
  • src/shadcn/components/ui/field/FieldLabel.vue
  • src/shadcn/components/ui/input-group/InputGroupInput.vue
  • src/shadcn/components/ui/button-group/ButtonGroupText.vue
  • src/shadcn/components/ui/button-group/ButtonGroupSeparator.vue
  • src/shadcn/components/ui/empty/EmptyContent.vue
  • src/shadcn/components/ui/empty/EmptyMedia.vue
  • src/shadcn/components/ui/separator/Separator.vue
  • src/shadcn/components/ui/item/ItemDescription.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Files:

  • src/shadcn/components/ui/kbd/index.ts
  • src/shadcn/components/ui/empty/index.ts
  • src/shadcn/components/ui/spinner/index.ts
  • src/shadcn/components/ui/input-group/InputGroupText.vue
  • src/shadcn/components/ui/field/FieldError.vue
  • src/shadcn/components/ui/item/ItemMedia.vue
  • src/shadcn/components/ui/field/FieldGroup.vue
  • src/shadcn/components/ui/kbd/Kbd.vue
  • src/shadcn/components/ui/field/index.ts
  • src/shadcn/components/ui/field/FieldLegend.vue
  • src/shadcn/components/ui/item/ItemActions.vue
  • src/shadcn/components/ui/item/ItemGroup.vue
  • src/shadcn/components/ui/button/index.ts
  • src/shadcn/components/ui/field/FieldContent.vue
  • src/shadcn/components/ui/input-group/InputGroupAddon.vue
  • src/shadcn/components/ui/item/ItemSeparator.vue
  • src/shadcn/components/ui/button-group/ButtonGroup.vue
  • src/shadcn/components/ui/empty/EmptyTitle.vue
  • src/shadcn/components/ui/spinner/Spinner.vue
  • src/shadcn/components/ui/field/Field.vue
  • src/shadcn/components/ui/input-group/index.ts
  • src/shadcn/components/ui/input-group/InputGroup.vue
  • src/shadcn/components/ui/field/FieldSet.vue
  • src/shadcn/components/ui/kbd/KbdGroup.vue
  • src/shadcn/components/ui/input-group/InputGroupButton.vue
  • src/shadcn/components/ui/field/FieldTitle.vue
  • src/shadcn/components/ui/item/ItemContent.vue
  • src/shadcn/components/ui/empty/EmptyDescription.vue
  • src/shadcn/components/ui/input-group/InputGroupTextarea.vue
  • src/shadcn/components/ui/empty/EmptyHeader.vue
  • src/shadcn/components/ui/field/FieldSeparator.vue
  • src/shadcn/components/ui/field/FieldDescription.vue
  • src/shadcn/components/ui/item/ItemFooter.vue
  • src/shadcn/components/ui/item/ItemHeader.vue
  • src/shadcn/components/ui/button-group/index.ts
  • src/shadcn/components/ui/item/ItemTitle.vue
  • src/shadcn/components/ui/item/Item.vue
  • src/shadcn/components/ui/empty/Empty.vue
  • src/shadcn/components/ui/item/index.ts
  • src/shadcn/components/ui/field/FieldLabel.vue
  • src/shadcn/components/ui/input-group/InputGroupInput.vue
  • src/shadcn/components/ui/button-group/ButtonGroupText.vue
  • src/shadcn/components/ui/button-group/ButtonGroupSeparator.vue
  • src/shadcn/components/ui/empty/EmptyContent.vue
  • src/shadcn/components/ui/empty/EmptyMedia.vue
  • src/shadcn/components/ui/separator/Separator.vue
  • src/shadcn/components/ui/item/ItemDescription.vue
**/*.{js,jsx,ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting: single quotes, no semicolons, max width 100

Files:

  • src/shadcn/components/ui/kbd/index.ts
  • src/shadcn/components/ui/empty/index.ts
  • scripts/update-shadcn.js
  • src/shadcn/components/ui/spinner/index.ts
  • src/shadcn/components/ui/input-group/InputGroupText.vue
  • src/shadcn/components/ui/field/FieldError.vue
  • src/shadcn/components/ui/item/ItemMedia.vue
  • src/shadcn/components/ui/field/FieldGroup.vue
  • src/shadcn/components/ui/kbd/Kbd.vue
  • src/shadcn/components/ui/field/index.ts
  • src/shadcn/components/ui/field/FieldLegend.vue
  • src/shadcn/components/ui/item/ItemActions.vue
  • src/shadcn/components/ui/item/ItemGroup.vue
  • src/shadcn/components/ui/button/index.ts
  • src/shadcn/components/ui/field/FieldContent.vue
  • src/shadcn/components/ui/input-group/InputGroupAddon.vue
  • src/shadcn/components/ui/item/ItemSeparator.vue
  • src/shadcn/components/ui/button-group/ButtonGroup.vue
  • src/shadcn/components/ui/empty/EmptyTitle.vue
  • src/shadcn/components/ui/spinner/Spinner.vue
  • src/shadcn/components/ui/field/Field.vue
  • src/shadcn/components/ui/input-group/index.ts
  • src/shadcn/components/ui/input-group/InputGroup.vue
  • src/shadcn/components/ui/field/FieldSet.vue
  • src/shadcn/components/ui/kbd/KbdGroup.vue
  • src/shadcn/components/ui/input-group/InputGroupButton.vue
  • src/shadcn/components/ui/field/FieldTitle.vue
  • src/shadcn/components/ui/item/ItemContent.vue
  • src/shadcn/components/ui/empty/EmptyDescription.vue
  • src/shadcn/components/ui/input-group/InputGroupTextarea.vue
  • src/shadcn/components/ui/empty/EmptyHeader.vue
  • src/shadcn/components/ui/field/FieldSeparator.vue
  • src/shadcn/components/ui/field/FieldDescription.vue
  • src/shadcn/components/ui/item/ItemFooter.vue
  • src/shadcn/components/ui/item/ItemHeader.vue
  • src/shadcn/components/ui/button-group/index.ts
  • src/shadcn/components/ui/item/ItemTitle.vue
  • src/shadcn/components/ui/item/Item.vue
  • src/shadcn/components/ui/empty/Empty.vue
  • src/shadcn/components/ui/item/index.ts
  • src/shadcn/components/ui/field/FieldLabel.vue
  • src/shadcn/components/ui/input-group/InputGroupInput.vue
  • src/shadcn/components/ui/button-group/ButtonGroupText.vue
  • src/shadcn/components/ui/button-group/ButtonGroupSeparator.vue
  • src/shadcn/components/ui/empty/EmptyContent.vue
  • src/shadcn/components/ui/empty/EmptyMedia.vue
  • src/shadcn/components/ui/separator/Separator.vue
  • src/shadcn/components/ui/item/ItemDescription.vue
scripts/**

📄 CodeRabbit inference engine (AGENTS.md)

Place build/signing/installer/runtime and commit-related scripts in scripts/

Files:

  • scripts/update-shadcn.js
🧠 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} : Use the Icon component with lucide icons.

Applied to files:

  • src/shadcn/components/ui/spinner/Spinner.vue
🧬 Code graph analysis (1)
src/shadcn/components/ui/input-group/index.ts (1)
src/shadcn/components/ui/button/index.ts (1)
  • ButtonVariants (39-39)
🔇 Additional comments (35)
src/shadcn/components/ui/kbd/index.ts (1)

1-2: LGTM!

Standard re-export pattern for Vue components. The exports properly expose Kbd and KbdGroup from their respective Vue files.

src/shadcn/components/ui/kbd/Kbd.vue (1)

1-21: LGTM!

Well-implemented keyboard component following Vue 3 and shadcn best practices:

  • Proper TypeScript typing with HTMLAttributes["class"]
  • Uses cn utility for class composition
  • Includes comprehensive styling for various contexts (tooltips, SVG sizing)
  • Semantic <kbd> element with slot support
src/shadcn/components/ui/kbd/KbdGroup.vue (1)

1-17: LGTM!

Clean implementation of the keyboard group wrapper component:

  • Consistent structure and typing with the Kbd component
  • Uses data-slot attribute for semantic grouping
  • Simple flexbox layout with proper class merging
package.json (1)

151-151: LGTM!

The reka-ui dependency bump from ^2.5.0 to ^2.5.1 is a patch-level update that aligns with the new shadcn-vue component additions. Patch updates are typically backward-compatible.

scripts/update-shadcn.js (1)

52-59: LGTM!

The component list has been correctly expanded to include all the new shadcn-vue components mentioned in the PR objectives: button-group, empty, field, input-group, item, kbd, and spinner. The trailing comma addition on line 52 ensures consistent formatting.

src/shadcn/components/ui/item/ItemActions.vue (1)

1-17: LGTM!

The component has a clean structure with consistent prop usage. The class merging via cn utility is correct, and the flexbox layout is appropriate for an actions container.

src/shadcn/components/ui/separator/Separator.vue (1)

16-29: LGTM!

This is a formatting-only change with no functional impact. The class composition logic remains correct and consistent.

src/shadcn/components/ui/spinner/index.ts (1)

1-1: LGTM!

The export follows the standard pattern for shadcn component index files and correctly re-exports the Spinner component.

src/shadcn/components/ui/field/FieldLabel.vue (1)

1-23: LGTM!

The component properly uses the Label primitive with type-safe props and consistent class composition. The complex class selectors for group/peer states and container queries are appropriate for a UI library component.

src/shadcn/components/ui/item/ItemTitle.vue (1)

1-17: LGTM!

The component follows consistent patterns with proper TypeScript typing and correct prop access.

src/shadcn/components/ui/field/FieldTitle.vue (1)

13-16: LGTM on class composition!

The class composition and styling logic are correctly implemented with appropriate group selectors for disabled states.

src/shadcn/components/ui/field/FieldSet.vue (1)

1-21: LGTM!

The component correctly uses the semantic <fieldset> element with proper TypeScript typing and appropriate has-[] selectors for nested component styling.

src/shadcn/components/ui/empty/Empty.vue (1)

1-20: LGTM!

The component follows consistent patterns with proper TypeScript typing, correct prop access, and appropriate responsive layout classes.

src/shadcn/components/ui/button/index.ts (1)

24-29: LGTM! Well-structured size variant expansion.

The new icon-sm and icon-lg variants follow the established pattern and use appropriate Tailwind sizing utilities (size-8 and size-10).

src/shadcn/components/ui/item/ItemContent.vue (1)

1-17: LGTM! Clean component structure.

The component follows Vue 3 best practices with proper TypeScript typing and the cn utility for flexible class composition.

src/shadcn/components/ui/field/FieldLegend.vue (1)

1-24: LGTM! Proper use of semantic HTML.

The component correctly uses the <legend> element with type-safe variant props and data attributes for flexible styling.

src/shadcn/components/ui/item/ItemDescription.vue (1)

1-21: LGTM! Well-styled description component.

The component includes thoughtful styling with line-clamp-2 for truncation, text-balance for improved readability, and proper link hover states.

src/shadcn/components/ui/field/FieldSeparator.vue (1)

1-29: LGTM! Elegant separator with optional label.

The component cleverly uses absolute positioning for the separator line and conditionally renders a centered label with background, creating a clean "text on line" visual effect.

src/shadcn/components/ui/button-group/ButtonGroup.vue (1)

1-22: LGTM! Proper accessibility semantics.

The component correctly uses role="group" for accessibility and maintains consistent prop references throughout.

src/shadcn/components/ui/input-group/InputGroupInput.vue (1)

12-18: No action needed: attributes are forwarded by default. Input.vue uses a native <input> root and doesn’t disable attribute inheritance, so undeclared props (e.g. placeholder, disabled, type) and v-model bindings passed through InputGroupInput flow into the native input automatically.

src/shadcn/components/ui/item/ItemGroup.vue (1)

1-18: LGTM!

The component implementation is clean and follows Vue 3 best practices. The use of role="list" provides appropriate semantic structure for accessibility, and the TypeScript typing is precise.

src/shadcn/components/ui/input-group/InputGroupAddon.vue (1)

1-36: LGTM!

The component correctly implements focus delegation for input group addons. The event handler properly prevents focus when clicking buttons inside the addon and safely uses optional chaining to handle edge cases.

src/shadcn/components/ui/item/Item.vue (1)

1-27: LGTM!

The component properly extends PrimitiveProps and integrates with the reka-ui Primitive component. The variant-based styling using CVA is correctly implemented.

src/shadcn/components/ui/input-group/InputGroupButton.vue (1)

1-21: LGTM!

The component properly wraps the Button component with input-group-specific variants. The default props (size: "xs" and variant: "ghost") are sensible defaults for input group contexts.

src/shadcn/components/ui/field/FieldError.vue (1)

1-44: LGTM!

The error handling logic is well-implemented:

  • Computed content correctly handles single vs. multiple errors
  • Proper accessibility with role="alert"
  • Flexible rendering supports custom slots, string messages, and error lists
  • Safe handling of undefined/null error objects
src/shadcn/components/ui/button-group/ButtonGroupText.vue (2)

1-16: LGTM!

The script setup follows Vue 3 Composition API best practices with proper TypeScript typing. The Props interface correctly extends PrimitiveProps and provides appropriate defaults via withDefaults.


18-29: LGTM!

The template correctly renders a Primitive wrapper with appropriate ARIA role and data attributes. The class composition using cn provides clean styling with proper Tailwind utilities and custom classes.

src/shadcn/components/ui/item/index.ts (3)

1-13: LGTM!

The imports and component exports are well-structured, following consistent naming conventions and proper module organization.


36-51: LGTM!

The itemMediaVariants CVA configuration is well-structured with appropriate variant options for different media presentation styles (default, icon, image).


53-54: LGTM!

The type exports correctly use VariantProps to expose typed variant props, following CVA best practices.

src/shadcn/components/ui/input-group/index.ts (5)

1-11: LGTM!

The imports and component exports are properly structured with appropriate dependencies on the button module for variant typing.


13-32: LGTM!

The inputGroupAddonVariants CVA configuration provides comprehensive alignment options (inline-start, inline-end, block-start, block-end) with appropriate styling for each position.


34-34: LGTM!

The type export correctly uses VariantProps to expose typed variant props from inputGroupAddonVariants.


36-51: LGTM!

The inputGroupButtonVariants CVA configuration provides appropriate size variants including icon-specific sizes, with sensible defaults.


53-59: LGTM!

The type exports and InputGroupButtonProps interface are well-defined, correctly referencing both local and imported variant types to provide comprehensive typing for the InputGroupButton component.

Comment on lines +8 to +23
export const buttonGroupVariants = cva(
"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
{
variants: {
orientation: {
horizontal:
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
vertical:
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
},
},
defaultVariants: {
orientation: "horizontal",
},
},
)
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

Format long lines to comply with max width guideline.

Multiple lines exceed the 100-character max width:

  • Line 9: 299 characters (base classes)
  • Line 13-14: 115 characters (horizontal variant)
  • Line 15-16: 126 characters (vertical variant)

Split these class strings for better readability.

As per coding guidelines.

Apply this diff to format the lines:

 export const buttonGroupVariants = cva(
-  "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
+  [
+    "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative",
+    "[&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
+    "has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md",
+    "has-[>[data-slot=button-group]]:gap-2",
+  ],
   {
     variants: {
       orientation: {
-        horizontal:
-          "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
-        vertical:
-          "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
+        horizontal: [
+          "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0",
+          "[&>*:not(:last-child)]:rounded-r-none",
+        ],
+        vertical: [
+          "flex-col [&>*:not(:first-child)]:rounded-t-none",
+          "[&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
+        ],
       },
     },
📝 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
export const buttonGroupVariants = cva(
"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
{
variants: {
orientation: {
horizontal:
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
vertical:
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
},
},
defaultVariants: {
orientation: "horizontal",
},
},
)
export const buttonGroupVariants = cva(
[
"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative",
"[&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
"has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md",
"has-[>[data-slot=button-group]]:gap-2",
],
{
variants: {
orientation: {
horizontal: [
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0",
"[&>*:not(:last-child)]:rounded-r-none",
],
vertical: [
"flex-col [&>*:not(:first-child)]:rounded-t-none",
"[&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
],
},
},
defaultVariants: {
orientation: "horizontal",
},
},
)
🤖 Prompt for AI Agents
In src/shadcn/components/ui/button-group/index.ts around lines 8 to 23, several
long class-string literals exceed the 100-character width limit; split the base
class string and each variant string into multiple shorter string literals (or
an array of strings joined with spaces) inside the cva call so each line stays
under 100 chars, preserving all class tokens and spacing and keeping the same
object shape and defaultVariants; ensure concatenation results in the exact same
final class string (no trailing/leading space loss) and keep the surrounding
cva(...) call and variant keys unchanged.

Comment on lines +13 to +16
:class="cn(
'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
$attrs.class ?? '',
)"
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

Inconsistent class prop usage.

The component defines class in props (line 5-7) but references $attrs.class in the template (line 15). This inconsistency can lead to unexpected behavior since class should be consumed from props, not attrs.

Apply this diff to fix the inconsistency:

     :class="cn(
       'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
-      $attrs.class ?? '',
+      props.class,
     )"

Alternatively, if you intend to use $attrs.class, remove class from the props definition:

-defineProps<{
-  class?: HTMLAttributes["class"]
-}>()
+defineProps<{}>()

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/shadcn/components/ui/empty/EmptyDescription.vue around lines 13 to 16,
the template references $attrs.class while the component defines class in its
props, causing inconsistency; update the template to consume the declared prop
(replace $attrs.class with the prop name, e.g., props.class or simply classProp
depending on your prop identifier) so the component uses the prop value, and
remove class from $attrs usage (or alternatively remove the class prop from the
props definition if you prefer to rely on $attrs) to keep class handling
consistent.

Comment on lines +5 to +15
defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>

<template>
<div
data-slot="empty-header"
:class="cn(
'flex max-w-sm flex-col items-center gap-2 text-center',
$attrs.class ?? '',
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

Fix incorrect class prop access.

The component defines class as a prop (lines 5-7) but then accesses it via $attrs.class (line 15). When a prop is explicitly declared with defineProps, it's removed from $attrs, so $attrs.class will always be undefined.

Apply this diff:

   <div
     data-slot="empty-header"
     :class="cn(
       'flex max-w-sm flex-col items-center gap-2 text-center',
-      $attrs.class ?? '',
+      props.class,
     )"
   >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/shadcn/components/ui/empty/EmptyHeader.vue around lines 5 to 15, the
component declares a prop named "class" via defineProps but then reads
$attrs.class in the template; since declared props are removed from $attrs this
will be undefined. Replace the $attrs.class access with the declared prop (i.e.,
use the prop value directly when composing the cn() call) or, alternatively,
stop declaring class as a prop and rely on $attrs — pick the former: reference
the declared class prop in the template (falling back to an empty string if
undefined) so the computed class includes the provided prop correctly.

Comment on lines +16 to +18
:data-variant="variant"
:class="cn(emptyMediaVariants({ variant }), props.class)"
>
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 | 🔴 Critical

Fix undefined variant references.

variant is not defined in this scope, so both the data-variant binding and the emptyMediaVariants call will throw at runtime. Reference the prop instead.

   <div
     data-slot="empty-icon"
-    :data-variant="variant"
-    :class="cn(emptyMediaVariants({ variant }), props.class)"
+    :data-variant="props.variant"
+    :class="cn(emptyMediaVariants({ variant: props.variant }), props.class)"
   >
📝 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
:data-variant="variant"
:class="cn(emptyMediaVariants({ variant }), props.class)"
>
<div
data-slot="empty-icon"
:data-variant="props.variant"
:class="cn(emptyMediaVariants({ variant: props.variant }), props.class)"
>
🤖 Prompt for AI Agents
In src/shadcn/components/ui/empty/EmptyMedia.vue around lines 16 to 18, the
template references an undefined local variable "variant" (in :data-variant and
emptyMediaVariants call); replace those references with the component prop
(e.g., props.variant or a destructured variant from defineProps/setup) so the
bindings use the declared prop value, ensuring the data-variant and class calls
reference a defined value.


<template>
<div
data-slot="empty-icon"
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

Incorrect data-slot attribute.

This component is EmptyTitle but the data-slot is set to "empty-icon". This appears to be a copy-paste error and will cause issues with slot-based selectors and component identification.

Apply this diff:

   <div
-    data-slot="empty-icon"
+    data-slot="empty-title"
     :data-variant="variant"
     :class="cn(emptyMediaVariants({ variant }), props.class)"
   >
📝 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
data-slot="empty-icon"
<div
data-slot="empty-title"
:data-variant="variant"
:class="cn(emptyMediaVariants({ variant }), props.class)"
>
🤖 Prompt for AI Agents
In src/shadcn/components/ui/empty/EmptyTitle.vue around line 15, the data-slot
attribute is incorrectly set to "empty-icon"; update it to "empty-title" so the
attribute matches the component name and intended slot selector, ensuring
slot-based selectors and component identification work correctly.

Comment on lines +11 to +24
export const emptyMediaVariants = cva(
"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-transparent",
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6",
},
},
defaultVariants: {
variant: "default",
},
},
)
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

Format long line to comply with max width guideline.

Line 17 exceeds the 100-character max width specified in the coding guidelines. Split the class string across multiple lines for better readability.

As per coding guidelines.

Apply this diff to format the line:

       variant: {
         default: "bg-transparent",
-        icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6",
+        icon:
+          "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg " +
+          "[&_svg:not([class*='size-'])]:size-6",
       },
     },
🤖 Prompt for AI Agents
In src/shadcn/components/ui/empty/index.ts around lines 11 to 24, the class
string on line 17 exceeds the 100-character max width; split the long class
string into multiple shorter strings (or an array joined with spaces) so each
line stays under 100 characters and preserves the exact combined class value,
keeping the cva call structure and variant keys unchanged.


<template>
<div
data-slot="field-label"
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

Incorrect data-slot attribute.

This component is FieldTitle but the data-slot is set to "field-label". This appears to be a copy-paste error and will cause issues with slot-based selectors and component identification.

Apply this diff:

   <div
-    data-slot="field-label"
+    data-slot="field-title"
     :class="cn(
       'flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50',
       props.class,
📝 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
data-slot="field-label"
<div
data-slot="field-title"
:class="cn(
'flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50',
props.class,
)>
🤖 Prompt for AI Agents
In src/shadcn/components/ui/field/FieldTitle.vue around line 12, the data-slot
attribute is incorrectly set to "field-label"; change it to "field-title" to
match the component name and ensure slot-based selectors and component
identification work correctly, and update any tests or CSS/selectors that
reference the old "field-label" data-slot accordingly.

Comment on lines +4 to +26
export const fieldVariants = cva(
"group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
{
variants: {
orientation: {
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
horizontal: [
"flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
responsive: [
"flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
},
},
defaultVariants: {
orientation: "vertical",
},
},
)
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

Format long lines to comply with max width guideline.

Lines 16 and 18 in the responsive variant exceed the 100-character max width:

  • Line 16: 133 characters
  • Line 18: 151 characters

Split these class strings for better readability.

As per coding guidelines.

Apply this diff to format the lines:

         responsive: [
-          "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
+          "flex-col [&>*]:w-full [&>.sr-only]:w-auto",
+          "@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
           "@md/field-group:[&>[data-slot=field-label]]:flex-auto",
-          "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
+          "@md/field-group:has-[>[data-slot=field-content]]:items-start",
+          "@md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
         ],
       },
📝 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
export const fieldVariants = cva(
"group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
{
variants: {
orientation: {
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
horizontal: [
"flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
responsive: [
"flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
},
},
defaultVariants: {
orientation: "vertical",
},
},
)
export const fieldVariants = cva(
"group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
{
variants: {
orientation: {
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
horizontal: [
"flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
responsive: [
"flex-col [&>*]:w-full [&>.sr-only]:w-auto",
"@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start",
"@md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
},
},
defaultVariants: {
orientation: "vertical",
},
},
)
🤖 Prompt for AI Agents
In src/shadcn/components/ui/field/index.ts around lines 4 to 26, the responsive
variant contains two very long class strings (lines ~16 and ~18) that exceed the
100-character width; split those long strings into multiple shorter strings
within the array (e.g., break the combined @md/field-group selectors into
separate array entries or separate quoted segments) so each line is under the
max width, preserve array ordering and commas, and keep the exact class tokens
unchanged aside from splitting so functionality stays the same.

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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/renderer/src/views/PlaygroundTabView.vue (2)

5-9: Replace hardcoded header text with i18n keys.

Lines 5-8 contain hardcoded user-facing text for the page header ("Shadcn Playground" and description). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update the template:

       <header class="space-y-3">
-        <h1 class="text-3xl font-semibold tracking-tight">Shadcn Playground</h1>
+        <h1 class="text-3xl font-semibold tracking-tight">{{ t('playground.header.title') }}</h1>
         <p class="text-muted-foreground">
-          Explore freshly installed @shadcn/ui components. These examples are for internal testing
-          only.
+          {{ t('playground.header.description') }}
         </p>
       </header>

Add corresponding keys to your i18n locale files.


56-196: Replace all hardcoded section and demo metadata with i18n keys.

The sections computed property (lines 56-196) contains extensive hardcoded user-facing strings including section titles, descriptions, demo titles, and demo descriptions. Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Refactor the sections array to use i18n keys. For example:

 const sections = computed(() => [
   {
-    title: 'Forms & Inputs',
-    description:
-      'Combination of input primitives like buttons, inputs, textarea, checkbox, switch.',
+    title: t('playground.sections.formsInputs.title'),
+    description: t('playground.sections.formsInputs.description'),
     columns: 2,
     component: DemoSection,
     demos: [
       {
-        title: 'Form Elements',
-        description: 'Basic form layout using button, input, textarea, checkbox, and switch.',
+        title: t('playground.demos.formElements.title'),
+        description: t('playground.demos.formElements.description'),
         componentName: '@shadcn/components/ui',
         render: FormDemo
       },

Apply similar changes to all section titles, descriptions, demo titles, and demo descriptions throughout the entire sections array. Add corresponding keys to your i18n locale files.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 299185c and 915dd17.

📒 Files selected for processing (8)
  • src/renderer/src/views/PlaygroundTabView.vue (5 hunks)
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/EmptyDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/FieldDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/ItemDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/KbdDemo.vue (1 hunks)
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue (1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.vue
src/renderer/**/*.{vue,ts}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.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/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue components in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/views/playground/demos/FieldDemo.vue
  • src/renderer/src/views/playground/demos/SpinnerDemo.vue
  • src/renderer/src/views/playground/demos/KbdDemo.vue
  • src/renderer/src/views/playground/demos/InputGroupDemo.vue
  • src/renderer/src/views/playground/demos/ButtonGroupDemo.vue
  • src/renderer/src/views/playground/demos/EmptyDemo.vue
  • src/renderer/src/views/playground/demos/ItemDemo.vue
  • src/renderer/src/views/PlaygroundTabView.vue
🧠 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} : Use Iconify/Vue for icon implementation.

Applied to files:

  • src/renderer/src/views/playground/demos/EmptyDemo.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)

Comment on lines +1 to +30
<template>
<div class="space-y-4">
<ButtonGroup class="w-full">
<Button variant="ghost" size="sm" class="flex-1">Day</Button>
<Button size="sm" class="flex-1">Week</Button>
<ButtonGroupSeparator />
<Button variant="ghost" size="sm" class="flex-1">Month</Button>
<Button variant="ghost" size="sm" class="flex-1">Year</Button>
</ButtonGroup>

<ButtonGroup orientation="vertical" class="w-full">
<ButtonGroupText class="justify-between">
<span class="text-xs uppercase tracking-wide text-muted-foreground">Team access</span>
<span class="text-xs text-muted-foreground">4 members</span>
</ButtonGroupText>
<Button variant="ghost" class="justify-between">
<span>Marketing</span>
<span class="text-xs text-muted-foreground">Owner</span>
</Button>
<Button variant="ghost" class="justify-between">
<span>Engineering</span>
<span class="text-xs text-muted-foreground">Can edit</span>
</Button>
<Button variant="ghost" class="justify-between">
<span>Support</span>
<span class="text-xs text-muted-foreground">Can view</span>
</Button>
</ButtonGroup>
</div>
</template>
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 | 🔴 Critical

Replace all hardcoded UI text with i18n keys.

The template contains numerous hardcoded user-facing strings (button labels "Day", "Week", "Month", "Year", section headers "Team access", "4 members", team names, and role labels). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff to the script section:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update all hardcoded strings in the template to use {{ t('key') }} pattern. For example:

-      <Button variant="ghost" size="sm" class="flex-1">Day</Button>
-      <Button size="sm" class="flex-1">Week</Button>
+      <Button variant="ghost" size="sm" class="flex-1">{{ t('playground.buttonGroup.day') }}</Button>
+      <Button size="sm" class="flex-1">{{ t('playground.buttonGroup.week') }}</Button>

Apply similar changes to all other user-facing strings and add corresponding keys to your i18n locale files.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/ButtonGroupDemo.vue lines 1-30:
template contains hardcoded user-facing strings (Day, Week, Month, Year, Team
access, 4 members, Marketing, Engineering, Support, Owner, Can edit, Can view).
Replace each with vue-i18n lookups (use the t('...') pattern), add a script
section using useI18n (or ensure t is available in the component setup/Options
API), and wire keys such as playground.button.day, playground.button.week,
playground.button.month, playground.button.year, playground.team.title,
playground.team.count, playground.team.marketing, playground.team.engineering,
playground.team.support, playground.role.owner, playground.role.canEdit,
playground.role.canView (or equivalent names consistent with your locale
structure) into your locale JSON/YAML files. Ensure the template uses {{
t('...') }} or v-t where appropriate and update all strings accordingly so no
hardcoded user-visible text remains.

Comment on lines +7 to +14
<EmptyTitle>No conversations yet</EmptyTitle>
<EmptyDescription>
Start a new thread to keep track of customer questions and follow-ups.
</EmptyDescription>
</EmptyHeader>
<EmptyContent class="flex flex-col sm:flex-row gap-2">
<Button>New conversation</Button>
<Button variant="outline">Import history</Button>
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 | 🔴 Critical

Replace hardcoded UI text with i18n keys.

Lines 7-14 contain hardcoded user-facing text including the title "No conversations yet", the description, and button labels "New conversation" and "Import history". Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update the template:

     <EmptyHeader>
-      <EmptyTitle>No conversations yet</EmptyTitle>
+      <EmptyTitle>{{ t('playground.empty.noConversations') }}</EmptyTitle>
       <EmptyDescription>
-        Start a new thread to keep track of customer questions and follow-ups.
+        {{ t('playground.empty.description') }}
       </EmptyDescription>
     </EmptyHeader>
     <EmptyContent class="flex flex-col sm:flex-row gap-2">
-      <Button>New conversation</Button>
-      <Button variant="outline">Import history</Button>
+      <Button>{{ t('playground.empty.newConversation') }}</Button>
+      <Button variant="outline">{{ t('playground.empty.importHistory') }}</Button>
     </EmptyContent>

Add corresponding keys to your i18n locale 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
<EmptyTitle>No conversations yet</EmptyTitle>
<EmptyDescription>
Start a new thread to keep track of customer questions and follow-ups.
</EmptyDescription>
</EmptyHeader>
<EmptyContent class="flex flex-col sm:flex-row gap-2">
<Button>New conversation</Button>
<Button variant="outline">Import history</Button>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
// …other imports and setup remain unchanged
</script>
<template>
<EmptyHeader>
<EmptyTitle>{{ t('playground.empty.noConversations') }}</EmptyTitle>
<EmptyDescription>
{{ t('playground.empty.description') }}
</EmptyDescription>
</EmptyHeader>
<EmptyContent class="flex flex-col sm:flex-row gap-2">
<Button>{{ t('playground.empty.newConversation') }}</Button>
<Button variant="outline">{{ t('playground.empty.importHistory') }}</Button>
</EmptyContent>
</template>
🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/EmptyDemo.vue around lines 7 to 14,
replace the hardcoded UI strings ("No conversations yet", the description, "New
conversation", "Import history") with vue-i18n translation keys (e.g.
$t('playground.empty.title'), $t('playground.empty.description'),
$t('playground.empty.newConversation'), $t('playground.empty.importHistory')) in
the template, update any Button props to use the translation calls, and then add
those keys with appropriate translations to the locale JSON/YAML files used by
the app (e.g. en.json and other locales) so the strings are available at
runtime.

Comment on lines +1 to +50
<template>
<FieldSet class="max-w-xl space-y-6">
<FieldLegend class="text-base font-semibold">Notification preferences</FieldLegend>
<FieldDescription class="text-sm text-muted-foreground">
Arrange label, helper text, and controls with a11y-friendly field primitives.
</FieldDescription>

<FieldGroup>
<Field orientation="responsive">
<FieldLabel for="digest" class="font-medium">Weekly product digest</FieldLabel>
<FieldContent>
<Switch id="digest" />
<FieldDescription class="text-sm text-muted-foreground">
Receive a summary of key updates every Monday morning.
</FieldDescription>
</FieldContent>
</Field>

<Field orientation="responsive">
<FieldLabel for="channel" class="font-medium">Default channel</FieldLabel>
<FieldContent class="gap-2">
<Select>
<SelectTrigger id="channel" class="w-full sm:w-48">
<SelectValue placeholder="Choose channel" />
</SelectTrigger>
<SelectContent>
<SelectItem value="email">Email</SelectItem>
<SelectItem value="slack">Slack</SelectItem>
<SelectItem value="teams">Teams</SelectItem>
</SelectContent>
</Select>
<FieldDescription class="text-sm text-muted-foreground">
Where notifications should arrive by default.
</FieldDescription>
</FieldContent>
</Field>

<Field orientation="responsive" data-invalid="true">
<FieldLabel for="quota" class="font-medium">Usage quota</FieldLabel>
<FieldContent>
<Input id="quota" type="number" min="0" placeholder="25" aria-invalid="true" />
<FieldDescription class="text-sm text-muted-foreground">
The maximum number of alerts your team can trigger each day.
</FieldDescription>
<FieldError :errors="[{ message: 'Provide a value between 10 and 50.' }]" />
</FieldContent>
</Field>
</FieldGroup>
</FieldSet>
</template>
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 | 🔴 Critical

Replace all hardcoded UI text with i18n keys.

The template contains extensive hardcoded user-facing strings including the legend ("Notification preferences"), descriptions, labels ("Weekly product digest", "Default channel", "Usage quota"), helper text, placeholder ("Choose channel"), and error message ("Provide a value between 10 and 50."). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff to the script section:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update all hardcoded strings in the template to use {{ t('key') }} pattern. For example:

   <FieldSet class="max-w-xl space-y-6">
-    <FieldLegend class="text-base font-semibold">Notification preferences</FieldLegend>
+    <FieldLegend class="text-base font-semibold">{{ t('playground.field.notificationPreferences') }}</FieldLegend>
     <FieldDescription class="text-sm text-muted-foreground">
-      Arrange label, helper text, and controls with a11y-friendly field primitives.
+      {{ t('playground.field.description') }}
     </FieldDescription>

Apply similar changes to all other user-facing strings, including the error message on line 45, and add corresponding keys to your i18n locale files.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/FieldDemo.vue around lines 1 to 50,
the template contains hardcoded user-facing strings that must be replaced with
vue-i18n keys; update the script section to import/use the i18n composable
(e.g., import { useI18n } from 'vue-i18n' and const { t } = useI18n()) and then
replace every hardcoded string in the template with interpolation calls like {{
t('path.to.key') }} or attributes bound to t('path.to.key') (e.g.,
:placeholder="t('...')" or <FieldError :errors="[{ message: t('...') }]" />),
create appropriate keys for each string in your locale files, and ensure aria
and id attributes remain unchanged while using translation keys for all visible
text.

Comment on lines +1 to +26
<template>
<div class="space-y-4">
<InputGroup>
<InputGroupAddon>
<Icon icon="lucide:search" class="w-4 h-4" />
<InputGroupText>Search docs</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Ask anything..." />
<InputGroupButton size="icon-sm" variant="ghost">
<Icon icon="lucide:command" class="w-4 h-4" />
</InputGroupButton>
</InputGroup>

<InputGroup class="w-full">
<InputGroupAddon align="block-start" class="border-b">
<InputGroupText class="font-medium text-foreground">Invite message</InputGroupText>
<InputGroupText class="text-xs text-muted-foreground">Shared with the team</InputGroupText>
</InputGroupAddon>
<InputGroupTextarea rows="3" placeholder="Hi team! Here's what changed in this release..." />
<InputGroupAddon align="block-end" class="border-t justify-between">
<InputGroupText class="text-xs text-muted-foreground">Markdown supported</InputGroupText>
<InputGroupButton size="xs" variant="outline">Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>
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 | 🔴 Critical

Replace all hardcoded UI text with i18n keys.

The template contains hardcoded user-facing strings including labels ("Search docs", "Invite message", "Shared with the team", "Markdown supported"), placeholders ("Ask anything...", "Hi team! Here's what changed..."), and button text ("Send"). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff to the script section:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update all hardcoded strings in the template to use {{ t('key') }} pattern. For example:

       <InputGroupAddon>
         <Icon icon="lucide:search" class="w-4 h-4" />
-        <InputGroupText>Search docs</InputGroupText>
+        <InputGroupText>{{ t('playground.inputGroup.searchDocs') }}</InputGroupText>
       </InputGroupAddon>
-      <InputGroupInput placeholder="Ask anything..." />
+      <InputGroupInput :placeholder="t('playground.inputGroup.askPlaceholder')" />

Apply similar changes to all other user-facing strings and add corresponding keys to your i18n locale 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
<template>
<div class="space-y-4">
<InputGroup>
<InputGroupAddon>
<Icon icon="lucide:search" class="w-4 h-4" />
<InputGroupText>Search docs</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Ask anything..." />
<InputGroupButton size="icon-sm" variant="ghost">
<Icon icon="lucide:command" class="w-4 h-4" />
</InputGroupButton>
</InputGroup>
<InputGroup class="w-full">
<InputGroupAddon align="block-start" class="border-b">
<InputGroupText class="font-medium text-foreground">Invite message</InputGroupText>
<InputGroupText class="text-xs text-muted-foreground">Shared with the team</InputGroupText>
</InputGroupAddon>
<InputGroupTextarea rows="3" placeholder="Hi team! Here's what changed in this release..." />
<InputGroupAddon align="block-end" class="border-t justify-between">
<InputGroupText class="text-xs text-muted-foreground">Markdown supported</InputGroupText>
<InputGroupButton size="xs" variant="outline">Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>
<template>
<div class="space-y-4">
<InputGroup>
<InputGroupAddon>
<Icon icon="lucide:search" class="w-4 h-4" />
<InputGroupText>{{ t('playground.inputGroup.searchDocs') }}</InputGroupText>
</InputGroupAddon>
<InputGroupInput :placeholder="t('playground.inputGroup.askPlaceholder')" />
<InputGroupButton size="icon-sm" variant="ghost">
<Icon icon="lucide:command" class="w-4 h-4" />
</InputGroupButton>
</InputGroup>
<InputGroup class="w-full">
<InputGroupAddon align="block-start" class="border-b">
<InputGroupText class="font-medium text-foreground">{{ t('playground.inputGroup.inviteMessage') }}</InputGroupText>
<InputGroupText class="text-xs text-muted-foreground">{{ t('playground.inputGroup.sharedWithTeam') }}</InputGroupText>
</InputGroupAddon>
<InputGroupTextarea rows="3" :placeholder="t('playground.inputGroup.hiTeamPlaceholder')" />
<InputGroupAddon align="block-end" class="border-t justify-between">
<InputGroupText class="text-xs text-muted-foreground">{{ t('playground.inputGroup.markdownSupported') }}</InputGroupText>
<InputGroupButton size="xs" variant="outline">{{ t('playground.inputGroup.send') }}</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>
🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/InputGroupDemo.vue around lines 1-26,
replace all hardcoded user-facing strings with vue-i18n keys: add a script (or
script setup) block that imports and calls useI18n (const { t } = useI18n()),
then update template text nodes to use {{ t('your.key') }}, update attributes
and props such as placeholders to use bindings like :placeholder="t('your.key')"
and component children (e.g., InputGroupText, button label) to use the t() call,
and add corresponding translation keys/values to the locale JSON files; ensure
keys are descriptive (e.g., playground.input.searchLabel,
playground.input.placeholder.ask) and replace each hardcoded string mentioned in
the comment accordingly.

Comment on lines +1 to +41
<template>
<ItemGroup class="w-full space-y-3">
<Item variant="outline">
<ItemMedia variant="icon">
<Icon icon="lucide:palette" class="w-4 h-4" />
</ItemMedia>
<ItemContent>
<ItemHeader>
<ItemTitle>Brand refresh</ItemTitle>
<ItemDescription>Update the marketing site with the new palette.</ItemDescription>
</ItemHeader>
<ItemFooter class="flex flex-wrap gap-2 text-xs text-muted-foreground">
<span class="inline-flex items-center gap-1">
<Icon icon="lucide:user" class="w-3 h-3" />
Design team
</span>
<span class="inline-flex items-center gap-1">
<Icon icon="lucide:calendar" class="w-3 h-3" />
Due Friday
</span>
</ItemFooter>
</ItemContent>
<ItemActions class="ml-auto flex items-center gap-2">
<Button variant="outline" size="sm">Preview</Button>
<Button size="sm">Open</Button>
</ItemActions>
</Item>

<Item variant="muted" size="sm">
<ItemMedia variant="icon">
<Icon icon="lucide:bell" class="w-4 h-4" />
</ItemMedia>
<ItemContent>
<ItemHeader>
<ItemTitle>Notifications paused</ItemTitle>
<ItemDescription>You're in focus mode until 4:00 PM.</ItemDescription>
</ItemHeader>
</ItemContent>
</Item>
</ItemGroup>
</template>
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 | 🔴 Critical

Replace all hardcoded UI text with i18n keys.

The template contains numerous hardcoded user-facing strings including titles ("Brand refresh", "Notifications paused"), descriptions, labels ("Design team", "Due Friday"), and button text ("Preview", "Open"). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff to the script section:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update all hardcoded strings in the template to use {{ t('key') }} pattern. For example:

         <ItemHeader>
-          <ItemTitle>Brand refresh</ItemTitle>
-          <ItemDescription>Update the marketing site with the new palette.</ItemDescription>
+          <ItemTitle>{{ t('playground.item.brandRefresh') }}</ItemTitle>
+          <ItemDescription>{{ t('playground.item.brandRefreshDesc') }}</ItemDescription>
         </ItemHeader>

Apply similar changes to all other user-facing strings and add corresponding keys to your i18n locale files.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/ItemDemo.vue around lines 1-41, the
template contains hardcoded user-visible strings; replace each with vue-i18n
keys by importing and exposing the i18n `t` function in the script section
(e.g., using const { t } = useI18n() or setup return) and update the template to
use {{ t('playground.item.brandTitle') }} style calls for every title,
description, label and button text (Brand refresh, Update the marketing site...,
Design team, Due Friday, Preview, Open, Notifications paused, You're in focus
mode until 4:00 PM., etc.). Add matching keys and translations to the locale
files under src/renderer/src/locales (or the project’s i18n locale paths) with
appropriate namespaces (e.g., playground.item) and ensure the script returns or
exposes `t` so the template can resolve the keys.

Comment on lines +10 to +23
<h4 class="text-sm font-semibold">Editor shortcuts</h4>
<ul class="space-y-2 text-sm text-muted-foreground">
<li class="flex items-center justify-between">
Comment selection
<Kbd>⌘ /</Kbd>
</li>
<li class="flex items-center justify-between">
Format document
<Kbd>Shift Alt F</Kbd>
</li>
<li class="flex items-center justify-between">
Open palette
<Kbd>⌘ Shift P</Kbd>
</li>
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 | 🔴 Critical

Replace hardcoded UI labels with i18n keys.

Lines 10, 13, 17, and 21 contain hardcoded user-facing labels ("Editor shortcuts", "Comment selection", "Format document", "Open palette"). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update the template:

-      <h4 class="text-sm font-semibold">Editor shortcuts</h4>
+      <h4 class="text-sm font-semibold">{{ t('playground.kbd.editorShortcuts') }}</h4>
       <ul class="space-y-2 text-sm text-muted-foreground">
         <li class="flex items-center justify-between">
-          Comment selection
+          {{ t('playground.kbd.commentSelection') }}
           <Kbd>⌘ /</Kbd>
         </li>
         <li class="flex items-center justify-between">
-          Format document
+          {{ t('playground.kbd.formatDocument') }}
           <Kbd>Shift Alt F</Kbd>
         </li>
         <li class="flex items-center justify-between">
-          Open palette
+          {{ t('playground.kbd.openPalette') }}
           <Kbd>⌘ Shift P</Kbd>
         </li>

Add corresponding keys to your i18n locale files.

🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/KbdDemo.vue around lines 10 to 23,
replace the hardcoded user-visible strings ("Editor shortcuts", "Comment
selection", "Format document", "Open palette") with vue-i18n translation keys
(e.g. use $t('playground.kbd.title'), $t('playground.kbd.commentSelection'),
$t('playground.kbd.formatDocument'), $t('playground.kbd.openPalette') or similar
names), update the template to call $t for each label, and add the corresponding
keys and translations to your locale files under src/renderer/src/locales (for
all supported locales) so the UI uses i18n instead of hardcoded text.

Comment on lines +8 to +9
<p class="text-sm font-medium">Syncing integrations</p>
<p class="text-xs text-muted-foreground">We’ll notify you once everything is connected.</p>
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 | 🔴 Critical

Replace hardcoded strings with i18n keys.

Lines 8-9 contain hardcoded user-facing text ("Syncing integrations", "We'll notify you once everything is connected."). Per coding guidelines, all user-visible strings in src/renderer/src/**/* must use vue-i18n translation keys.

As per coding guidelines.

Apply this diff:

+import { useI18n } from 'vue-i18n'
+
+const { t } = useI18n()

Then update the template:

-        <p class="text-sm font-medium">Syncing integrations</p>
-        <p class="text-xs text-muted-foreground">We'll notify you once everything is connected.</p>
+        <p class="text-sm font-medium">{{ t('playground.spinner.syncingIntegrations') }}</p>
+        <p class="text-xs text-muted-foreground">{{ t('playground.spinner.notifyMessage') }}</p>

Add corresponding keys to your i18n locale files.

🤖 Prompt for AI Agents
In src/renderer/src/views/playground/demos/SpinnerDemo.vue around lines 8-9, the
two hardcoded user-facing strings ("Syncing integrations" and "We’ll notify you
once everything is connected.") must be replaced with vue-i18n translation keys;
update the template to call $t('playground.spinner.syncingIntegrations') and
$t('playground.spinner.syncingNotice') (or similar key names consistent with
your namespace), and add corresponding entries to each locale JSON/YAML used by
the app (e.g., en.json, fr.json) with translated values; ensure keys follow
existing key naming conventions and run a quick lint/typecheck to confirm no
template errors.

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/components/settings/ShortcutSettings.vue (1)

335-356: Global shortcuts remain disabled after cancel; centralize enable/disable.

If the user presses Esc (cancel), shortcuts stay disabled because enableShortcutKey() isn’t called. Also, Enter path enables early and saveChanges() toggles again. Move enable into stopRecording and remove the early enable for consistency.

--- a/src/renderer/src/components/settings/ShortcutSettings.vue
+++ b/src/renderer/src/components/settings/ShortcutSettings.vue
@@
-  if (event.key === 'Enter' && tempShortcut.value) {
+  if (event.key === 'Enter' && tempShortcut.value) {
     // 验证快捷键是否合法
     if (validateShortcut(tempShortcut.value)) {
       saveAndStopRecording()
-      shortcutKeyStore.enableShortcutKey()
     }
     // 注意:错误信息会在 validateShortcut 中设置,不需要在这里清除
     return
   }
@@
 const stopRecording = () => {
   if (recordingShortcutId.value) {
     recordingShortcutId.value = null
     window.removeEventListener('keydown', handleKeyDown, { capture: true })
 
     // 恢复默认行为
     document.body.style.overflow = ''
+    // Re-enable global shortcuts after any recording ends
+    shortcutKeyStore.enableShortcutKey()
   }
 }
+
+// Ensure cleanup if component unmounts during recording
+onBeforeUnmount(() => {
+  stopRecording()
+})
@@
-import { ref, computed } from 'vue'
+import { ref, computed, onBeforeUnmount } from 'vue'

Also applies to: 398-405, 416-425

🧹 Nitpick comments (6)
src/renderer/src/components/settings/ShortcutSettings.vue (6)

30-57: Kbd UI looks solid; minor i18n nit for placeholders.

The grouped Kbd rendering and state classes are clean. Consider replacing the hardcoded placeholders ‘…’ (Line 48) and ‘—’ (Line 55) with i18n keys to fully comply with renderer i18n rules. Based on coding guidelines


58-84: Add aria-labels to icon-only buttons for a11y.

Relying on title alone is not sufficient for screen readers. Bind aria-label to the same i18n text.

-                  <Button
+                  <Button
                     v-if="!shortcut.disabled"
                     variant="ghost"
                     size="icon"
                     class="h-8 w-8 text-muted-foreground hover:text-primary"
-                    :title="t('common.edit')"
+                    :title="t('common.edit')"
+                    :aria-label="t('common.edit')"
                     @click.stop="startRecording(shortcut.id)"
                   >
                     <Icon icon="lucide:pencil" class="h-4 w-4" />
                   </Button>
-                  <Button
+                  <Button
                     v-if="!shortcut.disabled && shortcut.key.length"
                     variant="ghost"
                     size="icon"
                     class="h-8 w-8 text-muted-foreground hover:text-destructive"
-                    :title="t('settings.shortcuts.clearShortcut')"
+                    :title="t('settings.shortcuts.clearShortcut')"
+                    :aria-label="t('settings.shortcuts.clearShortcut')"
                     @click.stop="clearShortcut(shortcut.id)"
                   >
                     <Icon icon="lucide:x" class="h-4 w-4" />
                   </Button>

135-143: DRY up and guard platform detection (SSR-safe).

navigator/window is used directly twice; extract a small helper and guard for SSR to avoid reference errors in non-DOM contexts. Based on coding guidelines

Add once (outside the shown ranges):

const isMacPlatform = () =>
  typeof navigator !== 'undefined' &&
  /Mac|iPod|iPhone|iPad/i.test(navigator.platform)

Then update within these ranges:

-  const isMac = navigator.platform.toLowerCase().includes('mac')
+  const isMac = isMacPlatform()
-    .replace(
-      'CommandOrControl',
-      /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) ? '⌘' : 'Ctrl'
-    )
+    .replace('CommandOrControl', isMacPlatform() ? '⌘' : 'Ctrl')

Also applies to: 268-285


131-146: Logs/comments should be English-only per repo standards.

Several comments are in Chinese, and one console error (Line 308). Please convert to English for consistency. Based on coding guidelines

-    console.error('重置快捷键失败:', error)
+    console.error('Reset shortcut keys failed:', error)

If helpful, I can submit a pass converting inline comments to concise English.

Also applies to: 308-308


85-98: Optional: Announce recording status to AT.

Consider wrapping the hint text in a live region (role="status" aria-live="polite") so screen readers announce errors and instructions while recording.


215-218: Consistent spelling confirmed; optional rename
The key SwtichToLastTab is used consistently across ShortcutSettings.vue, shortcutKeySettings.ts, and shortcutPresenter.ts—no mismatches. If this is unintended, rename it to SwitchToLastTab and update all references.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 915dd17 and 19cfd77.

📒 Files selected for processing (1)
  • src/renderer/src/components/settings/ShortcutSettings.vue (4 hunks)
🧰 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/settings/ShortcutSettings.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.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/settings/ShortcutSettings.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue components in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/settings/ShortcutSettings.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (1)
src/renderer/src/components/settings/ShortcutSettings.vue (1)

118-118: New Kbd imports: Looks good. Ensure dependency presence.

Assuming shadcn kbd exports are added, this import is correct.

If not already, ensure @shadcn/components/ui/kbd index re-exports Kbd and KbdGroup in the regenerated shadcn sources.

@zerob13 zerob13 merged commit a2f14d4 into dev Oct 9, 2025
2 checks passed
zerob13 added a commit that referenced this pull request Oct 9, 2025
* chore(shadcn): sync new ui components

* chore(playground): showcase new shadcn suites

* feat: replace kbg and kb for ShortcutSettings
zerob13 added a commit that referenced this pull request Oct 9, 2025
* feat(ui): new prompt input and layout wip

* feat(provider-db): support reasoning/search objects (#964)

* chore: sync shadcn components (#963)

* chore(shadcn): sync new ui components

* chore(playground): showcase new shadcn suites

* feat: replace kbg and kb for ShortcutSettings

* feat(ui): prompt input with new chooser

---------

Co-authored-by: yyhhyyyyyy <yyhhyyyyyy8@gmail.com>
This was referenced Oct 10, 2025
@zerob13 zerob13 deleted the codex/integrate-new-shadcn-vue-components branch November 23, 2025 13:52
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.

2 participants