2026-04-05 Session: Convert AI chat from sheet to dedicated window per article
What was done
- Converted AI chat from a modal sheet to a dedicated macOS window per article, allowing multiple chats open simultaneously and free repositioning
- Created
ArticleAIChatWindowManager following the existing AppLogWindowManager pattern, tracking one window per article UUID
- Added 20px bottom padding to chat messages for visual comfort
- Auto-focus the input field when the chat window opens, using
@FocusState on macOS 13+ with graceful fallback
- Updated CLAUDE.md with guideline to use
#available/@available for newer APIs while maintaining macOS 12 compatibility
Key decisions
- Used the direct
NSWindow + NSHostingView pattern (like AppLogWindowManager) rather than the heavier WindowManager/WindowController/Window/ViewController hierarchy — simplest approach that supports multiple instances
- Replaced
@Environment(\.dismiss) with NSApp.keyWindow?.close() since dismiss doesn't work outside sheet context
- For auto-focus, extracted a
FocusableChatInput struct gated behind @available(macOS 13.0, *) rather than using fragile NSView hierarchy traversal
Files changed
Planet/Views/Articles/ArticleAIChatWindowManager.swift — New file: window manager tracking one NSWindow per article UUID
Planet/Views/Articles/ArticleView.swift — Removed sheet presentation, toolbar button now opens dedicated window
Planet/Views/Articles/ArticleAIChatView.swift — Removed dismiss environment, replaced with window close, flexible frame, bottom padding, focusOnAppear
Planet/Views/Articles/ChatInputField.swift — Added focusOnAppear support with @FocusState on macOS 13+
Planet.xcodeproj/project.pbxproj — Added new file to Planet target
CLAUDE.md — Added #available API adoption guideline