Skip to content

Feat/thoroc UI improvements#122

Merged
backnotprop merged 17 commits intobacknotprop:mainfrom
thoroc:feat/thoroc-ui-improvements
Feb 9, 2026
Merged

Feat/thoroc UI improvements#122
backnotprop merged 17 commits intobacknotprop:mainfrom
thoroc:feat/thoroc-ui-improvements

Conversation

@thoroc
Copy link
Contributor

@thoroc thoroc commented Jan 30, 2026

Summary

feat: Add Table of Contents sidebar with sticky action buttons

What Changed

  • Table of Contents Sidebar - Hierarchical navigation showing H2-H5 headings with click-to-scroll
  • Active Section Tracking - Real-time highlighting of current section based on scroll position
  • Sticky Action Buttons - Images, Global comment, and Copy plan buttons stay visible while scrolling
  • Navigation Fix - Scroll-to-section now works correctly within the scrollable main container
  • Config Fix - Corrected typo in opencode.json (CALUDE → CLAUDE)

Files Added/Modified

  • packages/ui/components/TableOfContents.tsx (new)
  • packages/ui/hooks/useActiveSection.ts (new)
  • packages/ui/utils/annotationHelpers.ts (new)
  • packages/editor/App.tsx - Added TOC integration
  • packages/ui/components/Viewer.tsx - Sticky button positioning
  • opencode.json - Typo fix

Testing

Run bun run build:hook && ./tests/manual/local/test-hook.sh to verify the UI locally.

- Add hierarchical Table of Contents component with clickable navigation
- Implement useActiveSection hook for real-time section highlighting
- Add annotationHelpers utility for block identification
- Make Images, Global comment, and Copy plan buttons sticky during scroll
- Fix navigation scrolling to work within scrollable main container
@kkharji
Copy link

kkharji commented Jan 30, 2026

Screenshot 2026-01-31 at 02 32 45 Found small bug while annotating code blocks. Not sure if it's issue from my-side or unified, but once I annotate a codeblock this happens.

@thoroc
Copy link
Contributor Author

thoroc commented Jan 31, 2026

Oh that is annoying indeed. I need to look into it.

@backnotprop
Copy link
Owner

Hey guys how are we looking here. I just got back from my only vacation this year and will get these PRs going.

- Replace surroundContents() with plain text wrapper approach
- Add syntax highlighting restoration in removeHighlight()
- Fixes issue reported by kkharji in PR backnotprop#122

The old approach used range.surroundContents() which wrapped syntax-highlighted
<span> elements, creating nested structure that broke the layout. The new approach
replaces code block innerHTML with plain text wrapped in <mark>, then restores
syntax highlighting when the annotation is removed.

Test coverage: 15 tests pass with edge cases for empty blocks, special chars,
large blocks (10k), unicode, and multiple annotation cycles.
- Add 15 test cases covering code block annotation behavior
- Test plain text wrapper approach vs nested span approach
- Verify syntax highlighting restoration on annotation removal
- Cover edge cases: empty blocks, special chars, large blocks, unicode
- Add happy-dom dev dependency for DOM testing
- Move comprehensive feature checklists to UI-TESTING-CHECKLIST.md
- Keep main UI-TESTING.md focused on development workflow and setup
- Add reference link to checklist file for easy navigation
@thoroc
Copy link
Contributor Author

thoroc commented Feb 5, 2026

@kkharji this should be addressed now

Screenshot 2026-02-05 at 22 32 50

@thoroc
Copy link
Contributor Author

thoroc commented Feb 5, 2026

@backnotprop I'll let you merge this when you're happy with the changes, otherwise say the word.

@backnotprop
Copy link
Owner

really cool work. I'm testing now. I may make it a settings config as well to toggle ToC on/off

@thoroc
Copy link
Contributor Author

thoroc commented Feb 7, 2026

That's a realty good idea

IntersectionObserver was using root: null (viewport) instead of the
actual scroll container (<main>), and the effect only ran on mount
before headings were rendered. Pass the container as root and re-run
the observer when heading count changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop
Copy link
Owner

Pushed a fix for the TOC active section tracking (dc497ba).

