aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryipstanley <stanley_yip@brown.edu>2019-06-14 17:44:17 -0400
committeryipstanley <stanley_yip@brown.edu>2019-06-14 17:44:17 -0400
commitb987e2edbf7befbe90fafbdee476ee3b6513cc50 (patch)
tree228b095ec696d9f80c2f378b0400f5d72dc91496
parent4a5fd3e230fe354dd6c579cad0d5f99a40d230db (diff)
pinning things
-rw-r--r--src/client/views/MainView.tsx3
-rw-r--r--src/client/views/pdf/PDFMenu.scss13
-rw-r--r--src/client/views/pdf/PDFMenu.tsx119
-rw-r--r--src/client/views/pdf/Page.tsx21
4 files changed, 137 insertions, 19 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 384cd2860..29015995f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
@@ -92,6 +92,7 @@ export class MainView extends React.Component {
library.add(faMusic);
library.add(faTree);
library.add(faCommentAlt);
+ library.add(faThumbtack);
this.initEventListeners();
this.initAuthenticationRouters();
}
diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss
index b84ebc12d..22868082a 100644
--- a/src/client/views/pdf/PDFMenu.scss
+++ b/src/client/views/pdf/PDFMenu.scss
@@ -1,18 +1,25 @@
.pdfMenu-cont {
position: absolute;
z-index: 10000;
- width: 100px;
- height: 30px;
+ height: 35px;
background: #323232;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
- border-radius: 0px 4px 4px 4px;
+ border-radius: 0px 6px 6px 6px;
overflow: hidden;
+ display: flex;
.pdfMenu-button {
background-color: transparent;
+ width: 35px;
+ height: 35px;
}
.pdfMenu-button:hover {
background-color: #121212;
}
+
+ .pdfMenu-dragger {
+ height: 100%;
+ transition: width .2s;
+ }
} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index a0230113b..d2a20fb6e 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -1,6 +1,6 @@
import React = require("react");
import "./PDFMenu.scss";
-import { observable } from "mobx";
+import { observable, action } from "mobx";
import { observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { emptyFunction } from "../../../Utils";
@@ -10,10 +10,18 @@ import { Doc } from "../../../new_fields/Doc";
export default class PDFMenu extends React.Component {
static Instance: PDFMenu;
- @observable Top: number = 0;
- @observable Left: number = 0;
+ @observable private _top: number = 0;
+ @observable private _left: number = 0;
+ @observable private _opacity: number = 1;
+ @observable private _transition: string = "opacity 0.5s";
+ @observable private _transitionDelay: string = "";
+ @observable private _pinned: boolean = false;
+
StartDrag: (e: PointerEvent) => void = emptyFunction;
Highlight: (d: Doc | undefined) => void = emptyFunction;
+ @observable Highlighting: boolean = false;
+
+ private _timeout: NodeJS.Timeout | undefined;
constructor(props: Readonly<{}>) {
super(props);
@@ -38,12 +46,109 @@ export default class PDFMenu extends React.Component {
e.preventDefault();
}
+ @action
+ jumpTo = (x: number, y: number) => {
+ if (!this._pinned) {
+ this._transition = this._transitionDelay = "";
+ this._opacity = 1;
+ this._left = x;
+ this._top = y;
+ }
+ }
+
+ @action
+ fadeOut = (forceOut: boolean) => {
+ if (!this._pinned) {
+ if (this._opacity === 0.2) {
+ this._transition = "opacity 0.1s";
+ this._transitionDelay = "";
+ this._opacity = 0;
+ this._left = this._top = -300;
+ }
+
+ if (forceOut) {
+ this._transition = "";
+ this._transitionDelay = "";
+ this._opacity = 0;
+ this._left = this._top = -300;
+ }
+ }
+ }
+
+ @action
+ pointerLeave = (e: React.PointerEvent) => {
+ if (!this._pinned) {
+ this._transition = "opacity 0.5s";
+ this._transitionDelay = "1s";
+ this._opacity = 0.2;
+ setTimeout(() => this.fadeOut(false), 3000);
+ }
+ }
+
+ @action
+ pointerEntered = (e: React.PointerEvent) => {
+ this._transition = "opacity 0.1s";
+ this._transitionDelay = "";
+ this._opacity = 1;
+ }
+
+ @action
+ togglePin = (e: React.MouseEvent) => {
+ this._pinned = !this._pinned;
+ }
+
+ @action
+ dragging = (e: PointerEvent) => {
+ this._left += e.movementX;
+ this._top += e.movementY;
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ dragEnd = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.dragging);
+ document.removeEventListener("pointerup", this.dragEnd);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ dragStart = (e: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.dragging);
+ document.addEventListener("pointermove", this.dragging);
+ document.removeEventListener("pointerup", this.dragEnd);
+ document.addEventListener("pointerup", this.dragEnd);
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ @action
+ highlightClicked = (e: React.MouseEvent) => {
+ if (!this._pinned) {
+ this.Highlight(undefined);
+ }
+ else {
+ this.Highlighting = !this.Highlighting;
+ this.Highlight(undefined);
+ }
+ }
+
render() {
return (
- <div className="pdfMenu-cont" style={{ left: this.Left, top: this.Top }}>
- <button className="pdfMenu-button" title="Highlight" onClick={() => this.Highlight(undefined)}><FontAwesomeIcon icon="highlighter" size="sm" /></button>
- <button className="pdfMenu-button" title="Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="sm" /></button>
- </div>
+ <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered}
+ style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
+ <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked}
+ style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>
+ <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
+ </button>
+ <button className="pdfMenu-button" title="Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>
+ <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
+ style={this._pinned ? { backgroundColor: "#121212" } : {}}>
+ <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
+ </button>
+ <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} />
+ </div >
)
}
} \ No newline at end of file
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 44c502a04..3bc3ac33c 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -132,6 +132,7 @@ export default class Page extends React.Component<IPageProps> {
}
}
+ @action
highlight = (targetDoc: Doc | undefined) => {
// creates annotation documents for current highlights
let annotationDoc = this.props.makeAnnotationDocuments(targetDoc);
@@ -196,6 +197,7 @@ export default class Page extends React.Component<IPageProps> {
// document.addEventListener("pointerup", this.endDrag);
}
else if (e.button === 0) {
+ PDFMenu.Instance.fadeOut(true);
let target: any = e.target;
if (target && target.parentElement === this._textLayer.current) {
e.stopPropagation();
@@ -304,25 +306,28 @@ export default class Page extends React.Component<IPageProps> {
}
copy.className = this._marquee.current.className;
this.props.createAnnotation(copy, this.props.page);
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
this._marquee.current.style.opacity = "0";
}
this._marqueeHeight = this._marqueeWidth = 0;
- PDFMenu.Instance.Left = e.clientX;
- PDFMenu.Instance.Top = e.clientY;
+ PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
}
else {
let sel = window.getSelection();
if (sel && sel.type === "Range") {
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
this.createTextAnnotation(sel);
- PDFMenu.Instance.Left = e.clientX;
- PDFMenu.Instance.Top = e.clientY;
+ PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
}
}
+
+
+ if (PDFMenu.Instance.Highlighting) {
+ this.highlight(undefined);
+ }
+ else {
+ PDFMenu.Instance.StartDrag = this.startDrag;
+ PDFMenu.Instance.Highlight = this.highlight;
+ }
// let x = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
// let y = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
// if (this._marqueeing) {