diff options
author | yipstanley <stanley_yip@brown.edu> | 2019-06-14 17:44:17 -0400 |
---|---|---|
committer | yipstanley <stanley_yip@brown.edu> | 2019-06-14 17:44:17 -0400 |
commit | b987e2edbf7befbe90fafbdee476ee3b6513cc50 (patch) | |
tree | 228b095ec696d9f80c2f378b0400f5d72dc91496 | |
parent | 4a5fd3e230fe354dd6c579cad0d5f99a40d230db (diff) |
pinning things
-rw-r--r-- | src/client/views/MainView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/pdf/PDFMenu.scss | 13 | ||||
-rw-r--r-- | src/client/views/pdf/PDFMenu.tsx | 119 | ||||
-rw-r--r-- | src/client/views/pdf/Page.tsx | 21 |
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) { |