# refactor\(web\): chat markdown links and file chips live in their own modules · PR \#22693 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/22693)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: merged

Source repository: pingdotgg/t3code

Source branch: refactor/chat-markdown-links

Target branch: refactor/chat-markdown-tables

Head commit: e113e20a3ef097439956f98e500d23e65581c354

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/22693)

[Commits](https://git.cafe/pingdotgg/t3code/pull/22693/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/22693/diffs?format=markdown)

## Description

---

ChatMarkdown.tsx was a 3,560-line file that held every markdown renderer. This stack splits it into focused modules so each piece is readable on its own.

The file-link chip moves to `chat/MarkdownFileLink.tsx`, and its pure action helpers to `MarkdownFileLink.logic.ts`. External-link favicons and URL wrapping move to `chat/MarkdownExternalLink.tsx`. Same-document fragment clicks and heading ids move to `chat/markdownFragments.ts`, and the hast text helpers to `chat/markdownHast.logic.ts`.

This is a pure move. Each renderer was already its own component, so no render boundary changes. Behavior is unchanged.

| | Before | After |
|---|---|---|
| `ChatMarkdown.tsx` lines | 2776 | 2068 |
| New files | | chat/MarkdownFileLink.tsx (411), MarkdownFileLink.logic.ts (62), MarkdownExternalLink.tsx (110), markdownFragments.ts (113), markdownHast.logic.ts (42) |
| Renders | unchanged: no component, subscription or context boundary moved | unchanged |

Renders were not measured for this layer. It changes no render boundaries: the components, their props, and the two contexts stay exactly as they were.

Tests run:
- `vp test run --project browser src/components/ChatMarkdown.browser.test.tsx src/components/ChatMarkdown.permissions.browser.test.tsx` (11 passed)
- `vp test run --project unit src/reactCompilerCoverage.test.ts` for every touched file (0 bailouts)
- `tsc --noEmit` for apps/web, and `vp lint` on changed files

🤖 Generated with [Claude Code](https://claude.com/claude-code)
