aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/ContextMenu.scss58
-rw-r--r--src/client/views/ContextMenu.tsx19
-rw-r--r--src/client/views/ContextMenuItem.tsx52
-rw-r--r--src/client/views/collections/CollectionPDFView.tsx2
-rw-r--r--src/client/views/collections/CollectionVideoView.tsx1
-rw-r--r--src/client/views/collections/CollectionView.tsx32
-rw-r--r--src/client/views/nodes/DocumentView.tsx61
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx10
-rw-r--r--src/client/views/nodes/ImageBox.tsx5
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"
});
}
}