Skip to content

Commit c9b003f

Browse files
committed
fix: Move properties panel into sidebar
Properties panel was using absolute positioning and overlapping the canvas. Moved it into the left sidebar below the elements grid so everything fits on screen without overlap. Also added a "drag or click to add" hint since it wasn't obvious.
1 parent a6b1786 commit c9b003f

File tree

2 files changed

+163
-160
lines changed

2 files changed

+163
-160
lines changed

DocumentGenerator.Client/src/components/VisualBuilder.css

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@
2424
font-size: 0.75rem;
2525
letter-spacing: 0.05em;
2626
background: rgba(0, 0, 0, 0.1);
27+
display: flex;
28+
justify-content: space-between;
29+
align-items: center;
30+
}
31+
32+
.vb-drag-hint {
33+
font-weight: 400;
34+
text-transform: none;
35+
font-size: 0.7rem;
36+
opacity: 0.7;
2737
}
2838

2939
.vb-sidebar-footer {
@@ -253,26 +263,16 @@
253263
background: #f59e0b;
254264
}
255265

256-
/* Properties Panel */
266+
/* Properties Panel - inside sidebar */
257267
.vb-properties {
258-
width: 280px;
259-
background: var(--bg-tertiary);
260-
border-left: 1px solid var(--border);
261-
padding: var(--space-md);
262-
position: absolute;
263-
right: 0;
264-
top: 0;
265-
bottom: 0;
268+
border-top: 1px solid var(--border);
269+
flex-shrink: 0;
270+
max-height: 50%;
266271
overflow-y: auto;
267-
box-shadow: -5px 0 15px rgba(0, 0, 0, 0.1);
268-
z-index: 50;
269272
}
270273