Two issues in useActiveSection.ts:

  1. Wrong observer rootIntersectionObserver was using root: null (viewport), but content scrolls inside the <main> element. Changed to root: container.

  2. Observer never initialized — The effect ran on mount before the plan loaded, found 0 headings, and early-returned. Since the dependency array ([containerRef]) never changes, it never re-ran. Added headingCount as a dependency so the observer re-initializes when headings render.

…links

Playwright MCP is dev tooling, not for end users. README referenced
docs/UI-TESTING.md and docs/CODE-STYLE.md which don't exist at those paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop
Copy link
Owner

Also reverted two unrelated changes (5cf22c5):

  • .claude-plugin/marketplace.json — Removed Playwright MCP server config. This is dev tooling and shouldn't ship to end users via the marketplace install.
  • README.md — Removed Contributing section that linked to docs/UI-TESTING.md and docs/CODE-STYLE.md which don't exist at those paths.

- Smaller text (text-xs) and tighter padding for compact feel
- Remove border-l-2 and font-medium from active state to prevent
  layout shifts that pushed text into multiline
- Annotation count badges are now perfect circles (w-5 h-5)
- Add left padding to root-level heading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop
Copy link
Owner

TOC styling tweaks (5ed11db):

  • Compact layout — smaller text and tighter padding
  • Fixed layout shifts — removed border-l-2 and font-medium from active state, which were causing text to reflow when scrolling between sections. Active state is now just a subtle background tint.
  • Annotation badges — fixed to perfect circles (w-5 h-5) instead of oval pills
  • Root heading padding — added left padding so the plan title isn't flush against the edge

backnotprop and others added 2 commits February 8, 2026 11:17
- New uiPreferences.ts utility for cookie-based persistence
- TOC toggle: conditionally renders sidebar in App.tsx
- Sticky Actions toggle: conditionally applies sticky positioning in Viewer.tsx
- Both default to enabled, persisted via cookies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace flat settings list with sidebar + content panel layout:
- General tab: Identity, Permission Mode, Agent Switching
- Display tab: TOC, Sticky Actions, Tater Mode
- Saving tab: Plan Saving, Obsidian, Bear Notes
- Scrollable content area (max-h-[70vh])
- Sidebar hidden in review mode (single tab)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop
Copy link
Owner

Additional commits pushed

feat(ui): add optional TOC and sticky actions settings (9f6e0ce)

  • Added uiPreferences.ts with cookie-based persistence for TOC and sticky actions toggles
  • TOC and sticky action buttons are now configurable via Settings (enabled by default)
  • Wired preferences through App.tsxViewer.tsx with stickyActions prop

refactor(ui): redesign Settings dialog with sidebar navigation (7714551)

  • Settings dialog was getting cluttered with 9+ settings in a flat list
  • Redesigned with sidebar + content panel layout (macOS System Settings style)
  • Three tabs: General (Identity, Permission Mode, Agent Switching), Display (TOC, Sticky Actions, Tater Mode), Saving (Plan Saving, Obsidian, Bear Notes)
  • Sidebar auto-hides in review mode (only General settings visible)
  • Scrollable content area with max-h-[70vh]

…background

Match main's button positioning across all breakpoints with responsive
margins that account for article padding. Use IntersectionObserver sentinel
to detect when the bar is stuck, revealing the card background only on scroll.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop
Copy link
Owner

Sticky action bar positioning fix (746ee01)

  • Fixed button positioning across all breakpoints — responsive negative margins now correctly compensate for article padding (p-5/md:p-8/lg:p-10/xl:p-12), matching main's absolute top-3 right-3 md:top-5 md:right-5 placement
  • Scroll-aware card background — uses an IntersectionObserver sentinel to detect when the sticky bar is actually stuck. At rest the buttons appear bare (same as main); on scroll, bg-card/95 backdrop-blur-sm shadow-sm fades in via transition-colors duration-150

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

  • If this code review was useful, please react with thumbs up. Otherwise, react with thumbs down.

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

1 similar comment
@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@backnotprop
Copy link
Owner

Code review: No issues found. Checked for bugs and CLAUDE.md compliance.

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

2 similar comments
@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

@backnotprop
Copy link
Owner

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Generated with Claude Code

…eferences)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@backnotprop backnotprop merged commit 313c451 into backnotprop:main Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments