Skip to content

feat: add CollapsibleOutputSection and markdown preview toggle#112

Open
Psypeal wants to merge 1 commit intomatt1398:mainfrom
Psypeal:feat/collapsible-output-md-preview
Open

feat: add CollapsibleOutputSection and markdown preview toggle#112
Psypeal wants to merge 1 commit intomatt1398:mainfrom
Psypeal:feat/collapsible-output-md-preview

Conversation

@Psypeal
Copy link
Contributor

@Psypeal Psypeal commented Mar 11, 2026

Summary

Split from #90 per maintainer feedback — keeps just the two requested improvements:

  • CollapsibleOutputSection: Reusable component that wraps tool output in a collapsed-by-default section with status dot, chevron toggle, and copy button. DefaultToolViewer refactored to use it.
  • Markdown preview toggle: ReadToolViewer gains a Code/Preview toggle for .md/.mdx files (defaults to preview). WriteToolViewer also defaults to preview for markdown files.

Dropped from #90: BashToolViewer, syntax highlighter keyword expansions.

Test plan

  • pnpm typecheck — no type errors
  • pnpm lint:fix — no lint errors
  • All 653 tests pass
  • Manual: open a session with tool calls — output sections should be collapsed by default, expandable via click
  • Manual: open a session with Read/Write of .md files — should show preview by default with Code/Preview toggle

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added collapsible output sections for improved UI organization
    • Introduced Markdown file preview support with code/preview toggle for better readability
    • Auto-preview mode enabled for Markdown files in write operations

- 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>
@gemini-code-assist
Copy link

Summary of Changes

Hello, 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 ReadToolViewer and WriteToolViewer, enabling users to switch between code and rendered preview modes, with a default to preview for better content consumption.

Highlights

  • Collapsible Output Section: Introduced a new reusable CollapsibleOutputSection component to wrap tool output, featuring a status dot, chevron toggle, and copy button, and refactored DefaultToolViewer to utilize it.
  • Markdown Preview Toggle: Added a Code/Preview toggle for .md/.mdx files in ReadToolViewer, defaulting to preview, and set WriteToolViewer to also default to preview for markdown files.
Changelog
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
    • Added a new React component CollapsibleOutputSection to display collapsible content with a status dot and toggle.
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
    • Removed direct StatusDot import as its functionality is now encapsulated within CollapsibleOutputSection.
    • Replaced the manual output section rendering with the new CollapsibleOutputSection component.
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
    • Imported MarkdownViewer to support markdown rendering.
    • Implemented a Code/Preview toggle for .md and .mdx files, defaulting to preview mode.
    • Conditionally renders MarkdownViewer or CodeBlockViewer based on the selected view mode.
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
    • Modified the initial viewMode state to default to 'preview' for markdown files.
  • src/renderer/components/chat/items/linkedTool/index.ts
    • Exported the newly created CollapsibleOutputSection component.
Activity
  • The author created this pull request to introduce a CollapsibleOutputSection component and a markdown preview toggle, splitting these features from a larger previous PR (feat: add BashToolViewer, collapsible output, and expanded syntax highlighting #90).
  • The author confirmed that pnpm typecheck and pnpm lint:fix passed without errors.
  • All 653 tests passed.
  • Manual testing is planned for verifying collapsed output sections and the markdown Code/Preview toggle functionality.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.

Comment on lines +32 to +33
className="mb-1 flex items-center gap-2 text-xs"
style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}

Choose a reason for hiding this comment

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

medium

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.

Suggested change
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)]"

Comment on lines +42 to +50
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)',
}}

Choose a reason for hiding this comment

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

medium

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.

Suggested change
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)]' }`}

Comment on lines +63 to +88
<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>

Choose a reason for hiding this comment

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

medium

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>

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

📝 Walkthrough

Walkthrough

Introduces 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

Cohort / File(s) Summary
Collapsible Output Component
src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx, src/renderer/components/chat/items/linkedTool/index.ts
Introduces new reusable CollapsibleOutputSection component that renders a collapsible header with label, StatusDot, and chevron indicator, with conditional styling based on status. Exports the component and associated types.
DefaultToolViewer Integration
src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
Replaces explicit Output block rendering with CollapsibleOutputSection wrapper, removing inline StatusDot usage and styling.
Markdown File Viewing
src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx, src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
Adds Markdown file detection (.md, .mdx) with preview/code toggle controls in ReadToolViewer; updates WriteToolViewer to default to preview mode for Markdown files.

Suggested labels

feature request


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

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

📥 Commits

Reviewing files that changed from the base of the PR and between f69493c and 516d0f6.

📒 Files selected for processing (5)
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/index.ts

Comment on lines +30 to +39
<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>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

Comment on lines +9 to 14
import { type ItemStatus } from '../BaseItem';

import { CollapsibleOutputSection } from './CollapsibleOutputSection';
import { renderInput, renderOutput } from './renderHelpers';

import type { LinkedToolItem } from '@renderer/types/groups';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

Comment on lines +62 to +88
{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>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant