feat: add fullscreen toggle to Modal, enable in NodeEditorModal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-18 01:16:10 -05:00
parent d295ae5d88
commit bee7f45459
2 changed files with 55 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useCallback, type ReactNode } from 'react' import { useState, useEffect, useCallback, type ReactNode } from 'react'
import { X } from 'lucide-react' import { X, Maximize2, Minimize2 } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
interface ModalProps { interface ModalProps {
@@ -10,9 +10,28 @@ interface ModalProps {
/** Optional footer content that stays fixed at bottom (doesn't scroll) */ /** Optional footer content that stays fixed at bottom (doesn't scroll) */
footer?: ReactNode footer?: ReactNode
size?: 'sm' | 'md' | 'lg' | 'xl' size?: 'sm' | 'md' | 'lg' | 'xl'
/** If true, a fullscreen toggle button appears in the modal header */
allowFullScreen?: boolean
}
export function Modal({ isOpen, onClose, title, children, footer, size = 'md', allowFullScreen = false }: ModalProps) {
const [isFullScreen, setIsFullScreen] = useState(() => {
if (!allowFullScreen) return false
try {
return localStorage.getItem('rf-editor-fullscreen') === 'true'
} catch {
return false
}
})
const toggleFullScreen = () => {
const next = !isFullScreen
setIsFullScreen(next)
try {
localStorage.setItem('rf-editor-fullscreen', String(next))
} catch {}
} }
export function Modal({ isOpen, onClose, title, children, footer, size = 'md' }: ModalProps) {
// Close on Escape key // Close on Escape key
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
(e: KeyboardEvent) => { (e: KeyboardEvent) => {
@@ -61,9 +80,13 @@ export function Modal({ isOpen, onClose, title, children, footer, size = 'md' }:
<div <div
className={cn( className={cn(
'relative flex w-full flex-col border border-border bg-card shadow-lg', 'relative flex w-full flex-col border border-border bg-card shadow-lg',
'animate-scale-in transition-all duration-200',
isFullScreen
? 'fixed inset-4 max-w-none w-auto h-auto rounded-2xl'
: cn(
'max-h-[100vh] rounded-t-2xl sm:max-h-[85vh] sm:rounded-2xl', 'max-h-[100vh] rounded-t-2xl sm:max-h-[85vh] sm:rounded-2xl',
'animate-scale-in',
sizeClasses[size] sizeClasses[size]
)
)} )}
> >
{/* Header - Fixed at top */} {/* Header - Fixed at top */}
@@ -71,6 +94,20 @@ export function Modal({ isOpen, onClose, title, children, footer, size = 'md' }:
<h2 id="modal-title" className="text-lg font-semibold text-foreground"> <h2 id="modal-title" className="text-lg font-semibold text-foreground">
{title} {title}
</h2> </h2>
<div className="flex items-center gap-1">
{allowFullScreen && (
<button
type="button"
onClick={toggleFullScreen}
className="rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
title={isFullScreen ? 'Exit full screen' : 'Full screen'}
>
{isFullScreen
? <Minimize2 className="h-4 w-4" />
: <Maximize2 className="h-4 w-4" />
}
</button>
)}
<button <button
onClick={onClose} onClick={onClose}
className={cn( className={cn(
@@ -83,6 +120,7 @@ export function Modal({ isOpen, onClose, title, children, footer, size = 'md' }:
<X className="h-5 w-5" /> <X className="h-5 w-5" />
</button> </button>
</div> </div>
</div>
{/* Body - Scrollable */} {/* Body - Scrollable */}
<div className="flex-1 overflow-y-auto px-4 py-4 sm:px-6"> <div className="flex-1 overflow-y-auto px-4 py-4 sm:px-6">

View File

@@ -83,7 +83,7 @@ export function NodeEditorModal({ node, onClose, isNewNode = false }: NodeEditor
) )
return ( return (
<Modal isOpen={true} onClose={onClose} title={getTitle()} size="lg" footer={footerContent}> <Modal isOpen={true} onClose={onClose} title={getTitle()} size="lg" footer={footerContent} allowFullScreen={true}>
{/* Node ID display */} {/* Node ID display */}
<div className="mb-4 text-xs text-muted-foreground"> <div className="mb-4 text-xs text-muted-foreground">
Node ID: <code className="rounded bg-accent px-1 py-0.5">{node.id}</code> Node ID: <code className="rounded bg-accent px-1 py-0.5">{node.id}</code>