Skip to content

Commit 31acb8b

Browse files
authored
Merge pull request #113 from cameron-toy/design_improvements
Design and resizer improvements
2 parents 13a84d1 + 7e713c6 commit 31acb8b

File tree

5 files changed

+186
-79
lines changed

5 files changed

+186
-79
lines changed

src/icons.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import greyDashboardSvgstr from '../style/icons/dashboard_icon_filled_grey.svg';
55
import blueDashboardSvgstr from '../style/icons/dashboard_icon_filled_blue.svg';
66
import whiteDashboardOutlineSvgstr from '../style/icons/dashboard_icon_outline_white.svg';
77
import greyDashboardOutlineSvgstr from '../style/icons/dashboard_icon_outline_grey.svg';
8+
import tealDashboardSvgstr from '../style/icons/dashboard_icon_filled_teal.svg';
89
import redoIcon from '../style/icons/redo.svg';
910
import fullscreenIcon from '../style/icons/fullscreen.svg';
1011
import statusIcon from '../style/icons/dummy.svg';
@@ -17,6 +18,11 @@ import resizer2Svgstr from '../style/icons/drag indicator lines.svg';
1718
* Dashboard icons
1819
*/
1920
export namespace DashboardIcons {
21+
export const tealDashboard = new LabIcon({
22+
name: 'pr-icons:teal-dashboard',
23+
svgstr: tealDashboardSvgstr
24+
});
25+
2026
export const whiteDashboard = new LabIcon({
2127
name: 'pr-icons:white-dashboard',
2228
svgstr: whiteDashboardSvgstr

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const extension: JupyterFrontEndPlugin<IDashboardTracker> = {
8686
contentType: 'file',
8787
extensions: ['.dashboard', '.dash'],
8888
fileFormat: 'text',
89-
icon: DashboardIcons.blueDashboard,
89+
icon: DashboardIcons.tealDashboard,
9090
iconLabel: 'Dashboard',
9191
mimeTypes: ['application/json']
9292
};
@@ -550,7 +550,7 @@ function addCommands(
550550

551551
commands.addCommand(CommandIDs.createNew, {
552552
label: 'Dashboard',
553-
icon: DashboardIcons.blueDashboard,
553+
icon: DashboardIcons.tealDashboard,
554554
execute: async args => {
555555
// A new file is created and opened separately to override the default
556556
// opening behavior when there's a notebook and open the dashboard in a

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: 114 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { CodeCell, MarkdownCell } from '@jupyterlab/cells';
44

55
import { Widget } from '@lumino/widgets';
66

7+
import { MessageLoop } from '@lumino/messaging';
8+
79
import { UUID, MimeData } from '@lumino/coreutils';
810

911
import { ArrayExt } from '@lumino/algorithm';
@@ -23,8 +25,6 @@ import {
2325

2426
import { Signal, ISignal } from '@lumino/signaling';
2527

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

3030
import { DashboardLayout } from './layout';
@@ -132,8 +132,20 @@ export class DashboardWidget extends Widget {
132132
this.node.style.opacity = '0';
133133

134134
container.classList.add(DASHBOARD_WIDGET_CHILD_CLASS);
135-
container.appendChild(clone.node);
136-
this.node.appendChild(container);
135+
136+
// Fake an attach in order to render LaTeX properly.
137+
// Note: This is not how you should use Lumino widgets.
138+
if (this.parent) {
139+
if (this.parent!.isAttached) {
140+
MessageLoop.sendMessage(clone, Widget.Msg.BeforeAttach);
141+
container.appendChild(clone.node);
142+
this.node.appendChild(container);
143+
if (this.parent!.isAttached) {
144+
MessageLoop.sendMessage(clone, Widget.Msg.AfterAttach);
145+
}
146+
}
147+
}
148+
137149
this._content = clone;
138150

139151
const done = (): void => {
@@ -152,8 +164,14 @@ export class DashboardWidget extends Widget {
152164
});
153165
}
154166

155-
const resizer = DashboardWidget.createResizer();
156-
this.node.appendChild(resizer);
167+
const resizerTopLeft = DashboardWidget.createResizer('top-left');
168+
const resizerTopRight = DashboardWidget.createResizer('top-right');
169+
const resizerBottomLeft = DashboardWidget.createResizer('bottom-left');
170+
const resizerBottomRight = DashboardWidget.createResizer('bottom-right');
171+
this.node.appendChild(resizerTopLeft);
172+
this.node.appendChild(resizerTopRight);
173+
this.node.appendChild(resizerBottomLeft);
174+
this.node.appendChild(resizerBottomRight);
157175

158176
this.addClass(DASHBOARD_WIDGET_CLASS);
159177
this.addClass(EDITABLE_WIDGET_CLASS);
@@ -294,9 +312,19 @@ export class DashboardWidget extends Widget {
294312

295313
// this.node.style.opacity = '0.6';
296314

315+
const elem = target as HTMLElement;
297316
// Set mode to resize if the mousedown happened on a resizer.
298-
if ((target as HTMLElement).classList.contains('pr-Resizer')) {
317+
if (elem.classList.contains('pr-Resizer')) {
299318
this._mouseMode = 'resize';
319+
if (elem.classList.contains('pr-ResizerTopRight')) {
320+
this._selectedResizer = 'top-right';
321+
} else if (elem.classList.contains('pr-ResizerTopLeft')) {
322+
this._selectedResizer = 'top-left';
323+
} else if (elem.classList.contains('pr-ResizerBottomLeft')) {
324+
this._selectedResizer = 'bottom-left';
325+
} else {
326+
this._selectedResizer = 'bottom-right';
327+
}
300328
} else {
301329
this._mouseMode = 'drag';
302330
}
@@ -305,12 +333,16 @@ export class DashboardWidget extends Widget {
305333

306334
const rect = this.node.getBoundingClientRect();
307335

336+
const { width, height, top, left } = this.pos;
337+
308338
this._clickData = {
309339
pressX: event.clientX,
310340
pressY: event.clientY,
311341
cell,
312-
pressWidth: parseInt(this.node.style.width, 10),
313-
pressHeight: parseInt(this.node.style.height, 10),
342+
origWidth: width,
343+
origHeight: height,
344+
origLeft: left,
345+
origTop: top,
314346
target: this.node.cloneNode(true) as HTMLElement,
315347
widgetX: rect.left,
316348
widgetY: rect.top
@@ -352,16 +384,44 @@ export class DashboardWidget extends Widget {
352384
* Handle `mousemove` events when the widget mouseMode is `resize`.
353385
*/
354386
private _resizeMouseMove(event: MouseEvent): void {
355-
const { pressX, pressY, pressWidth, pressHeight } = this._clickData;
387+
const {
388+
pressX,
389+
pressY,
390+
origWidth,
391+
origHeight,
392+
origLeft,
393+
origTop
394+
} = this._clickData;
356395

357396
const deltaX = event.clientX - pressX;
358397
const deltaY = event.clientY - pressY;
359398

360-
const width = Math.max(pressWidth + deltaX, DashboardWidget.MIN_WIDTH);
361-
const height = Math.max(pressHeight + deltaY, DashboardWidget.MIN_HEIGHT);
399+
let { width, height, top, left } = this.pos;
400+
401+
switch (this._selectedResizer) {
402+
case 'bottom-right':
403+
width = Math.max(origWidth + deltaX, DashboardWidget.MIN_WIDTH);
404+
height = Math.max(origHeight + deltaY, DashboardWidget.MIN_HEIGHT);
405+
break;
406+
case 'bottom-left':
407+
width = Math.max(origWidth - deltaX, DashboardWidget.MIN_WIDTH);
408+
height = Math.max(origHeight + deltaY, DashboardWidget.MIN_HEIGHT);
409+
left = origLeft + deltaX;
410+
break;
411+
case 'top-right':
412+
width = Math.max(origWidth + deltaX, DashboardWidget.MIN_WIDTH);
413+
height = Math.max(origHeight - deltaY, DashboardWidget.MIN_HEIGHT);
414+
top = origTop + deltaY;
415+
break;
416+
case 'top-left':
417+
width = Math.max(origWidth - deltaX, DashboardWidget.MIN_WIDTH);
418+
height = Math.max(origHeight - deltaY, DashboardWidget.MIN_HEIGHT);
419+
top = origTop + deltaY;
420+
left = origLeft + deltaX;
421+
break;
422+
}
362423

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

366426
if (this.mode === 'grid-edit') {
367427
(this.parent.layout as DashboardLayout).drawDropZone(this.pos, '#2b98f0');
@@ -375,10 +435,14 @@ export class DashboardWidget extends Widget {
375435
* Fit widget width/height to the width/height of the underlying content.
376436
*/
377437
fitContent(): void {
378-
const element = this._content.node;
438+
const element = this._content.node.firstChild as HTMLElement;
379439
// 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`;
440+
this.pos = {
441+
width: element.clientWidth + 3,
442+
height: element.clientHeight + 2,
443+
left: undefined,
444+
top: undefined
445+
};
382446
}
383447

384448
/**
@@ -642,15 +706,18 @@ export class DashboardWidget extends Widget {
642706
private _clickData: {
643707
pressX: number;
644708
pressY: number;
645-
pressWidth: number;
646-
pressHeight: number;
709+
origWidth: number;
710+
origHeight: number;
711+
origLeft: number;
712+
origTop: number;
647713
target: HTMLElement;
648714
cell: CodeCell | MarkdownCell;
649715
widgetX: number;
650716
widgetY: number;
651717
} | null = null;
652718
private _locked = false;
653719
private _content: Widget;
720+
private _selectedResizer: DashboardWidget.ResizerCorner;
654721
}
655722

656723
/**
@@ -710,18 +777,39 @@ export namespace DashboardWidget {
710777
return `DashboardWidget-${UUID.uuid4()}`;
711778
}
712779

780+
/**
781+
* A type for describing the corner for a widget resizer.
782+
*/
783+
export type ResizerCorner =
784+
| 'top-left'
785+
| 'bottom-left'
786+
| 'top-right'
787+
| 'bottom-right';
788+
713789
/**
714790
* Create a resizer element for a dashboard widget.
715791
*/
716-
export function createResizer(): HTMLElement {
792+
export function createResizer(corner: ResizerCorner): HTMLElement {
717793
const resizer = document.createElement('div');
718794
resizer.classList.add('pr-Resizer');
719-
DashboardIcons.resizer2.element({
720-
container: resizer,
721-
width: '15px',
722-
height: '15px',
723-
pointerEvents: 'none'
724-
});
795+
796+
switch (corner) {
797+
case 'top-left':
798+
resizer.classList.add('pr-ResizerTopLeft');
799+
break;
800+
case 'top-right':
801+
resizer.classList.add('pr-ResizerTopRight');
802+
break;
803+
case 'bottom-left':
804+
resizer.classList.add('pr-ResizerBottomLeft');
805+
break;
806+
case 'bottom-right':
807+
resizer.classList.add('pr-ResizerBottomRight');
808+
break;
809+
default:
810+
resizer.classList.add('pr-ResizerBottomRight');
811+
break;
812+
}
725813

726814
return resizer;
727815
}

0 commit comments

Comments
 (0)