feat(canvas): widen zone modal into two columns
The add/edit zone modal grew tall enough to overflow the viewport. Apply the same layout as NodeModal: widen to sm:max-w-3xl and split fields into a Content column (label, font, text/label position, text size) and a Style column (colors, border style/width, z-order). ha-relevant: yes
This commit is contained in:
@@ -120,12 +120,17 @@ export function GroupRectModal({ open, onClose, onSubmit, onDelete, initial, tit
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={(o) => !o && onClose()}>
|
<Dialog open={open} onOpenChange={(o) => !o && onClose()}>
|
||||||
<DialogContent className="bg-[#161b22] border-[#30363d] text-foreground max-w-sm">
|
<DialogContent className="bg-[#161b22] border-[#30363d] text-foreground max-w-[calc(100%-2rem)] sm:max-w-3xl max-h-[90vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-sm font-semibold">{title}</DialogTitle>
|
<DialogTitle className="text-sm font-semibold">{title}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4 mt-2">
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4 mt-2">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-4">
|
||||||
|
{/* ── LEFT column: content & text ── */}
|
||||||
|
<div className="flex flex-col gap-4 min-w-0">
|
||||||
|
<div className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70 pb-1 border-b border-[#30363d]">Content</div>
|
||||||
|
|
||||||
{/* Label */}
|
{/* Label */}
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<Label className="text-xs text-muted-foreground">Label</Label>
|
<Label className="text-xs text-muted-foreground">Label</Label>
|
||||||
@@ -209,6 +214,38 @@ export function GroupRectModal({ open, onClose, onSubmit, onDelete, initial, tit
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Text size */}
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<Label className="text-xs text-muted-foreground">Text Size</Label>
|
||||||
|
<div className="grid grid-cols-6 gap-1">
|
||||||
|
{TEXT_SIZES.map(({ value, label }) => {
|
||||||
|
const isSelected = form.text_size === value
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={value}
|
||||||
|
type="button"
|
||||||
|
onClick={() => set('text_size', value)}
|
||||||
|
className={`flex items-center justify-center h-8 rounded transition-colors cursor-pointer ${modalStyles['modal-interactive']}`}
|
||||||
|
aria-label={`Text size ${label}`}
|
||||||
|
style={{
|
||||||
|
background: isSelected ? '#00d4ff22' : '#21262d',
|
||||||
|
border: `1px solid ${isSelected ? '#00d4ff88' : '#30363d'}`,
|
||||||
|
color: isSelected ? '#00d4ff' : '#8b949e',
|
||||||
|
fontSize: value,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>{/* ── end LEFT column ── */}
|
||||||
|
|
||||||
|
{/* ── RIGHT column: style ── */}
|
||||||
|
<div className="flex flex-col gap-4 min-w-0">
|
||||||
|
<div className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70 pb-1 border-b border-[#30363d]">Style</div>
|
||||||
|
|
||||||
{/* Colors */}
|
{/* Colors */}
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<Label className="text-xs text-muted-foreground">Colors</Label>
|
<Label className="text-xs text-muted-foreground">Colors</Label>
|
||||||
@@ -245,33 +282,6 @@ export function GroupRectModal({ open, onClose, onSubmit, onDelete, initial, tit
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Text size */}
|
|
||||||
<div className="flex flex-col gap-1.5">
|
|
||||||
<Label className="text-xs text-muted-foreground">Text Size</Label>
|
|
||||||
<div className="grid grid-cols-6 gap-1">
|
|
||||||
{TEXT_SIZES.map(({ value, label }) => {
|
|
||||||
const isSelected = form.text_size === value
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={value}
|
|
||||||
type="button"
|
|
||||||
onClick={() => set('text_size', value)}
|
|
||||||
className={`flex items-center justify-center h-8 rounded transition-colors cursor-pointer ${modalStyles['modal-interactive']}`}
|
|
||||||
aria-label={`Text size ${label}`}
|
|
||||||
style={{
|
|
||||||
background: isSelected ? '#00d4ff22' : '#21262d',
|
|
||||||
border: `1px solid ${isSelected ? '#00d4ff88' : '#30363d'}`,
|
|
||||||
color: isSelected ? '#00d4ff' : '#8b949e',
|
|
||||||
fontSize: value,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Border style */}
|
{/* Border style */}
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<Label className="text-xs text-muted-foreground">Border Style</Label>
|
<Label className="text-xs text-muted-foreground">Border Style</Label>
|
||||||
@@ -342,6 +352,8 @@ export function GroupRectModal({ open, onClose, onSubmit, onDelete, initial, tit
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
</div>{/* ── end RIGHT column ── */}
|
||||||
|
</div>{/* ── end 2-column grid ── */}
|
||||||
|
|
||||||
<div className="flex justify-between gap-2 pt-1">
|
<div className="flex justify-between gap-2 pt-1">
|
||||||
{onDelete && (
|
{onDelete && (
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ describe('GroupRectModal', () => {
|
|||||||
expect(screen.getByText('Z-Order (1 = furthest back)')).toBeDefined()
|
expect(screen.getByText('Z-Order (1 = furthest back)')).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('renders two-column Content and Style section headers', () => {
|
||||||
|
render(<GroupRectModal open onClose={vi.fn()} onSubmit={vi.fn()} />)
|
||||||
|
expect(screen.getByText('Content')).toBeDefined()
|
||||||
|
expect(screen.getByText('Style')).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
it('renders Edit Zone title when provided', () => {
|
it('renders Edit Zone title when provided', () => {
|
||||||
render(<GroupRectModal open onClose={vi.fn()} onSubmit={vi.fn()} title="Edit Zone" />)
|
render(<GroupRectModal open onClose={vi.fn()} onSubmit={vi.fn()} title="Edit Zone" />)
|
||||||
expect(screen.getByText('Edit Zone')).toBeDefined()
|
expect(screen.getByText('Edit Zone')).toBeDefined()
|
||||||
|
|||||||
Reference in New Issue
Block a user