Skip to content

Commit 6fde523

Browse files
committed
add resize handles; design improvements
1 parent 13a84d1 commit 6fde523

File tree

3 files changed

+153
-75
lines changed

3 files changed

+153
-75
lines changed

src/layout.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ export class DashboardLayout extends Layout {
508508
*/
509509
updateLayoutFromWidgetstore(): void {
510510
this._signalChanges = false;
511-
const records = this._widgetstore.getWidgets();
511+
const records = this._widgetstore.get(Widgetstore.WIDGET_SCHEMA);
512512
each(records, record => {
513513
this._updateLayoutFromRecord(record);
514514
});
@@ -869,10 +869,10 @@ export class DashboardLayout extends Layout {
869869
*/
870870
setTileSize(s: number): void {
871871
this._tileSize = s;
872-
const backgroundPosition = `0 0, 0 ${s}px, ${s}px -${s}px, -${s}px 0px`;
872+
// const backgroundPosition = `0 0, 0 ${s}px, ${s}px -${s}px, -${s}px 0px`;
873873

874-
this.canvas.style.backgroundPosition = backgroundPosition;
875-
this.canvas.style.backgroundSize = `${2 * s}px ${2 * s}px`;
874+
// this.canvas.style.backgroundPosition = backgroundPosition;
875+
this.canvas.style.backgroundSize = `${s}px ${s}px`;
876876
this.parent.update();
877877

878878
this.startBatch();

src/widget.ts

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import {
2323

2424
import { Signal, ISignal } from '@lumino/signaling';
2525

26-
import { DashboardIcons } from './icons';
27-
2826
import { Widgetstore, WidgetPosition } from './widgetstore';
2927

3028
import { DashboardLayout } from './layout';
@@ -152,8 +150,14 @@ export class DashboardWidget extends Widget {
152150
});
153151
}
154152

155-
const resizer = DashboardWidget.createResizer();
156-
this.node.appendChild(resizer);
153+
const resizerTopLeft = DashboardWidget.createResizer('top-left');
154+
const resizerTopRight = DashboardWidget.createResizer('top-right');
155+
const resizerBottomLeft = DashboardWidget.createResizer('bottom-left');
156+
const resizerBottomRight = DashboardWidget.createResizer('bottom-right');
157+
this.node.appendChild(resizerTopLeft);
158+
this.node.appendChild(resizerTopRight);
159+
this.node.appendChild(resizerBottomLeft);
160+
this.node.appendChild(resizerBottomRight);
157161

158162
this.addClass(DASHBOARD_WIDGET_CLASS);
159163
this.addClass(EDITABLE_WIDGET_CLASS);
@@ -294,9 +298,19 @@ export class DashboardWidget extends Widget {
294298

295299
// this.node.style.opacity = '0.6';
296300

301+
const elem = target as HTMLElement;
297302
// Set mode to resize if the mousedown happened on a resizer.
298-
if ((target as HTMLElement).classList.contains('pr-Resizer')) {
303+
if (elem.classList.contains('pr-Resizer')) {
299304
this._mouseMode = 'resize';
305+
if (elem.classList.contains('pr-ResizerTopRight')) {
306+
this._selectedResizer = 'top-right';
307+
} else if (elem.classList.contains('pr-ResizerTopLeft')) {
308+
this._selectedResizer = 'top-left';
309+
} else if (elem.classList.contains('pr-ResizerBottomLeft')) {
310+
this._selectedResizer = 'bottom-left';
311+
} else {
312+
this._selectedResizer = 'bottom-right';
313+
}
300314
} else {
301315
this._mouseMode = 'drag';
302316
}
@@ -305,12 +319,16 @@ export class DashboardWidget extends Widget {
305319

306320
const rect = this.node.getBoundingClientRect();
307321

322+
const { width, height, top, left } = this.pos;
323+
308324
this._clickData = {
309325
pressX: event.clientX,
310326
pressY: event.clientY,
311327
cell,
312-
pressWidth: parseInt(this.node.style.width, 10),
313-
pressHeight: parseInt(this.node.style.height, 10),
328+
origWidth: width,
329+
origHeight: height,
330+
origLeft: left,
331+
origTop: top,
314332
target: this.node.cloneNode(true) as HTMLElement,
315333
widgetX: rect.left,
316334
widgetY: rect.top
@@ -352,16 +370,44 @@ export class DashboardWidget extends Widget {
352370
* Handle `mousemove` events when the widget mouseMode is `resize`.
353371
*/
354372
private _resizeMouseMove(event: MouseEvent): void {
355-
const { pressX, pressY, pressWidth, pressHeight } = this._clickData;
373+
const {
374+
pressX,
375+
pressY,
376+
origWidth,
377+
origHeight,
378+
origLeft,
379+
origTop
380+
} = this._clickData;
356381

357382
const deltaX = event.clientX - pressX;
358383
const deltaY = event.clientY - pressY;
359384

360-
const width = Math.max(pressWidth + deltaX, DashboardWidget.MIN_WIDTH);
361-
const height = Math.max(pressHeight + deltaY, DashboardWidget.MIN_HEIGHT);
385+
let { width, height, top, left } = this.pos;
386+
387+
switch (this._selectedResizer) {
388+
case 'bottom-right':
389+
width = Math.max(origWidth + deltaX, DashboardWidget.MIN_WIDTH);
390+
height = Math.max(origHeight + deltaY, DashboardWidget.MIN_HEIGHT);
391+
break;
392+
case 'bottom-left':
393+
width = Math.max(origWidth - deltaX, DashboardWidget.MIN_WIDTH);
394+
height = Math.max(origHeight + deltaY, DashboardWidget.MIN_HEIGHT);
395+
left = origLeft + deltaX;
396+
break;
397+
case 'top-right':
398+
width = Math.max(origWidth + deltaX, DashboardWidget.MIN_WIDTH);
399+
height = Math.max(origHeight - deltaY, DashboardWidget.MIN_HEIGHT);
400+
top = origTop + deltaY;
401+
break;
402+
case 'top-left':
403+
width = Math.max(origWidth - deltaX, DashboardWidget.MIN_WIDTH);
404+
height = Math.max(origHeight - deltaY, DashboardWidget.MIN_HEIGHT);
405+
top = origTop + deltaY;
406+
left = origLeft + deltaX;
407+
break;
408+
}
362409

363-
this.node.style.width = `${width}px`;
364-
this.node.style.height = `${height}px`;
410+
this.pos = { width, height, top, left };
365411

366412
if (this.mode === 'grid-edit') {
367413
(this.parent.layout as DashboardLayout).drawDropZone(this.pos, '#2b98f0');
@@ -377,8 +423,12 @@ export class DashboardWidget extends Widget {
377423
fitContent(): void {
378424
const element = this._content.node;
379425
// Pixels are added to prevent weird wrapping issues. Kind of a hack.
380-
this.node.style.width = `${element.clientWidth + 3}px`;
381-
this.node.style.height = `${element.clientHeight + 2}px`;
426+
this.pos = {
427+
width: element.clientWidth + 3,
428+
height: element.clientHeight + 2,
429+
left: undefined,
430+
top: undefined
431+
};
382432
}
383433

384434
/**
@@ -642,15 +692,18 @@ export class DashboardWidget extends Widget {
642692
private _clickData: {
643693
pressX: number;
644694
pressY: number;
645-
pressWidth: number;
646-
pressHeight: number;
695+
origWidth: number;
696+
origHeight: number;
697+
origLeft: number;
698+
origTop: number;
647699
target: HTMLElement;
648700
cell: CodeCell | MarkdownCell;
649701
widgetX: number;
650702
widgetY: number;
651703
} | null = null;
652704
private _locked = false;
653705
private _content: Widget;
706+
private _selectedResizer: DashboardWidget.ResizerCorner;
654707
}
655708

656709
/**
@@ -710,18 +763,39 @@ export namespace DashboardWidget {
710763
return `DashboardWidget-${UUID.uuid4()}`;
711764
}
712765

766+
/**
767+
* A type for describing the corner for a widget resizer.
768+
*/
769+
export type ResizerCorner =
770+
| 'top-left'
771+
| 'bottom-left'
772+
| 'top-right'
773+
| 'bottom-right';
774+
713775
/**
714776
* Create a resizer element for a dashboard widget.
715777
*/
716-
export function createResizer(): HTMLElement {
778+
export function createResizer(corner: ResizerCorner): HTMLElement {
717779
const resizer = document.createElement('div');
718780
resizer.classList.add('pr-Resizer');
719-
DashboardIcons.resizer2.element({
720-
container: resizer,
721-
width: '15px',
722-
height: '15px',
723-
pointerEvents: 'none'
724-
});
781+
782+
switch (corner) {
783+
case 'top-left':
784+
resizer.classList.add('pr-ResizerTopLeft');
785+
break;
786+
case 'top-right':
787+
resizer.classList.add('pr-ResizerTopRight');
788+
break;
789+
case 'bottom-left':
790+
resizer.classList.add('pr-ResizerBottomLeft');
791+
break;
792+
case 'bottom-right':
793+
resizer.classList.add('pr-ResizerBottomRight');
794+
break;
795+
default:
796+
resizer.classList.add('pr-ResizerBottomRight');
797+
break;
798+
}
725799

726800
return resizer;
727801
}

style/base.css

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,61 +13,74 @@
1313
}
1414

1515
.pr-EditableWidget {
16-
border: var(--jp-border-width) solid var(--jp-inverse-layout-color4);
16+
outline: var(--jp-border-width) solid var(--jp-inverse-layout-color4);
17+
outline-offset: calc( -1 * var(--jp-border-width));
1718
background: var(--jp-layout-color0);
19+
overflow: visible;
1820
}
1921

2022
.pr-EditableWidget > .pr-DashboardWidgetChild {
2123
pointer-events: none;
2224
}
2325

2426
.pr-EditableWidget:focus {
25-
border: var(--jp-border-width) solid var(--jp-brand-color1);
26-
}
27-
28-
.pr-EditableWidget:focus:after {
29-
content: '';
30-
position: absolute;
31-
width: 100%;
32-
height: 100%;
33-
z-index: 2;
34-
background: rgba(0, 0, 0, 0.1);
27+
outline: var(--jp-border-width) solid var(--jp-brand-color1);
28+
outline-offset: calc( -1 * var(--jp-border-width));
3529
}
3630

3731
.pr-EditableWidget:hover {
38-
border: var(--jp-border-width) solid var(--jp-brand-color1);
32+
outline: var(--jp-border-width) solid var(--jp-brand-color1);
33+
outline-offset: calc( -1 * var(--jp-border-width));
3934
cursor: move;
4035
}
4136

42-
.pr-EditableWidget:hover:after {
43-
content: '';
44-
position: absolute;
45-
width: 100%;
46-
height: 100%;
47-
z-index: 2;
48-
background: rgba(0, 0, 0, 0.1);
49-
}
50-
5137
.pr-DashboardArea {
5238
overflow: auto;
5339
}
5440

5541
.pr-Resizer {
5642
display: none;
57-
width: 15px;
58-
height: 15px;
59-
right: 0;
60-
bottom: 0;
43+
width: 8px;
44+
height: 8px;
45+
outline: 2px solid var(--jp-brand-color1);
6146
z-index: 3;
62-
cursor: nwse-resize;
47+
background-color: var(--jp-layout-color0);
6348
position: absolute;
6449
}
6550

51+
.pr-Resizer:hover {
52+
background-color: var(--jp-brand-color1);
53+
}
54+
55+
.pr-ResizerBottomRight {
56+
right: -4px;
57+
bottom: -4px;
58+
cursor: nwse-resize;
59+
}
60+
61+
.pr-ResizerBottomLeft {
62+
left: -4px;
63+
bottom: -4px;
64+
cursor: nesw-resize;
65+
}
66+
67+
.pr-ResizerTopRight {
68+
right: -4px;
69+
top: -4px;
70+
cursor: nesw-resize;
71+
}
72+
73+
.pr-ResizerTopLeft {
74+
left: -4px;
75+
top: -4px;
76+
cursor: nwse-resize;
77+
}
78+
6679
.pr-DashboardWidgetChild {
6780
display: inline-block;
6881
}
6982

70-
.pr-EditableWidget:hover .pr-Resizer {
83+
.pr-EditableWidget:focus .pr-Resizer {
7184
display: block;
7285
}
7386

@@ -76,29 +89,19 @@
7689
}
7790

7891
.pr-Canvas.pr-FreeLayout {
79-
background-image: linear-gradient(
80-
45deg,
81-
rgba(160, 160, 160, 0.15) 25%,
82-
transparent 25%
83-
),
84-
linear-gradient(-45deg, rgba(160, 160, 160, 0.15) 25%, transparent 25%),
85-
linear-gradient(45deg, transparent 75%, rgba(160, 160, 160, 0.15) 75%),
86-
linear-gradient(-45deg, transparent 75%, rgba(160, 160, 160, 0.15) 70%);
87-
background-size: 20px 20px;
88-
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
92+
background-image:
93+
linear-gradient(to right, #E5E5E5 1px, transparent 1px),
94+
linear-gradient(to bottom, #E5E5E5 1px, transparent 1px);
95+
background-color: white;
96+
background-size: 10px 10px;
8997
}
9098

9199
.pr-Canvas.pr-TiledLayout {
92-
background-image: linear-gradient(
93-
45deg,
94-
rgba(160, 160, 160, 0.15) 25%,
95-
transparent 25%
96-
),
97-
linear-gradient(-45deg, rgba(160, 160, 160, 0.15) 25%, transparent 25%),
98-
linear-gradient(45deg, transparent 75%, rgba(160, 160, 160, 0.15) 75%),
99-
linear-gradient(-45deg, transparent 75%, rgba(160, 160, 160, 0.15) 70%);
100-
background-size: 64px 64px;
101-
background-position: 0 0, 0 32px, 32px -32px, -32px 0px;
100+
background-image:
101+
linear-gradient(to right, #E5E5E5 1px, transparent 1px),
102+
linear-gradient(to bottom, #E5E5E5 1px, transparent 1px);
103+
background-color: white;
104+
background-size: 32px 32px;
102105
}
103106

104107
.pr-OnboardingGif {
@@ -140,5 +143,6 @@ select.pr-ToolbarSelector.jp-mod-styled {
140143

141144
.pr-DragImage {
142145
box-shadow: var(--jp-elevation-z1);
143-
border: var(--jp-border-width) solid var(--jp-brand-color1);
146+
outline: var(--jp-border-width) solid var(--jp-brand-color1);
147+
outline-offset: calc( -1 * var(--jp-border-width));
144148
}

0 commit comments

Comments
 (0)