diff options
-rw-r--r-- | src/client/cognitive_services/CognitiveServices.ts | 5 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 2 | ||||
-rw-r--r-- | src/client/views/ContextMenu.scss | 57 | ||||
-rw-r--r-- | src/client/views/ContextMenu.tsx | 8 | ||||
-rw-r--r-- | src/client/views/ContextMenuItem.tsx | 6 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 10 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 13 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 34 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/IconBox.tsx | 10 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 29 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 6 | ||||
-rw-r--r-- | src/client/views/search/SearchItem.tsx | 7 |
17 files changed, 144 insertions, 70 deletions
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index d69378d0e..bbc438a9b 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -9,6 +9,7 @@ import { Utils } from "../../Utils"; import { CompileScript } from "../util/Scripting"; import { ComputedField } from "../../new_fields/ScriptField"; import { InkData } from "../../new_fields/InkField"; +import { undoBatch, UndoManager } from "../util/UndoManager"; type APIManager<D> = { converter: BodyConverter<D>, requester: RequestExecutor, analyzer: AnalysisApplier }; type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise<string>; @@ -103,6 +104,7 @@ export namespace CognitiveServices { }, analyzer: async (target: Doc, keys: string[], service: Service, converter: Converter) => { + let batch = UndoManager.StartBatch("Image Analysis"); let imageData = Cast(target.data, ImageField); let storageKey = keys[0]; if (!imageData || await Cast(target[storageKey], Doc)) { @@ -120,6 +122,7 @@ export namespace CognitiveServices { } } target[storageKey] = toStore; + batch.end(); } }; @@ -205,6 +208,7 @@ export namespace CognitiveServices { }, analyzer: async (target: Doc, keys: string[], inkData: InkData) => { + let batch = UndoManager.StartBatch("Ink Analysis"); let results = await executeQuery<InkData, any>(Service.Handwriting, Manager, inkData); if (results) { results.recognitionUnits && (results = results.recognitionUnits); @@ -213,6 +217,7 @@ export namespace CognitiveServices { let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); target[keys[1]] = individualWords.join(" "); } + batch.end(); } }; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 5271f2f5d..95416cd53 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,6 +8,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss"; import { DocumentManager } from "./DocumentManager"; import { LinkManager } from "./LinkManager"; import { SelectionManager } from "./SelectionManager"; +import { DocumentDecorations } from "../views/DocumentDecorations"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -421,6 +422,7 @@ export namespace DragManager { if (options) { options.handlers.dragComplete({}); } + DocumentDecorations.Instance.endLinkDragBatch(); }; AbortDrag = () => { diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 254163b53..e2c0de8af 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -6,6 +6,10 @@ z-index: $contextMenu-zindex; box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw; flex-direction: column; + background: whitesmoke; + padding-bottom: 10px; + border-radius: 15px; + border: solid #BBBBBBBB 1px; } // .contextMenu-item:first-child { @@ -28,12 +32,17 @@ z-index: 1000; box-shadow: #AAAAAA .2vw .2vw .4vw; flex-direction: column; + border: 1px solid #BBBBBBBB; + border-radius: 15px; + padding-top: 10px; + padding-bottom: 10px; + background: whitesmoke; } .contextMenu-item { // width: 11vw; //10vw height: 30px; //2vh - background: #DDDDDD; + background: whitesmoke; display: flex; //comment out to allow search icon to be inline with search text justify-content: left; align-items: center; @@ -44,23 +53,33 @@ -ms-user-select: none; user-select: none; transition: all .1s; + border-style: none; + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 13px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; + padding-right: 30px; +} + +.contextMenu-item:hover { border-width: .11px; border-style: none; border-color: $intermediate-color; // rgb(187, 186, 186); border-bottom-style: solid; - // padding: 10px 0px 10px 0px; - white-space: nowrap; - font-size: 20px; + border-top-style: solid; } .contextMenu-itemSelected { - background: rgb(136, 136, 136) + background: lightgoldenrodyellow; + border-style: none; } .contextMenu-group { // width: 11vw; //10vw height: 30px; //2vh - background: rgb(200, 200, 200); + background: lightgray; display: flex; //comment out to allow search icon to be inline with search text justify-content: left; align-items: center; @@ -74,27 +93,41 @@ border-width: .11px; border-style: none; border-color: $intermediate-color; // rgb(187, 186, 186); - border-bottom-style: solid; // padding: 10px 0px 10px 0px; white-space: nowrap; - font-size: 20px; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 2px; + padding-left: 5px; } .contextMenu-item:hover { - transition: all 0.1s; + transition: all 0.1s ease; background: $lighter-alt-accent; } .contextMenu-description { - font-size: 20px; + margin-left: 5px; text-align: left; display: inline; //need this? } +.search-icon { + margin: 10px; +} + +.search { + margin-left: 10px; + padding-left: 10px; + border: solid black 1px; + border-radius: 5px; +} + .icon-background { pointer-events: none; - background-color: #DDDDDD; + background-color: transparent; width: 35px; text-align: center; - font-size: 22px; + font-size: 20px; + margin-left: 5px; }
\ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index c163c56a0..a608e448a 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -38,6 +38,10 @@ export class ContextMenu extends React.Component { this._items = []; } + findByDescription = (target: string) => { + return this._items.find(menuItem => menuItem.description === target); + } + @action addItem(item: ContextMenuProps) { if (this._items.indexOf(item) === -1) { @@ -165,11 +169,11 @@ export class ContextMenu extends React.Component { const contents = ( <> - <span> + <span className={"search-icon"}> <span className="icon-background"> <FontAwesomeIcon icon="search" size="lg" /> </span> - <input className="contextMenu-item contextMenu-description" type="text" placeholder="Search . . ." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus /> + <input className="contextMenu-item contextMenu-description search" type="text" placeholder="Search . . ." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus /> </span> {this.menuItems} </> diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 9bbb97d7e..badb9cf19 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -10,14 +10,14 @@ library.add(faAngleRight); export interface OriginalMenuProps { description: string; event: () => void; - icon?: IconProp; //maybe should be optional (icon?) + icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } export interface SubmenuProps { description: string; subitems: ContextMenuProps[]; - icon?: IconProp; //maybe should be optional (icon?) + icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } @@ -94,7 +94,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select ) : null} <div className="contextMenu-description"> {this.props.description} - <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "5px" }} /> + <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "10px"}} /> </div> {submenu} </div> diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c08a84742..751b64c35 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -54,6 +54,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _downY = 0; private _iconDoc?: Doc = undefined; private _resizeUndo?: UndoManager.Batch; + private _linkDrag?: UndoManager.Batch; @observable private _minimizedX = 0; @observable private _minimizedY = 0; @observable private _title: string = ""; @@ -376,7 +377,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } + endLinkDragBatch = () => { + if (!this._linkDrag) { + return; + } + this._linkDrag.end(); + this._linkDrag = undefined; + } + onLinkerButtonDown = (e: React.PointerEvent): void => { + this._linkDrag = UndoManager.StartBatch("Drag Link"); e.stopPropagation(); document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.addEventListener("pointermove", this.onLinkerButtonMoved); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8b7eb8856..52292abbb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -389,7 +389,7 @@ export class MainView extends React.Component { ]; if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]); - return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} > + return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 20, bottom: 20 }} > <input type="checkbox" id="add-menu-toggle" ref={this.addMenuToggle} /> <label htmlFor="add-menu-toggle" style={{ marginTop: 2 }} title="Add Node"><p>+</p></label> diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 0f67c47aa..a57d3c81a 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { faCog, faPlus, faTable } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; @@ -34,7 +34,7 @@ import { ComputedField } from "../../../new_fields/ScriptField"; library.add(faCog); -library.add(faPlus); +library.add(faPlus, faTable); // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -321,7 +321,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { 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: "Make DB", event: this.makeDB }); + ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" }); } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a1697f9b4..1c7fe4bee 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt, faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; @@ -61,7 +61,7 @@ library.add(faCaretRight); library.add(faCaretSquareDown); library.add(faCaretSquareRight); library.add(faArrowsAltH); - +library.add(faPlus, faMinus); @observer /** * Component that takes in a document prop and a boolean whether it's collapsed or not. @@ -520,8 +520,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document - ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) }); - ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) }); + ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()), icon: "plus" }); + ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)), icon: "minus" }); e.stopPropagation(); e.preventDefault(); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index cd137cd60..b4f29755c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -15,6 +15,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; +import { faEye } from '@fortawesome/free-regular-svg-icons'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -26,7 +27,7 @@ library.add(faThList); library.add(faFingerprint); library.add(faColumns); library.add(faEllipsisV); -library.add(faImage); +library.add(faImage, faEye); @observer export class CollectionView extends React.Component<FieldViewProps> { @@ -66,7 +67,7 @@ export class CollectionView extends React.Component<FieldViewProps> { break; } } - ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); + ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c5ed64314..d07fc7f80 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -13,7 +13,7 @@ import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; -import { ContextMenu } from "../../ContextMenu"; +import { SubmenuProps, ContextMenuProps } from "../../ContextMenuItem"; import { InkingCanvas } from "../../InkingCanvas"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; @@ -34,11 +34,12 @@ import { CompileScript } from "../../../util/Scripting"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faTable, faPaintBrush, faAsterisk, faExpandArrowsAlt, faCompressArrowsAlt } from "@fortawesome/free-solid-svg-icons"; +import { faTable, faPaintBrush, faAsterisk, faExpandArrowsAlt, faCompressArrowsAlt, faCompass } from "@fortawesome/free-solid-svg-icons"; import { undo } from "prosemirror-history"; import { number } from "prop-types"; +import { ContextMenu } from "../../ContextMenu"; -library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt); +library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass); export const panZoomSchema = createSchema({ panX: "number", @@ -492,12 +493,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } onContextMenu = () => { - ContextMenu.Instance.addItem({ + let layoutItems: ContextMenuProps[] = []; + layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: undoBatch(async () => this.props.Document.fitToBox = !this.fitToBox), icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); - ContextMenu.Instance.addItem({ + layoutItems.push({ description: "Arrange contents in grid", icon: "table", event: async () => { @@ -524,6 +526,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } }); + ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); ContextMenu.Instance.addItem({ description: "Analyze Strokes", event: async () => { let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8177916c5..ddb3ad44e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -39,6 +39,8 @@ import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; import { ClientUtils } from '../../util/ClientUtils'; import { EditableView } from '../EditableView'; +import { faHandPointer, faHandPointRight } from '@fortawesome/free-regular-svg-icons'; +import { DocumentDecorations } from '../DocumentDecorations'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -60,8 +62,7 @@ library.add(fa.faCrosshairs); library.add(fa.faDesktop); library.add(fa.faUnlock); library.add(fa.faLock); -library.add(fa.faLaptopCode); - +library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake); // const linkSchema = createSchema({ // title: "string", @@ -551,12 +552,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); - cm.addItem({ description: !BoolCast(this.props.Document.ignoreAspect) && this.props.Document.nativeWidth && this.props.Document.nativeHeight ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); - cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); - cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); - cm.addItem({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); - cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); - cm.addItem({ + cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); + cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); + cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); + let makes: ContextMenuProps[] = []; + makes.push({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); + makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); + makes.push({ description: "Make Portal", event: () => { let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" }); //Doc.GetProto(this.props.Document).subBulletDocs = new List<Doc>([portal]); @@ -570,6 +572,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu }, icon: "window-restore" }); + cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); // cm.addItem({ // description: "Find aliases", event: async () => { // const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); @@ -580,11 +583,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); - cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); + let existing = ContextMenu.Instance.findByDescription("Layout..."); + let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; + layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); + layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); + !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); if (!ClientUtils.RELEASE) { - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + let copies: ContextMenuProps[] = []; + copies.push({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); + copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" }); } cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; @@ -608,7 +616,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu notifDoc.data = new List([sharedDoc]); } } - } + }, icon: "male" })); } catch { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index bd0fd8301..c3d1c0e90 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons'; +import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons'; import { action, IReactionDisposer, observable, reaction, runInAction, computed, trace } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; @@ -38,7 +38,7 @@ import { thisExpression } from 'babel-types'; import { Utils } from '../../../Utils'; library.add(faEdit); -library.add(faSmile); +library.add(faSmile, faTextHeight); // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -462,7 +462,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height", event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems }); + ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" }); } render() { let self = this; diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 6f50033a4..7e78ec684 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTag, faTextHeight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -18,7 +18,7 @@ library.add(faCaretUp); library.add(faObjectGroup); library.add(faStickyNote); library.add(faFilePdf); -library.add(faFilm); +library.add(faFilm, faTag, faTextHeight); @observer export class IconBox extends React.Component<FieldViewProps> { @@ -47,13 +47,15 @@ export class IconBox extends React.Component<FieldViewProps> { specificContextMenu = (): void => { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon", - event: this.setLabelField + event: this.setLabelField, + icon: "tag" }); let maxDocs = DocListCast(this.props.Document.maximizedDocs); if (maxDocs.length === 1 && !BoolCast(this.props.Document.hideLabel)) { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.useOwnTitle) ? "Use target title for label" : "Use own title label", - event: this.setUseOwnTitleField + event: this.setUseOwnTitleField, + icon: "text-height" }); } } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 2115024a1..29a76b0c8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -202,6 +202,20 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD }); } + @undoBatch + rotate = action(() => { + let proto = Doc.GetProto(this.props.Document); + let nw = this.props.Document.nativeWidth; + let nh = this.props.Document.nativeHeight; + let w = this.props.Document.width; + let h = this.props.Document.height; + proto.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + proto.nativeWidth = nh; + proto.nativeHeight = nw; + this.props.Document.width = h; + this.props.Document.height = w; + }); + specificContextMenu = (e: React.MouseEvent): void => { let field = Cast(this.Document[this.props.fieldKey], ImageField); if (field) { @@ -209,20 +223,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD let funcs: ContextMenuProps[] = []; funcs.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); funcs.push({ description: "Record 1sec audio", event: this.recordAudioAnnotation, icon: "expand-arrows-alt" }); - funcs.push({ - description: "Rotate", event: action(() => { - let proto = Doc.GetProto(this.props.Document); - let nw = this.props.Document.nativeWidth; - let nh = this.props.Document.nativeHeight; - let w = this.props.Document.width; - let h = this.props.Document.height; - proto.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; - proto.nativeWidth = nh; - proto.nativeHeight = nw; - this.props.Document.width = h; - this.props.Document.height = w; - }), icon: "expand-arrows-alt" - }); + funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); let modes: ContextMenuProps[] = []; let dataDoc = Doc.GetProto(this.props.Document); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 30ad75000..34cb47b20 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -19,10 +19,14 @@ import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { faVideo } from "@fortawesome/free-solid-svg-icons"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); +library.add(faVideo); + @observer export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) { private _reactionDisposer?: IReactionDisposer; @@ -179,7 +183,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD }, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems }); + ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" }); } } diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 5c2ced2eb..562594210 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote, faFingerprint } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -38,7 +38,7 @@ library.add(faFilm); library.add(faMusic); library.add(faLink); library.add(faChartBar); -library.add(faGlobeAsia); +library.add(faGlobeAsia, faFingerprint); @observer export class SelectorContextMenu extends React.Component<SearchItemProps> { @@ -223,7 +223,8 @@ export class SearchItem extends React.Component<SearchItemProps> { ContextMenu.Instance.addItem({ description: "Copy ID", event: () => { Utils.CopyText(this.props.doc[Id]); - } + }, + icon: "fingerprint" }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } |