mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 02:44:50 +01:00
27897e754e0dfead44397044bef96d3a9925d60d
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
27897e754e |
feat(markdown): add syntax colors to rendered code blocks
The block follows the theme now, but every token in it is one color. Add syntax highlighting, using the palette from the approved design. Render: add rehype-highlight and pass it to react-markdown. The plugin array sits at module scope, because react-markdown remounts the rendered tree when the array identity changes. That is the same hazard the remarkPlugins memo already guards against. Detection: `detect` is on, because most agent-authored fences carry no language tag and would never highlight without it. `subset` restricts detection to the languages agents actually post. highlight.js guesses badly on short snippets, and a wrong guess colors the whole block wrongly. Palette: eight `--code-syntax-*` aliases carry the roles. Each one points at a token that already exists and already has a `.dark` override, so a custom property resolves per mode at its use site and one definition covers both themes. The mapping is BORROWED, and this is the part to review. Paperclip has no syntax palette. `--status-task-icon-*` and `--chip-match-title-fg` name task-status and search-chip concerns. They were used because they are the only hues that carry a real per-mode value; the fixed `--status-task-*` hues go dim on the dark code surface. The coupling is confined to the alias block. Repointing those eight lines moves the whole palette, and no rule changes. A test asserts that the syntax rules never reference the borrowed tokens directly. Verified in both themes on a real task. Light resolves keyword #7c3aed, identifier oklch(0.145 0 0), function oklch(0.4 0.13 265), comment oklch(0.556 0 0). Dark resolves #9474f0, oklch(0.985 0 0), oklch(0.78 0.1 265), oklch(0.708 0 0). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
a1278e6ded |
fix(markdown): make rendered code blocks follow the active theme (#11591)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents report their work in task chat, and that chat renders markdown through `MarkdownBody` > - Agents post shell commands, API payloads and diffs, so a fenced code block is one of the most frequent things a person reads in the product > - The rendered code block was pinned to two literal colors, so it stayed dark in light mode and was the only dark surface on a light page > - The `prose` and the `prose-invert` variables held the same two values, so the theme could not change the block at all > - This pull request binds the block to the theme tokens that already exist and already carry a `.dark` override > - The benefit is that a code block now matches the page in both modes, and it follows any future change to the theme automatically ## Linked Issues or Issue Description No public issue exists. The problem is described below. **What happened?** A fenced code block in rendered markdown is always dark. It uses the background `#1e1e2e` and the text color `#cdd6f4` in light mode and in dark mode. In light mode the block is the only dark surface on the page. The rule is in `ui/src/index.css`. The variables `--tw-prose-pre-bg` and `--tw-prose-invert-pre-bg` are set to the same literal value, so `prose-invert` cannot change it. **Expected behavior** A code block uses a light surface with dark text in light mode. It uses a dark surface with light text in dark mode. It follows the theme like every other surface in the app. **Steps to reproduce** 1. Start the app and open a task that contains a fenced code block in its chat. 2. Set the theme to light. 3. Look at the code block. The block is dark. The page is light. 4. Set the theme to dark. The block does not change. **Paperclip version or commit** Reproduced on `master` at `4af55ba6b`. **Agent adapter(s) involved** Not adapter-specific (core bug). The defect is in the UI render path. **Deployment mode** Local development server. ## What Changed - Bind `.paperclip-markdown pre` to `--muted`, `--foreground`, `--border` and `--radius-lg` in `ui/src/index.css`. Remove the `#1e1e2e` and `#cdd6f4` literals. - Set the four `--tw-prose-*-pre-*` variables to the same tokens, so `prose` and `prose-invert` both follow the theme. - Apply the same four tokens to `.paperclip-mdxeditor-content pre`. - Change the fill of the copy button and the wrap button to `--background` in `ui/src/components/MarkdownBody.tsx`. The old fill was `color-mix(in oklab, var(--muted) 92%, var(--background) 8%)`. That value is almost equal to the block's new `--muted` surface, so the buttons would nearly disappear. - Update the stale comment above the rule. The comment said "Dark theme code blocks". - Add `ui/src/components/MarkdownCodeBlockStyles.test.ts`. It fails if a literal color returns to any themed code surface. - Export `codeBlockActionStyle` from `MarkdownBody.tsx` so the new test can read it. No new design token is added. Every token used here is already defined in `ui/src/index.css`, and each one already has a `.dark` override. ## Verification Automated: ```bash cd ui && npx vitest run --config vitest.config.ts src/components/MarkdownCodeBlockStyles.test.ts src/components/MarkdownBody.test.tsx src/components/MarkdownBody.wrap.test.tsx src/components/MarkdownAccentStyles.test.ts ``` 59 tests pass. `MarkdownCodeBlockStyles.test.ts` is new. It guards the defect directly. It reads `index.css` and asserts that each themed code surface rides a token and holds no hex, `rgb()` or `hsl()` literal. I confirmed the test fails on the original defect: restoring `#1e1e2e` and `#cdd6f4` fails 2 of the 5 tests. Manual. Open a task that has a fenced code block in its chat. Read the computed style of `.paperclip-markdown pre` in the browser. The measured values are: | Property | Light | Dark | | --- | --- | --- | | background | `oklch(0.97 0 0)` | `oklch(0.269 0 0)` | | color | `oklch(0.145 0 0)` | `oklch(0.985 0 0)` | | border | `oklch(0.922 0 0)` | `oklch(1 0 0 / 0.1)` | | radius | `8px` | `8px` | These values are `--muted`, `--foreground`, `--border` and `--radius-lg` for each mode. Toggle the theme and confirm the block changes with the page. ## Risks Low risk. The change is CSS and one inline style value. There is no migration and no schema change. Two behavioral notes for the reviewer: 1. The corner radius changes from `calc(var(--radius) - 3px)` (5px) to `var(--radius-lg)` (8px). This matches the approved design and removes an arbitrary offset. It is a small visual change on every code block. 2. The CodeMirror theme inside the MDXEditor still uses the Catppuccin literals (`ui/src/index.css`, the `.paperclip-mdxeditor .cm-editor` rules). That surface is an editor, not a rendered snippet, and a change there needs a full light CodeMirror theme. A code block therefore looks light when it is rendered and dark while a person edits it. This is intentional in this pull request. Tell me if you want it in scope. Syntax highlighting, line numbers and diff rows are not in this pull request. The repository has no highlighter dependency and no syntax or diff tokens. Those are separate changes. ## Model Used Claude Opus 5 (`claude-opus-5`), via Claude Code. Extended thinking was on. Tool use was on, with file edit, shell, browser automation and the Paper design tool. The design was produced first in Paper, then read back through the design tool for exact token values rather than from screenshots. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Notes on the unchecked boxes: - Branch name. The branch is `claude/paperclip-code-snippet-styling-202f7d`. It describes the change, but the `202f7d` suffix comes from the local worktree name. It carries no ticket id. I did not rename it, because the branch was already named when this work was requested. Tell me if you want it renamed before review. - CI and Greptile. Not yet run at the time of opening. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |