From fd7c015b9ed915988224fef95a496c803cd03672 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 8 Dec 2025 00:51:23 -0800 Subject: [PATCH] feat: add maximize button to StandardizedToolWrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add maximize/fullscreen button to standardized header bar - Create useMaximize hook for shape utils to enable fullscreen - Shape fills viewport when maximized, restores on Esc or toggle - Implement on ChatBoxShapeUtil as example (other shapes can add easily) - Button shows ⤢ for maximize, ⊡ for exit fullscreen 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/components/StandardizedToolWrapper.tsx | 46 ++++++++ src/hooks/useMaximize.ts | 130 +++++++++++++++++++++ src/shapes/ChatBoxShapeUtil.tsx | 12 ++ 3 files changed, 188 insertions(+) create mode 100644 src/hooks/useMaximize.ts diff --git a/src/components/StandardizedToolWrapper.tsx b/src/components/StandardizedToolWrapper.tsx index e485fb1..bc11545 100644 --- a/src/components/StandardizedToolWrapper.tsx +++ b/src/components/StandardizedToolWrapper.tsx @@ -44,6 +44,10 @@ export interface StandardizedToolWrapperProps { onMinimize?: () => void /** Whether the tool is minimized */ isMinimized?: boolean + /** Callback when maximize button is clicked */ + onMaximize?: () => void + /** Whether the tool is maximized (fullscreen) */ + isMaximized?: boolean /** Optional custom header content */ headerContent?: ReactNode /** Editor instance for shape selection */ @@ -76,6 +80,8 @@ export const StandardizedToolWrapper: React.FC = ( onClose, onMinimize, isMinimized = false, + onMaximize, + isMaximized = false, headerContent, editor, shapeId, @@ -91,6 +97,22 @@ export const StandardizedToolWrapper: React.FC = ( const tagInputRef = useRef(null) const isDarkMode = useIsDarkMode() + // Handle Esc key to exit maximize mode + useEffect(() => { + if (!isMaximized || !onMaximize) return + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault() + e.stopPropagation() + onMaximize() + } + } + + window.addEventListener('keydown', handleKeyDown, true) + return () => window.removeEventListener('keydown', handleKeyDown, true) + }, [isMaximized, onMaximize]) + // Dark mode aware colors const colors = useMemo(() => isDarkMode ? { contentBg: '#1a1a1a', @@ -243,6 +265,16 @@ export const StandardizedToolWrapper: React.FC = ( color: isSelected ? 'white' : primaryColor, } + const maximizeButtonStyle: React.CSSProperties = { + ...buttonBaseStyle, + backgroundColor: isMaximized + ? (isSelected ? 'rgba(255,255,255,0.4)' : primaryColor) + : (isSelected ? 'rgba(255,255,255,0.2)' : `${primaryColor}20`), + color: isMaximized + ? (isSelected ? 'white' : 'white') + : (isSelected ? 'white' : primaryColor), + } + const contentStyle: React.CSSProperties = { width: '100%', height: isMinimized ? 0 : 'calc(100% - 40px)', @@ -488,6 +520,20 @@ export const StandardizedToolWrapper: React.FC = ( > _ + {onMaximize && ( + + )}