271-
.vb-properties h4 {
272-
margin-bottom: var(--space-md);
273-
font-size: 1rem;
274-
border-bottom: 1px solid var(--border);
275-
padding-bottom: var(--space-sm);
274+
.vb-properties-content {
275+
padding: var(--space-md);
276276
}
277277

278278
.prop-group {

DocumentGenerator.Client/src/components/VisualBuilder.jsx

Lines changed: 147 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ export default function VisualBuilder({ initialContent, onChange }) {
512512
<div className="vb-sidebar">
513513
<div className="vb-sidebar-header">
514514
Elements
515+
<span className="vb-drag-hint">Drag or click to add</span>
515516
</div>
516517
<div className="vb-elements">
517518
{[
@@ -537,6 +538,152 @@ export default function VisualBuilder({ initialContent, onChange }) {
537538
))}
538539
</div>
539540

541+
{selectedBlock && (
542+
<div className="vb-properties">
543+
<div className="vb-sidebar-header">Properties</div>
544+
545+
<div className="vb-properties-content">
546+
<div className="prop-group">
547+
<label>Position</label>
548+
<div className="prop-row">
549+
<div className="prop-field">
550+
<span>X</span>
551+
<input
552+
type="number"
553+
value={Math.round(selectedBlock.position.x)}
554+
onChange={(e) => updateBlockPosition(selectedBlock.id, {
555+
...selectedBlock.position,
556+
x: parseInt(e.target.value) || 0
557+
})}
558+
/>
559+
</div>
560+
<div className="prop-field">
561+
<span>Y</span>
562+
<input
563+
type="number"
564+
value={Math.round(selectedBlock.position.y)}
565+
onChange={(e) => updateBlockPosition(selectedBlock.id, {
566+
...selectedBlock.position,
567+
y: parseInt(e.target.value) || 0
568+
})}
569+
/>
570+
</div>
571+
</div>
572+
</div>
573+
574+
<div className="prop-group">
575+
<label>Size</label>
576+
<div className="prop-row">
577+
<div className="prop-field">
578+
<span>W</span>
579+
<input
580+
type="number"
581+
value={Math.round(selectedBlock.size.width)}
582+
onChange={(e) => updateBlockSize(selectedBlock.id, {
583+
width: parseInt(e.target.value) || 100
584+
})}
585+
/>
586+
</div>
587+
<div className="prop-field">
588+
<span>H</span>
589+
<input
590+
type="number"
591+
value={Math.round(selectedBlock.size.height)}
592+
onChange={(e) => updateBlockSize(selectedBlock.id, {
593+
height: parseInt(e.target.value) || 24
594+
})}
595+
/>
596+
</div>
597+
</div>
598+
</div>
599+
600+
<div className="prop-group">
601+
<label>Text Align</label>
602+
<div className="btn-group">
603+
<button
604+
type="button"
605+
className={selectedBlock.styles.textAlign === 'left' ? 'active' : ''}
606+
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'left')}
607+
>
608+
Left
609+
</button>
610+
<button
611+
type="button"
612+
className={selectedBlock.styles.textAlign === 'center' ? 'active' : ''}
613+
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'center')}
614+
>
615+
Center
616+
</button>
617+
<button
618+
type="button"
619+
className={selectedBlock.styles.textAlign === 'right' ? 'active' : ''}
620+
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'right')}
621+
>
622+
Right
623+
</button>
624+
</div>
625+
</div>
626+
627+
<div className="prop-group">
628+
<label>Color</label>
629+
<input
630+
type="color"
631+
value={selectedBlock.styles.color === 'inherit' ? '#000000' : selectedBlock.styles.color}
632+
onChange={(e) => updateBlockStyle(selectedBlock.id, 'color', e.target.value)}
633+
/>
634+
</div>
635+
636+
{selectedBlock.type === 'table' && (
637+
<>
638+
<div className="prop-group">
639+
<label>Columns</label>
640+
<div className="table-controls">
641+
<button
642+
type="button"
643+
className="btn btn-sm btn-secondary"
644+
onClick={() => removeTableColumn(selectedBlock.id)}
645+
disabled={getTableInfo(selectedBlock)?.cols <= 1}
646+
>
647+
648+
</button>
649+
<span className="table-count">{getTableInfo(selectedBlock)?.cols || 0}</span>
650+
<button
651+
type="button"
652+
className="btn btn-sm btn-secondary"
653+
onClick={() => addTableColumn(selectedBlock.id)}
654+
>
655+
+
656+
</button>
657+
</div>
658+
</div>
659+
660+
<div className="prop-group">
661+
<label>Rows</label>
662+
<div className="table-controls">
663+
<button
664+
type="button"
665+
className="btn btn-sm btn-secondary"
666+
onClick={() => removeTableRow(selectedBlock.id)}
667+
disabled={getTableInfo(selectedBlock)?.rows <= 2}
668+
>
669+
670+
</button>
671+
<span className="table-count">{(getTableInfo(selectedBlock)?.rows || 1) - 1}</span>
672+
<button
673+
type="button"
674+
className="btn btn-sm btn-secondary"
675+
onClick={() => addTableRow(selectedBlock.id)}
676+
>
677+
+
678+
</button>
679+
</div>
680+
</div>
681+
</>
682+
)}
683+
</div>
684+
</div>
685+
)}
686+
540687
<div className="vb-sidebar-footer">
541688
<button type="button" className="btn btn-danger w-full" onClick={handleClear}>
542689
Clear All
@@ -661,150 +808,6 @@ export default function VisualBuilder({ initialContent, onChange }) {
661808
);
662809
})}
663810
</div>
664-
665-
{selectedBlock && (
666-
<div className="vb-properties">
667-
<h4>Properties</h4>
668-
669-
<div className="prop-group">
670-
<label>Position</label>
671-
<div className="prop-row">
672-
<div className="prop-field">
673-
<span>X</span>
674-
<input
675-
type="number"
676-
value={Math.round(selectedBlock.position.x)}
677-
onChange={(e) => updateBlockPosition(selectedBlock.id, {
678-
...selectedBlock.position,
679-
x: parseInt(e.target.value) || 0
680-
})}
681-
/>
682-
</div>
683-
<div className="prop-field">
684-
<span>Y</span>
685-
<input
686-
type="number"
687-
value={Math.round(selectedBlock.position.y)}
688-
onChange={(e) => updateBlockPosition(selectedBlock.id, {
689-
...selectedBlock.position,
690-
y: parseInt(e.target.value) || 0
691-
})}
692-
/>
693-
</div>
694-
</div>
695-
</div>
696-
697-
<div className="prop-group">
698-
<label>Size</label>
699-
<div className="prop-row">
700-
<div className="prop-field">
701-
<span>W</span>
702-
<input
703-
type="number"
704-
value={Math.round(selectedBlock.size.width)}
705-
onChange={(e) => updateBlockSize(selectedBlock.id, {
706-
width: parseInt(e.target.value) || 100
707-
})}
708-
/>
709-
</div>
710-
<div className="prop-field">
711-
<span>H</span>
712-
<input
713-
type="number"
714-
value={Math.round(selectedBlock.size.height)}
715-
onChange={(e) => updateBlockSize(selectedBlock.id, {
716-
height: parseInt(e.target.value) || 24
717-
})}
718-
/>
719-
</div>
720-
</div>
721-
</div>
722-
723-
<div className="prop-group">
724-
<label>Text Align</label>
725-
<div className="btn-group">
726-
<button
727-
type="button"
728-
className={selectedBlock.styles.textAlign === 'left' ? 'active' : ''}
729-
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'left')}
730-
>
731-
Left
732-
</button>
733-
<button
734-
type="button"
735-
className={selectedBlock.styles.textAlign === 'center' ? 'active' : ''}
736-
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'center')}
737-
>
738-
Center
739-
</button>
740-
<button
741-
type="button"
742-
className={selectedBlock.styles.textAlign === 'right' ? 'active' : ''}
743-
onClick={() => updateBlockStyle(selectedBlock.id, 'textAlign', 'right')}
744-
>
745-
Right
746-
</button>
747-
</div>
748-
</div>
749-
750-
<div className="prop-group">
751-
<label>Color</label>
752-
<input
753-
type="color"
754-
value={selectedBlock.styles.color === 'inherit' ? '#000000' : selectedBlock.styles.color}
755-
onChange={(e) => updateBlockStyle(selectedBlock.id, 'color', e.target.value)}
756-
/>
757-
</div>
758-
759-
{selectedBlock.type === 'table' && (
760-
<>
761-
<div className="prop-group">
762-
<label>Columns</label>
763-
<div className="table-controls">
764-
<button
765-
type="button"
766-
className="btn btn-sm btn-secondary"
767-
onClick={() => removeTableColumn(selectedBlock.id)}
768-
disabled={getTableInfo(selectedBlock)?.cols <= 1}
769-
>
770-
− Remove
771-
</button>
772-
<span className="table-count">{getTableInfo(selectedBlock)?.cols || 0}</span>
773-
<button
774-
type="button"
775-
className="btn btn-sm btn-secondary"
776-
onClick={() => addTableColumn(selectedBlock.id)}
777-
>
778-
+ Add
779-
</button>
780-
</div>
781-
</div>
782-
783-
<div className="prop-group">
784-
<label>Rows</label>
785-
<div className="table-controls">
786-
<button
787-
type="button"
788-
className="btn btn-sm btn-secondary"
789-
onClick={() => removeTableRow(selectedBlock.id)}
790-
disabled={getTableInfo(selectedBlock)?.rows <= 2}
791-
>
792-
− Remove
793-
</button>
794-
<span className="table-count">{(getTableInfo(selectedBlock)?.rows || 1) - 1}</span>
795-
<button
796-
type="button"
797-
className="btn btn-sm btn-secondary"
798-
onClick={() => addTableRow(selectedBlock.id)}
799-
>
800-
+ Add
801-
</button>
802-
</div>
803-
</div>
804-
</>
805-
)}
806-
</div>
807-
)}
808811
</div>
809812

810813
<Modal

0 commit comments

Comments
 (0)