feat(ui): 侧栏、底栏与状态指示器多项体验优化#20
Conversation
- 侧栏:摄像头/屏幕/浏览器 Tab 与预览区对齐;直播/会话标签移入预览框内 - 底栏:压缩输入区高度;Footer 间距与折叠按钮布局;麦克风/举手按钮点击反馈 - 字幕:毛玻璃背景 - 状态:WebSocket 与 AI 状态文案更明确;AI 指示器与连接状态并排、颜色随状态变化 - 聊天:主容器居中对称,为收起按钮保留完整宽度 - 侧栏:Chakra Tooltip 与 Mode Menu 冲突,模式按钮改回 title - 国际化:tooltip、wsStatus、aiState 等中英文更新 Made-with: Cursor
📝 WalkthroughWalkthroughThis PR refactors the UI layout by repositioning indicators and controls from dedicated headers to absolutely-positioned overlays within containers, applies styling refinements for visual polish, and adds comprehensive internationalization support with translated tooltips throughout sidebar and footer controls. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (1)
src/renderer/src/components/footer/ai-state-indicator.tsx (1)
5-12: UseRecord<AiStateEnum, string>to enforce exhaustive state-color mapping.
Record<string, string>permits arbitrary string keys and allows missing enum mappings to pass type-checking. Change toRecord<AiStateEnum, string>to make the mapping exhaustive and eliminate the defensive fallback.Refactor
-const stateColors: Record<string, string> = { +const stateColors: Record<AiStateEnum, string> = { [AiStateEnum.IDLE]: 'gray.500', [AiStateEnum.THINKING_SPEAKING]: '#7C5CFF', [AiStateEnum.INTERRUPTED]: 'orange.500', [AiStateEnum.LOADING]: 'yellow.500', [AiStateEnum.LISTENING]: 'blue.400', [AiStateEnum.WAITING]: 'gray.500', }; -const color = stateColors[aiState] || 'gray.500'; +const color = stateColors[aiState];Also applies to: 17-17
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/src/components/footer/ai-state-indicator.tsx` around lines 5 - 12, Change the stateColors declaration from Record<string, string> to Record<AiStateEnum, string> and ensure every AiStateEnum member is present in the mapping (add any missing enum keys such as X if applicable) so the compiler enforces exhaustiveness; update the symbol stateColors and validate usages of AiStateEnum (e.g., in ai-state-indicator.tsx) to remove the need for a defensive fallback since the mapping is now exhaustive.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderer/src/components/footer/footer-styles.tsx`:
- Line 24: The footer collapsed translateY uses a 20px handle (transform:
isCollapsed ? 'translateY(calc(100% - 20px))'...), but App.tsx still uses
hardcoded subtitle offsets (39px / 135px) causing vertical drift; change App.tsx
to compute subtitle anchor offsets from a single source of truth instead of
magic numbers—either export a FOOTER_HANDLE_HEIGHT (or FOOTER_COLLAPSED_HANDLE)
from src/renderer/src/components/footer/footer-styles.tsx and use it to compute
the offsets in the subtitle positioning logic in App.tsx, or derive the offsets
at runtime from the footer element (query by its component ID/class and read its
clientHeight) so isCollapsed, translateY and subtitle offsets stay in sync.
In `@src/renderer/src/components/footer/footer.tsx`:
- Around line 79-80: Replace hard-coded aria-label strings in the Footer
component with localized translation keys: import and call the i18n hook (e.g.,
useTranslation) at the top of the Footer component, then replace
aria-label="Raise hand" and the other static aria-labels around lines referenced
with aria-label={t('footer.raiseHand')} (and corresponding keys like
'footer.someOtherAction') so the Button/Action components use t('...') instead
of literal English; update translation files with the new keys.
- Around line 66-75: The IconButton used for the mic toggle (IconButton with
props bg, onClick={onMicToggle}, using micOn and icons BsMicFill/BsMicMuteFill)
is icon-only and needs an accessible name; add an explicit accessible label and
toggle state by supplying props like aria-label (e.g., aria-label={micOn ? "Mute
microphone" : "Unmute microphone"}) and aria-pressed={micOn} (or aria-checked if
using role="switch") to the IconButton so screen readers can announce the button
and its state.
- Around line 45-54: Replace the non-semantic clickable Box with a real button
element (e.g., Chakra UI Box with as="button" or an IconButton) so it becomes
keyboard-accessible and behaves like a native control; keep the existing props
footerStyles.footer.toggleButton and the onToggle handler, add type="button",
include aria-expanded={isCollapsed} and an accessible name via
aria-label="Toggle footer collapse" (or visually-hidden text) and preserve the
transform style based on isCollapsed; update the element rendering the
FiChevronDown accordingly so the visual appearance stays the same.
In `@src/renderer/src/components/sidebar/browser-panel.tsx`:
- Around line 55-57: The absolute positioned session label Box (the Box
rendering t('sidebar.browserSession') in browser-panel.tsx) is intercepting
iframe clicks; make that Box non-interactive by disabling pointer events and
accessibility interception (e.g., set CSS pointer-events to 'none' and mark it
aria-hidden) so it no longer captures mouse events or screen-reader focus while
keeping the visual label intact.
In `@src/renderer/src/components/sidebar/sidebar.tsx`:
- Around line 71-85: The hardcoded English strings for the mode options bypass
localization; update the Menu.RadioItem labels and the disabled title to use the
app's i18n/messages (e.g., call t('liveMode'), t('petMode'), and
t('petModeDesktopOnlyHint')) instead of literal "Live Mode", "Pet Mode" and the
inline title; locate the two Menu.RadioItem components (the one with value "pet"
and its sibling for Live mode) and replace the visible text and the
title={!isElectron ? "Pet mode is only available in desktop app" : undefined}
with localized lookups, leaving the isElectron guard and setMode('pet') logic
unchanged.
- Around line 99-129: The sidebar icon-only Buttons (the Button inside the
Settings area with onSettingsOpen, the Button wrapped by GroupDrawer, the Button
wrapped by HistoryDrawer, and the New Chat Button with onNewHistory) currently
rely on tooltips for identification; add explicit localized aria-label
attributes to each Button using the same translation keys (e.g.,
t('tooltip.settings'), t('tooltip.group'), t('tooltip.chatHistory'),
t('tooltip.newChat')) so screen readers receive accessible names independent of
the Tooltip component.
- Around line 40-46: The sidebar toggle is currently a clickable Box
(sidebarStyles.sidebar.toggleButton) with onClick and transform but lacks
keyboard and ARIA semantics; make it keyboard-accessible by giving that Box
role="button", tabIndex={0}, and an accessible name (e.g., aria-label="Toggle
sidebar" or aria-labelledby pointing to a label), add a keyDown handler on the
same element that calls onToggle when Enter or Space is pressed, and consider
using aria-pressed or aria-expanded (tied to isCollapsed) to expose state to
assistive tech.
---
Nitpick comments:
In `@src/renderer/src/components/footer/ai-state-indicator.tsx`:
- Around line 5-12: Change the stateColors declaration from Record<string,
string> to Record<AiStateEnum, string> and ensure every AiStateEnum member is
present in the mapping (add any missing enum keys such as X if applicable) so
the compiler enforces exhaustiveness; update the symbol stateColors and validate
usages of AiStateEnum (e.g., in ai-state-indicator.tsx) to remove the need for a
defensive fallback since the mapping is now exhaustive.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fbab6dbc-0581-4564-94f4-0503d385566a
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (12)
src/renderer/src/App.tsxsrc/renderer/src/components/canvas/canvas-styles.tsxsrc/renderer/src/components/footer/ai-state-indicator.tsxsrc/renderer/src/components/footer/footer-styles.tsxsrc/renderer/src/components/footer/footer.tsxsrc/renderer/src/components/sidebar/browser-panel.tsxsrc/renderer/src/components/sidebar/camera-panel.tsxsrc/renderer/src/components/sidebar/screen-panel.tsxsrc/renderer/src/components/sidebar/sidebar-styles.tsxsrc/renderer/src/components/sidebar/sidebar.tsxsrc/renderer/src/locales/en/translation.jsonsrc/renderer/src/locales/zh/translation.json
| bg: isCollapsed ? 'transparent' : 'gray.800', | ||
| borderTopRadius: isCollapsed ? 'none' : 'lg', | ||
| transform: isCollapsed ? 'translateY(calc(100% - 24px))' : 'translateY(0)', | ||
| transform: isCollapsed ? 'translateY(calc(100% - 20px))' : 'translateY(0)', |
There was a problem hiding this comment.
Sync footer handle height changes with subtitle anchor offsets.
Line 24 reduces the collapsed reveal height to 20px, but src/renderer/src/App.tsx Line 131 still uses hardcoded subtitle offsets (39px / 135px) tuned to the old footer geometry. This can cause subtitle vertical drift between collapsed/expanded states.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/footer/footer-styles.tsx` at line 24, The footer
collapsed translateY uses a 20px handle (transform: isCollapsed ?
'translateY(calc(100% - 20px))'...), but App.tsx still uses hardcoded subtitle
offsets (39px / 135px) causing vertical drift; change App.tsx to compute
subtitle anchor offsets from a single source of truth instead of magic
numbers—either export a FOOTER_HANDLE_HEIGHT (or FOOTER_COLLAPSED_HANDLE) from
src/renderer/src/components/footer/footer-styles.tsx and use it to compute the
offsets in the subtitle positioning logic in App.tsx, or derive the offsets at
runtime from the footer element (query by its component ID/class and read its
clientHeight) so isCollapsed, translateY and subtitle offsets stay in sync.
| <Box | ||
| {...footerStyles.footer.toggleButton} | ||
| onClick={onToggle} | ||
| color="whiteAlpha.500" | ||
| style={{ | ||
| transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)', | ||
| }} | ||
| > | ||
| <FiChevronDown /> | ||
| </Box> |
There was a problem hiding this comment.
Use a semantic button for the footer collapse toggle.
The current clickable Box is not keyboard-friendly by default and has no explicit accessible name.
♿ Suggested fix
- <Box
+ <Box
+ as="button"
+ type="button"
+ aria-label={isCollapsed ? t('tooltip.expandInput') : t('tooltip.collapseInput')}
{...footerStyles.footer.toggleButton}
onClick={onToggle}
color="whiteAlpha.500"
style={{
transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)',
}}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ onToggle?.();
+ }
+ }}
>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/footer/footer.tsx` around lines 45 - 54, Replace
the non-semantic clickable Box with a real button element (e.g., Chakra UI Box
with as="button" or an IconButton) so it becomes keyboard-accessible and behaves
like a native control; keep the existing props footerStyles.footer.toggleButton
and the onToggle handler, add type="button", include aria-expanded={isCollapsed}
and an accessible name via aria-label="Toggle footer collapse" (or
visually-hidden text) and preserve the transform style based on isCollapsed;
update the element rendering the FiChevronDown accordingly so the visual
appearance stays the same.
| <IconButton | ||
| bg={micOn ? 'green.500' : 'red.500'} | ||
| {...footerStyles.footer.actionButton} | ||
| onClick={onMicToggle} | ||
| transition="all 0.15s ease" | ||
| _hover={{ bg: micOn ? 'green.400' : 'red.400', transform: 'scale(1.05)' }} | ||
| _active={{ bg: micOn ? 'green.600' : 'red.600', transform: 'scale(0.88)', boxShadow: micOn ? '0 0 12px rgba(34, 197, 94, 0.6)' : '0 0 12px rgba(239, 68, 68, 0.6)' }} | ||
| > | ||
| {micOn ? <BsMicFill /> : <BsMicMuteFill />} | ||
| </IconButton> |
There was a problem hiding this comment.
Add an accessible label to the mic toggle button.
The mic button is icon-only and currently lacks an explicit accessible name.
♿ Suggested fix
<IconButton
+ aria-label={micOn ? t('tooltip.micOn') : t('tooltip.micOff')}
bg={micOn ? 'green.500' : 'red.500'}
{...footerStyles.footer.actionButton}
onClick={onMicToggle}📝 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.
| <IconButton | |
| bg={micOn ? 'green.500' : 'red.500'} | |
| {...footerStyles.footer.actionButton} | |
| onClick={onMicToggle} | |
| transition="all 0.15s ease" | |
| _hover={{ bg: micOn ? 'green.400' : 'red.400', transform: 'scale(1.05)' }} | |
| _active={{ bg: micOn ? 'green.600' : 'red.600', transform: 'scale(0.88)', boxShadow: micOn ? '0 0 12px rgba(34, 197, 94, 0.6)' : '0 0 12px rgba(239, 68, 68, 0.6)' }} | |
| > | |
| {micOn ? <BsMicFill /> : <BsMicMuteFill />} | |
| </IconButton> | |
| <IconButton | |
| aria-label={micOn ? t('tooltip.micOn') : t('tooltip.micOff')} | |
| bg={micOn ? 'green.500' : 'red.500'} | |
| {...footerStyles.footer.actionButton} | |
| onClick={onMicToggle} | |
| transition="all 0.15s ease" | |
| _hover={{ bg: micOn ? 'green.400' : 'red.400', transform: 'scale(1.05)' }} | |
| _active={{ bg: micOn ? 'green.600' : 'red.600', transform: 'scale(0.88)', boxShadow: micOn ? '0 0 12px rgba(34, 197, 94, 0.6)' : '0 0 12px rgba(239, 68, 68, 0.6)' }} | |
| > | |
| {micOn ? <BsMicFill /> : <BsMicMuteFill />} | |
| </IconButton> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/footer/footer.tsx` around lines 66 - 75, The
IconButton used for the mic toggle (IconButton with props bg,
onClick={onMicToggle}, using micOn and icons BsMicFill/BsMicMuteFill) is
icon-only and needs an accessible name; add an explicit accessible label and
toggle state by supplying props like aria-label (e.g., aria-label={micOn ? "Mute
microphone" : "Unmute microphone"}) and aria-pressed={micOn} (or aria-checked if
using role="switch") to the IconButton so screen readers can announce the button
and its state.
| aria-label="Raise hand" | ||
| bg="yellow.500" |
There was a problem hiding this comment.
Localize static aria-label strings for action buttons.
These labels stay English regardless of language selection; use translation keys for consistency.
🌐 Suggested fix
- aria-label="Raise hand"
+ aria-label={t('tooltip.raiseHand')}
...
- aria-label="Attach file"
+ aria-label={t('tooltip.attachFile')}Also applies to: 110-111
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/footer/footer.tsx` around lines 79 - 80, Replace
hard-coded aria-label strings in the Footer component with localized translation
keys: import and call the i18n hook (e.g., useTranslation) at the top of the
Footer component, then replace aria-label="Raise hand" and the other static
aria-labels around lines referenced with aria-label={t('footer.raiseHand')} (and
corresponding keys like 'footer.someOtherAction') so the Button/Action
components use t('...') instead of literal English; update translation files
with the new keys.
| <Box position="absolute" top="8px" left="10px" zIndex={1}> | ||
| <Text fontSize="sm" color="blue.300">{t('sidebar.browserSession')}</Text> | ||
| </Box> |
There was a problem hiding this comment.
Prevent session label overlay from intercepting iframe clicks.
The absolute label on Line 55 sits above the interactive browser view and can steal clicks in that region. Make it non-interactive.
💡 Proposed fix
- <Box position="absolute" top="8px" left="10px" zIndex={1}>
+ <Box position="absolute" top="8px" left="10px" zIndex={1} pointerEvents="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.
| <Box position="absolute" top="8px" left="10px" zIndex={1}> | |
| <Text fontSize="sm" color="blue.300">{t('sidebar.browserSession')}</Text> | |
| </Box> | |
| <Box position="absolute" top="8px" left="10px" zIndex={1} pointerEvents="none"> | |
| <Text fontSize="sm" color="blue.300">{t('sidebar.browserSession')}</Text> | |
| </Box> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/sidebar/browser-panel.tsx` around lines 55 - 57,
The absolute positioned session label Box (the Box rendering
t('sidebar.browserSession') in browser-panel.tsx) is intercepting iframe clicks;
make that Box non-interactive by disabling pointer events and accessibility
interception (e.g., set CSS pointer-events to 'none' and mark it aria-hidden) so
it no longer captures mouse events or screen-reader focus while keeping the
visual label intact.
| <Box | ||
| {...sidebarStyles.sidebar.toggleButton} | ||
| style={{ | ||
| transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)', | ||
| }} | ||
| onClick={onToggle} | ||
| > |
There was a problem hiding this comment.
Make the sidebar toggle keyboard-accessible.
This control is implemented as a clickable Box, so it lacks native button semantics and an explicit accessible name.
♿ Suggested fix
- <Box
+ <Box
+ as="button"
+ type="button"
+ aria-label={isCollapsed ? t('tooltip.expandSidebar') : t('tooltip.collapseSidebar')}
{...sidebarStyles.sidebar.toggleButton}
style={{
transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)',
}}
onClick={onToggle}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ onToggle();
+ }
+ }}
>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/sidebar/sidebar.tsx` around lines 40 - 46, The
sidebar toggle is currently a clickable Box (sidebarStyles.sidebar.toggleButton)
with onClick and transform but lacks keyboard and ARIA semantics; make it
keyboard-accessible by giving that Box role="button", tabIndex={0}, and an
accessible name (e.g., aria-label="Toggle sidebar" or aria-labelledby pointing
to a label), add a keyDown handler on the same element that calls onToggle when
Enter or Space is pressed, and consider using aria-pressed or aria-expanded
(tied to isCollapsed) to expose state to assistive tech.
| Live Mode | ||
| </Menu.RadioItem> | ||
| <Menu.RadioItem | ||
| value="pet" | ||
| onClick={() => { | ||
| if (isElectron) { | ||
| setMode('pet'); | ||
| } | ||
| }} | ||
| disabled={!isElectron} | ||
| title={!isElectron ? "Pet mode is only available in desktop app" : undefined} | ||
| > | ||
| <Menu.ItemIndicator /> | ||
| Pet Mode | ||
| </Menu.RadioItem> |
There was a problem hiding this comment.
Localize mode option labels and the desktop-only hint.
Live Mode, Pet Mode, and the disabled title are hardcoded English and will bypass locale switching.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/sidebar/sidebar.tsx` around lines 71 - 85, The
hardcoded English strings for the mode options bypass localization; update the
Menu.RadioItem labels and the disabled title to use the app's i18n/messages
(e.g., call t('liveMode'), t('petMode'), and t('petModeDesktopOnlyHint'))
instead of literal "Live Mode", "Pet Mode" and the inline title; locate the two
Menu.RadioItem components (the one with value "pet" and its sibling for Live
mode) and replace the visible text and the title={!isElectron ? "Pet mode is
only available in desktop app" : undefined} with localized lookups, leaving the
isElectron guard and setMode('pet') logic unchanged.
| <Tooltip content={t('tooltip.settings')} showArrow openDelay={300}> | ||
| <Button onClick={onSettingsOpen}> | ||
| <FiSettings /> | ||
| </Button> | ||
| </Tooltip> | ||
|
|
||
| <GroupDrawer> | ||
| <Box as="span" display="inline-flex"> | ||
| <Tooltip content={t('tooltip.group')} showArrow openDelay={300}> | ||
| <Button> | ||
| <FiUsers /> | ||
| </Button> | ||
| </Tooltip> | ||
| </Box> | ||
| </GroupDrawer> | ||
|
|
||
| <HistoryDrawer> | ||
| <Box as="span" display="inline-flex"> | ||
| <Tooltip content={t('tooltip.chatHistory')} showArrow openDelay={300}> | ||
| <Button> | ||
| <FiClock /> | ||
| </Button> | ||
| </Tooltip> | ||
| </Box> | ||
| </HistoryDrawer> | ||
|
|
||
| <Tooltip content={t('tooltip.newChat')} showArrow openDelay={300}> | ||
| <Button onClick={onNewHistory}> | ||
| <FiPlus /> | ||
| </Button> | ||
| </Tooltip> |
There was a problem hiding this comment.
Add accessible names to sidebar icon-only buttons.
Settings, Group, History, and New Chat buttons should expose explicit localized aria-labels instead of relying on tooltips.
♿ Suggested fix
- <Button onClick={onSettingsOpen}>
+ <Button onClick={onSettingsOpen} aria-label={t('tooltip.settings')}>
<FiSettings />
</Button>
...
- <Button>
+ <Button aria-label={t('tooltip.group')}>
<FiUsers />
</Button>
...
- <Button>
+ <Button aria-label={t('tooltip.chatHistory')}>
<FiClock />
</Button>
...
- <Button onClick={onNewHistory}>
+ <Button onClick={onNewHistory} aria-label={t('tooltip.newChat')}>
<FiPlus />
</Button>📝 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.
| <Tooltip content={t('tooltip.settings')} showArrow openDelay={300}> | |
| <Button onClick={onSettingsOpen}> | |
| <FiSettings /> | |
| </Button> | |
| </Tooltip> | |
| <GroupDrawer> | |
| <Box as="span" display="inline-flex"> | |
| <Tooltip content={t('tooltip.group')} showArrow openDelay={300}> | |
| <Button> | |
| <FiUsers /> | |
| </Button> | |
| </Tooltip> | |
| </Box> | |
| </GroupDrawer> | |
| <HistoryDrawer> | |
| <Box as="span" display="inline-flex"> | |
| <Tooltip content={t('tooltip.chatHistory')} showArrow openDelay={300}> | |
| <Button> | |
| <FiClock /> | |
| </Button> | |
| </Tooltip> | |
| </Box> | |
| </HistoryDrawer> | |
| <Tooltip content={t('tooltip.newChat')} showArrow openDelay={300}> | |
| <Button onClick={onNewHistory}> | |
| <FiPlus /> | |
| </Button> | |
| </Tooltip> | |
| <Tooltip content={t('tooltip.settings')} showArrow openDelay={300}> | |
| <Button onClick={onSettingsOpen} aria-label={t('tooltip.settings')}> | |
| <FiSettings /> | |
| </Button> | |
| </Tooltip> | |
| <GroupDrawer> | |
| <Box as="span" display="inline-flex"> | |
| <Tooltip content={t('tooltip.group')} showArrow openDelay={300}> | |
| <Button aria-label={t('tooltip.group')}> | |
| <FiUsers /> | |
| </Button> | |
| </Tooltip> | |
| </Box> | |
| </GroupDrawer> | |
| <HistoryDrawer> | |
| <Box as="span" display="inline-flex"> | |
| <Tooltip content={t('tooltip.chatHistory')} showArrow openDelay={300}> | |
| <Button aria-label={t('tooltip.chatHistory')}> | |
| <FiClock /> | |
| </Button> | |
| </Tooltip> | |
| </Box> | |
| </HistoryDrawer> | |
| <Tooltip content={t('tooltip.newChat')} showArrow openDelay={300}> | |
| <Button onClick={onNewHistory} aria-label={t('tooltip.newChat')}> | |
| <FiPlus /> | |
| </Button> | |
| </Tooltip> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/src/components/sidebar/sidebar.tsx` around lines 99 - 129, The
sidebar icon-only Buttons (the Button inside the Settings area with
onSettingsOpen, the Button wrapped by GroupDrawer, the Button wrapped by
HistoryDrawer, and the New Chat Button with onNewHistory) currently rely on
tooltips for identification; add explicit localized aria-label attributes to
each Button using the same translation keys (e.g., t('tooltip.settings'),
t('tooltip.group'), t('tooltip.chatHistory'), t('tooltip.newChat')) so screen
readers receive accessible names independent of the Tooltip component.
…outh_form support (Open-LLM-VTuber#20) Co-authored-by: MrXnneHang <XnneHang@gmail.com>
Made-with: Cursor
Summary by CodeRabbit
New Features
Improvements