diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/ContextMenu.scss | 58 | ||||
-rw-r--r-- | src/client/views/ContextMenu.tsx | 19 | ||||
-rw-r--r-- | src/client/views/ContextMenuItem.tsx | 52 | ||||
-rw-r--r-- | src/client/views/collections/CollectionPDFView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionVideoView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 32 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 61 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 10 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 5 |
9 files changed, 164 insertions, 76 deletions
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index fe884ca85..3b1b18f88 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -21,27 +21,35 @@ color: $light-color; } +.subMenu-cont { + position: absolute; + display: flex; + z-index: 1000; + box-shadow: #AAAAAA .2vw .2vw .4vw; + flex-direction: column; +} + .contextMenu-item { - width: auto; - height: auto; - background: $light-color-secondary; - display: flex; - justify-content: left; - align-items: center; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - transition: all 0.1s; - border-width: 0.11px; - border-style: none; - border-color: $intermediate-color; - border-bottom-style: solid; - padding: 10px; - white-space: nowrap; - font-size: 13px; + width: 11vw; //10vw + height: 2.5vh; //2vh + background: #DDDDDD; + display: flex; //comment out to allow search icon to be inline with search text + justify-content: left; + align-items: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-width: .11px; + border-style: none; + border-color: $intermediate-color; // rgb(187, 186, 186); + border-bottom-style: solid; + padding: 10px; + white-space: nowrap; + font-size: 1.5vw; } .contextMenu-item:hover { @@ -50,6 +58,12 @@ } .contextMenu-description { - text-align: left; - width: 8vw; + font-size: 1.5vw; + text-align: left; + width: 8vw; + display: inline; //need this? +} + +.icon-background { + background-color: #DDDDDD; } diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 615a928ad..9ccbb7149 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,14 +1,19 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; -import { observer } from "mobx-react"; -import "./ContextMenu.scss"; +import { observer } from "mobx-react" +import "./ContextMenu.scss" +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSearch } from '@fortawesome/free-solid-svg-icons'; + +library.add(faSearch); @observer export class ContextMenu extends React.Component { static Instance: ContextMenu; - @observable private _items: Array<ContextMenuProps> = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault() }]; + @observable private _items: Array<ContextMenuProps> = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault(), icon: "smile" }]; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: string = "none"; @@ -82,7 +87,13 @@ export class ContextMenu extends React.Component { return ( <div className="contextMenu-cont" style={style} ref={this.ref}> - <input className="contextMenu-item" type="text" placeholder="Search . . ." value={this._searchString} onChange={this.onChange}></input> + <span> + <span className="icon-background"> + <FontAwesomeIcon icon="circle" size="lg" /> + <FontAwesomeIcon icon="search" size="lg" /> + </span> + <input className="contextMenu-item" type="text" placeholder="Search . . ." value={this._searchString} onChange={this.onChange} /> + </span> {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). map(prop => <ContextMenuItem {...prop} key={prop.description} />)} </div> diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 70813f0dd..ed583942a 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -1,8 +1,13 @@ import React = require("react"); +import { observable, action } from "mobx"; +import { observer } from "mobx-react"; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -export interface ContextMenuProps { +export interface OriginalMenuProps { description: string; event: (e: React.MouseEvent<HTMLDivElement>) => void; + icon?: IconProp; //maybe should be optional (icon?) } export interface SubmenuProps { @@ -13,13 +18,48 @@ export interface SubmenuProps { export interface ContextMenuItemProps { type: ContextMenuProps | SubmenuProps; } +export type ContextMenuProps = OriginalMenuProps | SubmenuProps; +@observer export class ContextMenuItem extends React.Component<ContextMenuProps> { + @observable private _items: Array<ContextMenuProps> = []; + @observable private overItem = false; + + constructor(props: ContextMenuProps | SubmenuProps) { + super(props); + if ("subitems" in this.props) { + this.props.subitems.forEach(i => this._items.push(i)); + } + } + render() { - return ( - <div className="contextMenu-item" onClick={this.props.event}> - <div className="contextMenu-description">{this.props.description}</div> - </div> - ); + if ("event" in this.props) { + return ( + <div className="contextMenu-item" onClick={this.props.event}> + <span className="icon-background"> + <FontAwesomeIcon icon="circle" size="sm" /> + {this.props.icon ? <FontAwesomeIcon icon={this.props.icon} size="sm" /> : null} + </span> + <div className="contextMenu-description"> {this.props.description}</div> + </div> + ); + } + else { + let submenu = null; + if (this.overItem) { + submenu = ( + <div className="subMenu-cont" style={{ marginLeft: "100.5%", left: "0px" }}> + {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} />)} + </div> + ); + } + return ( + <div className="contextMenu-item" onMouseEnter={action(() => { this.overItem = true; })} + onMouseLeave={action(() => this.overItem = false)}> + <div className="contextMenu-description"> {this.props.description}</div> + {submenu} + </div> + ); + } } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index b3762206a..a6614da21 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -61,7 +61,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "PDFOptions", event: emptyFunction }); + ContextMenu.Instance.addItem({ description: "PDFOptions", event: emptyFunction, icon: "file-pdf" }); } } diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 16121bb1b..9ab959f3c 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -66,7 +66,6 @@ export class CollectionVideoView extends React.Component<FieldViewProps> { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "VideoOptions", event: emptyFunction }); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 55fd2a284..3d9b4990a 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,15 +1,23 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faProjectDiagram, faSquare, faTh, faTree } from '@fortawesome/free-solid-svg-icons'; +import { observer } from "mobx-react"; import * as React from 'react'; -import { FieldViewProps, FieldView } from '../nodes/FieldView'; -import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView'; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -import { CollectionSchemaView } from './CollectionSchemaView'; -import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionTreeView } from './CollectionTreeView'; -import { ContextMenu } from '../ContextMenu'; +import { Id } from '../../../new_fields/RefField'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { observer } from 'mobx-react'; import { undoBatch } from '../../util/UndoManager'; -import { Id } from '../../../new_fields/RefField'; +import { ContextMenu } from "../ContextMenu"; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; +import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from './CollectionBaseView'; +import { CollectionDockingView } from "./CollectionDockingView"; +import { CollectionSchemaView } from "./CollectionSchemaView"; +import { CollectionTreeView } from "./CollectionTreeView"; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +export const COLLECTION_BORDER_WIDTH = 2; + +library.add(faTh); +library.add(faTree); +library.add(faSquare); +library.add(faProjectDiagram); @observer export class CollectionView extends React.Component<FieldViewProps> { @@ -32,9 +40,9 @@ export class CollectionView extends React.Component<FieldViewProps> { onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform) }); - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema) }); - ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree) }); + ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "project-diagram" }); + ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "project-diagram" }); + ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b7d8eda9c..7167da93b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,33 +1,44 @@ -import { action, computed, runInAction, reaction, IReactionDisposer } from "mobx"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; +import { Copy, ObjectField } from "../../../new_fields/ObjectField"; +import { Id } from "../../../new_fields/RefField"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { BoolCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { emptyFunction, Utils } from "../../../Utils"; +import { DocServer } from "../../DocServer"; import { Docs } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, dropActionType } from "../../util/DragManager"; +import { SearchUtil } from "../../util/SearchUtil"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; -import { undoBatch, UndoManager } from "../../util/UndoManager"; +import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; +import { DocComponent } from "../DocComponent"; +import { PresentationView } from "../PresentationView"; import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Opt, Doc, WidthSym, HeightSym, DocListCastAsync, DocListCast } from "../../../new_fields/Doc"; -import { DocComponent } from "../DocComponent"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { FieldValue, StrCast, BoolCast, Cast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { DocServer } from "../../DocServer"; -import { Id } from "../../../new_fields/RefField"; -import { PresentationView } from "../PresentationView"; -import { SearchUtil } from "../../util/SearchUtil"; -import { ObjectField, Copy } from "../../../new_fields/ObjectField"; +const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? + +library.add(faTrash); +library.add(faExpandArrowsAlt); +library.add(faCompressArrowsAlt); +library.add(faLayerGroup); +library.add(faAlignCenter); +library.add(faCaretSquareRight); +library.add(faSquare); const linkSchema = createSchema({ title: "string", @@ -300,22 +311,22 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu e.preventDefault(); const cm = ContextMenu.Instance; - cm.addItem({ description: "Full Screen", event: this.fullScreenClicked }); - cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton }); - cm.addItem({ description: "Fields", event: this.fieldsClicked }); - cm.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }); - cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document) }); - cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }); + cm.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "expand-arrows-alt" }); + cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton, icon: "expand-arrows-alt" }); + cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); + cm.addItem({ description: "Center", event: () => this.props.focus(this.props.Document), icon: "align-center" }); + cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }); cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); CollectionDockingView.Instance.AddRightSplit(Docs.SchemaDocument(["title"], aliases, {})); - } + }, icon: "expand-arrows-alt" }); - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])) }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]) }); - cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document) }); - cm.addItem({ description: "Delete", event: this.deleteClicked }); + cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); if (!this.topMost) { // DocumentViews should stop propagation of this event e.stopPropagation(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index bf98fb40b..98abde89e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,3 +1,5 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons'; import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; @@ -5,7 +7,7 @@ import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import { Doc, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { Doc, Field, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { RichTextField } from "../../../new_fields/RichTextField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; @@ -27,6 +29,9 @@ import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); +library.add(faEdit); +library.add(faSmile); + // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // // HTML Markup: <FormattedTextBox Doc={Document's ID} FieldKey={Key's name} @@ -286,7 +291,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } ContextMenu.Instance.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", - event: this.freezeNativeDimensions + event: this.freezeNativeDimensions, + icon: "edit" }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 33411f978..828ac9bc8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,5 +1,4 @@ - -import { action, observable, trace } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app @@ -134,7 +133,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD ContextMenu.Instance.addItem({ description: "Copy path", event: () => { Utils.CopyText(url); - } + }, icon: "expand-arrows-alt" }); } } |