From b987e2edbf7befbe90fafbdee476ee3b6513cc50 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Fri, 14 Jun 2019 17:44:17 -0400
Subject: pinning things

---
 src/client/views/pdf/PDFMenu.tsx | 119 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 112 insertions(+), 7 deletions(-)

(limited to 'src/client/views/pdf/PDFMenu.tsx')

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
-- 
cgit v1.2.3-70-g09d2

