feat: add CollapsibleOutputSection and markdown preview toggle#112
feat: add CollapsibleOutputSection and markdown preview toggle#112Psypeal wants to merge 1 commit intomatt1398:mainfrom
Conversation
- Add reusable CollapsibleOutputSection component for tool outputs (collapsed by default, with status dot and copy support) - Refactor DefaultToolViewer to use CollapsibleOutputSection - Add Code/Preview toggle for .md/.mdx files in ReadToolViewer - Default to preview mode for markdown files in WriteToolViewer - Export CollapsibleOutputSection from linkedTool barrel Split from matt1398#90 per maintainer feedback — drops BashToolViewer and keyword expansions, keeps the collapsible output refactor and markdown preview improvements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the user interface for displaying tool outputs and markdown files. It introduces a new collapsible component for tool output sections, improving readability and space management by allowing users to expand or collapse output details. Additionally, it provides a toggle for markdown files within Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces two nice features: a reusable CollapsibleOutputSection component and a markdown preview toggle for tool viewers. The refactoring of DefaultToolViewer to use the new collapsible section is a good improvement. My review includes suggestions to enhance maintainability by replacing inline styles with utility classes, which aligns better with the existing styling approach in the project and reduces code duplication.
| className="mb-1 flex items-center gap-2 text-xs" | ||
| style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }} |
There was a problem hiding this comment.
To improve maintainability and align with the project's use of utility classes, it's better to replace inline styles with Tailwind CSS classes. This keeps styling consistent and easier to manage.
| className="mb-1 flex items-center gap-2 text-xs" | |
| style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }} | |
| className="mb-1 flex items-center gap-2 cursor-pointer border-none bg-transparent p-0 text-xs text-[var(--tool-item-muted)]" |
| className="max-h-96 overflow-auto rounded p-3 font-mono text-xs" | ||
| style={{ | ||
| backgroundColor: 'var(--code-bg)', | ||
| border: '1px solid var(--code-border)', | ||
| color: | ||
| status === 'error' | ||
| ? 'var(--tool-result-error-text)' | ||
| : 'var(--color-text-secondary)', | ||
| }} |
There was a problem hiding this comment.
These inline styles can be converted to Tailwind classes. For conditional styling, you can use template literals to construct the className string. This improves code clarity and consistency.
| className="max-h-96 overflow-auto rounded p-3 font-mono text-xs" | |
| style={{ | |
| backgroundColor: 'var(--code-bg)', | |
| border: '1px solid var(--code-border)', | |
| color: | |
| status === 'error' | |
| ? 'var(--tool-result-error-text)' | |
| : 'var(--color-text-secondary)', | |
| }} | |
| className={`max-h-96 overflow-auto rounded border border-[var(--code-border)] bg-[var(--code-bg)] p-3 font-mono text-xs ${ status === 'error' ? 'text-[var(--tool-result-error-text)]' : 'text-[var(--color-text-secondary)]' }`} |
| <div className="flex items-center justify-end gap-1"> | ||
| <button | ||
| type="button" | ||
| onClick={() => setViewMode('code')} | ||
| className="rounded px-2 py-1 text-xs transition-colors" | ||
| style={{ | ||
| backgroundColor: viewMode === 'code' ? 'var(--tag-bg)' : 'transparent', | ||
| color: viewMode === 'code' ? 'var(--tag-text)' : 'var(--color-text-muted)', | ||
| border: '1px solid var(--tag-border)', | ||
| }} | ||
| > | ||
| Code | ||
| </button> | ||
| <button | ||
| type="button" | ||
| onClick={() => setViewMode('preview')} | ||
| className="rounded px-2 py-1 text-xs transition-colors" | ||
| style={{ | ||
| backgroundColor: viewMode === 'preview' ? 'var(--tag-bg)' : 'transparent', | ||
| color: viewMode === 'preview' ? 'var(--tag-text)' : 'var(--color-text-muted)', | ||
| border: '1px solid var(--tag-border)', | ||
| }} | ||
| > | ||
| Preview | ||
| </button> | ||
| </div> |
There was a problem hiding this comment.
There's some duplication in the rendering of the 'Code' and 'Preview' buttons. You can refactor this by creating a small configuration array and mapping over it to render the buttons. This makes the code more concise and easier to extend if more view modes are added in the future. Additionally, using conditional classes instead of inline styles for the active state would be more idiomatic with Tailwind CSS.
<div className="flex items-center justify-end gap-1">
{(['code', 'preview'] as const).map((mode) => (
<button
key={mode}
type="button"
onClick={() => setViewMode(mode)}
className={`rounded border border-[var(--tag-border)] px-2 py-1 text-xs transition-colors ${
viewMode === mode
? 'bg-[var(--tag-bg)] text-[var(--tag-text)]'
: 'bg-transparent text-[var(--color-text-muted)]'
}`}
>
{mode.charAt(0).toUpperCase() + mode.slice(1)}
</button>
))}
</div>
📝 WalkthroughWalkthroughIntroduces a new reusable CollapsibleOutputSection component for rendering collapsible output panels. Integrates the component into DefaultToolViewer and adds Markdown file detection with preview/code toggle functionality to ReadToolViewer and WriteToolViewer. Changes
Suggested labels
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: 3
🤖 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/components/chat/items/linkedTool/CollapsibleOutputSection.tsx`:
- Around line 30-39: The toggle button in CollapsibleOutputSection should expose
its disclosure state and link to the content region: update the button element
(where onClick calls setIsExpanded and uses isExpanded) to include
aria-expanded={isExpanded} and aria-controls pointing to the content panel's id,
and ensure the content region has a matching id; generate a stable id (e.g., via
React's useId or a prop) for the panel so the button and panel are reliably
connected for assistive tech.
In `@src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx`:
- Around line 9-14: Reorder the import block in DefaultToolViewer.tsx so
path-alias imports come before relative imports: move "import type {
LinkedToolItem } from '@renderer/types/groups';" above the relative imports for
CollapsibleOutputSection and renderHelpers; keep the external/package imports
(e.g., ItemStatus) first, then alias imports (LinkedToolItem), then the relative
imports (CollapsibleOutputSection, renderInput, renderOutput) to match the
project's import ordering convention.
In `@src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx`:
- Around line 62-88: The two mode toggle buttons in ReadToolViewer (the
Code/Preview buttons that call setViewMode and read viewMode) are not exposing
the active state to assistive tech; update each button to include an accessible
state such as aria-pressed with a boolean expression (e.g.,
aria-pressed={viewMode === 'code'} for the Code button and
aria-pressed={viewMode === 'preview'} for the Preview button) or convert the
pair into an ARIA tabs pattern (role="tablist" on the container and role="tab"
plus aria-selected based on viewMode) so screen readers can announce which view
is active while keeping the existing onClick handlers and styling.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ec36e9c-d239-4680-b07b-dc1b1747cbb0
📒 Files selected for processing (5)
src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsxsrc/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsxsrc/renderer/components/chat/items/linkedTool/ReadToolViewer.tsxsrc/renderer/components/chat/items/linkedTool/WriteToolViewer.tsxsrc/renderer/components/chat/items/linkedTool/index.ts
| <button | ||
| type="button" | ||
| className="mb-1 flex items-center gap-2 text-xs" | ||
| style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }} | ||
| onClick={() => setIsExpanded((prev) => !prev)} | ||
| > | ||
| {isExpanded ? <ChevronDown className="size-3" /> : <ChevronRight className="size-3" />} | ||
| {label} | ||
| <StatusDot status={status} /> | ||
| </button> |
There was a problem hiding this comment.
Expose the disclosure state to assistive tech.
This button toggles the panel, but it never reports whether the section is open. Please add aria-expanded and connect it to the content region with aria-controls/id so screen-reader users can understand the current state.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx`
around lines 30 - 39, The toggle button in CollapsibleOutputSection should
expose its disclosure state and link to the content region: update the button
element (where onClick calls setIsExpanded and uses isExpanded) to include
aria-expanded={isExpanded} and aria-controls pointing to the content panel's id,
and ensure the content region has a matching id; generate a stable id (e.g., via
React's useId or a prop) for the panel so the button and panel are reliably
connected for assistive tech.
| import { type ItemStatus } from '../BaseItem'; | ||
|
|
||
| import { CollapsibleOutputSection } from './CollapsibleOutputSection'; | ||
| import { renderInput, renderOutput } from './renderHelpers'; | ||
|
|
||
| import type { LinkedToolItem } from '@renderer/types/groups'; |
There was a problem hiding this comment.
Reorder the imports to match the repo convention.
@renderer/types/groups should be grouped before the relative imports in this file.
As per coding guidelines, "Organize imports in order: external packages, path aliases (@main, @renderer, @shared, @preload), then relative imports".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx` around
lines 9 - 14, Reorder the import block in DefaultToolViewer.tsx so path-alias
imports come before relative imports: move "import type { LinkedToolItem } from
'@renderer/types/groups';" above the relative imports for
CollapsibleOutputSection and renderHelpers; keep the external/package imports
(e.g., ItemStatus) first, then alias imports (LinkedToolItem), then the relative
imports (CollapsibleOutputSection, renderInput, renderOutput) to match the
project's import ordering convention.
| {isMarkdownFile && ( | ||
| <div className="flex items-center justify-end gap-1"> | ||
| <button | ||
| type="button" | ||
| onClick={() => setViewMode('code')} | ||
| className="rounded px-2 py-1 text-xs transition-colors" | ||
| style={{ | ||
| backgroundColor: viewMode === 'code' ? 'var(--tag-bg)' : 'transparent', | ||
| color: viewMode === 'code' ? 'var(--tag-text)' : 'var(--color-text-muted)', | ||
| border: '1px solid var(--tag-border)', | ||
| }} | ||
| > | ||
| Code | ||
| </button> | ||
| <button | ||
| type="button" | ||
| onClick={() => setViewMode('preview')} | ||
| className="rounded px-2 py-1 text-xs transition-colors" | ||
| style={{ | ||
| backgroundColor: viewMode === 'preview' ? 'var(--tag-bg)' : 'transparent', | ||
| color: viewMode === 'preview' ? 'var(--tag-text)' : 'var(--color-text-muted)', | ||
| border: '1px solid var(--tag-border)', | ||
| }} | ||
| > | ||
| Preview | ||
| </button> | ||
| </div> |
There was a problem hiding this comment.
Expose the active view mode to assistive tech.
These buttons visually toggle modes, but they do not announce which option is selected. Please add aria-pressed to each button, or model this as a tabs pattern, so the current mode is conveyed accessibly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx` around
lines 62 - 88, The two mode toggle buttons in ReadToolViewer (the Code/Preview
buttons that call setViewMode and read viewMode) are not exposing the active
state to assistive tech; update each button to include an accessible state such
as aria-pressed with a boolean expression (e.g., aria-pressed={viewMode ===
'code'} for the Code button and aria-pressed={viewMode === 'preview'} for the
Preview button) or convert the pair into an ARIA tabs pattern (role="tablist" on
the container and role="tab" plus aria-selected based on viewMode) so screen
readers can announce which view is active while keeping the existing onClick
handlers and styling.
Summary
Split from #90 per maintainer feedback — keeps just the two requested improvements:
DefaultToolViewerrefactored to use it.ReadToolViewergains a Code/Preview toggle for.md/.mdxfiles (defaults to preview).WriteToolVieweralso defaults to preview for markdown files.Dropped from #90: BashToolViewer, syntax highlighter keyword expansions.
Test plan
pnpm typecheck— no type errorspnpm lint:fix— no lint errors.mdfiles — should show preview by default with Code/Preview toggle🤖 Generated with Claude Code
Summary by CodeRabbit