diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/ContextMenu.tsx | 50 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.scss | 17 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 14 | ||||
-rw-r--r-- | src/client/views/Main.scss | 2 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.tsx | 19 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 12 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss | 4 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.scss | 27 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 4 | ||||
-rw-r--r-- | src/client/views/search/SearchBox.scss | 5 | ||||
-rw-r--r-- | src/client/views/search/SearchBox.tsx | 21 | ||||
-rw-r--r-- | src/new_fields/Doc.ts | 3 |
14 files changed, 145 insertions, 38 deletions
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 1bf6e383d..760736501 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from "./ContextMenuItem"; -import { observable, action, computed } from "mobx"; +import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import "./ContextMenu.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; @@ -27,6 +27,13 @@ export class ContextMenu extends React.Component { @observable private _width: number = 0; @observable private _height: number = 0; + @observable private _mouseX: number = -1; + @observable private _mouseY: number = -1; + @observable private _shouldDisplay: boolean = false; + @observable private _mouseDown: boolean = false; + + private _reactionDisposer?: IReactionDisposer; + constructor(props: Readonly<{}>) { super(props); @@ -34,6 +41,40 @@ export class ContextMenu extends React.Component { } @action + onPointerDown = (e: PointerEvent) => { + this._mouseDown = true; + this._mouseX = e.clientX; + this._mouseY = e.clientY; + } + @action + onPointerUp = (e: PointerEvent) => { + this._mouseDown = false; + let curX = e.clientX; + let curY = e.clientY; + if (this._mouseX !== curX || this._mouseY !== curY) { + this._shouldDisplay = false; + } + + this._shouldDisplay && (this._display = true); + } + componentWillUnmount() { + document.removeEventListener("pointerdown", this.onPointerDown); + document.removeEventListener("pointerup", this.onPointerUp); + this._reactionDisposer && this._reactionDisposer(); + } + + @action + componentDidMount = () => { + document.addEventListener("pointerdown", this.onPointerDown); + document.addEventListener("pointerup", this.onPointerUp); + + this._reactionDisposer = reaction( + () => this._shouldDisplay, + () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) + ); + } + + @action clearItems() { this._items = []; } @@ -83,22 +124,21 @@ export class ContextMenu extends React.Component { } @action - displayMenu(x: number, y: number) { + displayMenu = (x: number, y: number) => { //maxX and maxY will change if the UI/font size changes, but will work for any amount //of items added to the menu this._pageX = x; this._pageY = y; - this._searchString = ""; - - this._display = true; + this._shouldDisplay = true; } @action closeMenu = () => { this.clearItems(); this._display = false; + this._shouldDisplay = false; } @computed get filteredItems(): (OriginalMenuProps | string[])[] { diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 0b7411fca..3627edaae 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -24,13 +24,13 @@ $linkGap : 3px; .documentDecorations-resizer { pointer-events: auto; background: $alt-accent; - opacity: 0.8; + opacity: 1; } .documentDecorations-radius { pointer-events: auto; background: black; - opacity: 0.8; + opacity: 1; transform: translate(10px, 10px); grid-row: 4; } @@ -92,27 +92,30 @@ $linkGap : 3px; .title { background: $alt-accent; + opacity: 1; grid-column-start: 3; grid-column-end: 4; pointer-events: auto; overflow: hidden; + text-align: center; } } .documentDecorations-closeButton { background: $alt-accent; - opacity: 0.8; + opacity: 1; grid-column-start: 4; grid-column-end: 6; pointer-events: all; text-align: center; cursor: pointer; + padding-right: 10px; } .documentDecorations-minimizeButton { background: $alt-accent; - opacity: 0.8; + opacity: 1; grid-column-start: 1; grid-column-end: 3; pointer-events: all; @@ -121,6 +124,7 @@ $linkGap : 3px; position: absolute; left: 0px; top: 0px; + padding-top: 5px; width: $MINIMIZED_ICON_SIZE; height: $MINIMIZED_ICON_SIZE; } @@ -219,6 +223,11 @@ $linkGap : 3px; margin-top: 3px; } +.documentdecorations-times { + margin-top: 3px; + padding-right: 3px; +} + .templating-button, .docDecs-tagButton { width: 20px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index df526e01c..d24762443 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faLink, faTag } from '@fortawesome/free-solid-svg-icons'; +import { faLink, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -36,6 +36,7 @@ export const Flyout = higflyout.default; library.add(faLink); library.add(faTag); +library.add(faTimes); @observer export class DocumentDecorations extends React.Component<{}, { value: string }> { @@ -65,6 +66,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @observable private _opacity = 1; @observable private _removeIcon = false; @observable public Interacting = false; + @observable private _isMoving = false; constructor(props: Readonly<{}>) { super(props); @@ -346,9 +348,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onRadiusMove); document.addEventListener("pointerup", this.onRadiusUp); } + if (!this._isMoving) { + SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). + map(d => d.borderRounding = "0%"); + } } onRadiusMove = (e: PointerEvent): void => { + this._isMoving = true; let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1])); SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). map(d => d.borderRounding = `${Math.min(100, dist)}%`); @@ -361,6 +368,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.preventDefault(); this._isPointerDown = false; this._resizeUndo && this._resizeUndo.end(); + this._isMoving = false; document.removeEventListener("pointermove", this.onRadiusMove); document.removeEventListener("pointerup", this.onRadiusUp); } @@ -743,7 +751,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> {this._edtingTitle ? <input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> : <div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>} - <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>X</div> + <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}> + <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" /> + </div> <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div> <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div> <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div> diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index d84decdfe..bc0975c86 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -140,6 +140,8 @@ button:hover { // font-size: 8px; // user-select: none; // } + margin-top: -2.55px; + margin-left: -2.55px; } // add nodes menu. Note that the + button is actually an input label, not an actual button. diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7b4f1fc52..6e240817c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -38,6 +38,7 @@ import { PreviewCursor } from './PreviewCursor'; import { FilterBox } from './search/FilterBox'; import { CollectionTreeView } from './collections/CollectionTreeView'; import { ClientUtils } from '../util/ClientUtils'; +import { SearchBox } from './search/SearchBox'; import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField'; import { DictationManager } from '../util/DictationManager'; import * as $ from 'jquery'; @@ -542,7 +543,7 @@ export class MainView extends React.Component { } @observable isSearchVisible = false; - @action + @action.bound toggleSearch = () => { // console.log("search toggling") this.isSearchVisible = !this.isSearchVisible; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index c3c1f2108..4add7774e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -29,6 +29,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef<HTMLDivElement>(); _heightDisposer?: IReactionDisposer; + _childLayoutDisposer?: IReactionDisposer; _sectionFilterDisposer?: IReactionDisposer; _docXfs: any[] = []; _columnStart: number = 0; @@ -84,19 +85,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return fields; } - childLayoutDisposer?: IReactionDisposer; componentDidMount() { - this.childLayoutDisposer = reaction(() => this.props.Document.childLayout, - async () => { - let chidlLayout = Cast(this.props.Document.childLayout, Doc); - if (chidlLayout instanceof Doc) { - const childLayout = chidlLayout; - let list = await this.childDocList; - list && list.map(async doc => { - !Doc.AreProtosEqual(childLayout, (await doc).layout as Doc) && Doc.ApplyTemplateTo(childLayout, (await doc), undefined); - }); - } - }); + this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], + async (args) => args[1] instanceof Doc && + this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined))); + // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). this._heightDisposer = reaction(() => { if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) { @@ -121,7 +114,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ); } componentWillUnmount() { - this.childLayoutDisposer && this.childLayoutDisposer(); + this._childLayoutDisposer && this._childLayoutDisposer(); this._heightDisposer && this._heightDisposer(); this._sectionFilterDisposer && this._sectionFilterDisposer(); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0501bf929..ed7d9a02e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload, faChalkboard, faBraille } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCastAsync, HeightSym, WidthSym, DocListCast, FieldResult, Field, Opt } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; @@ -192,9 +192,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } private inkKey = "ink"; + private _childLayoutDisposer?: IReactionDisposer; - constructor(props: any) { - super(props); + componentDidMount() { + this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], + async (args) => args[1] instanceof Doc && + this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined))); + } + componentWillUnmount() { + this._childLayoutDisposer && this._childLayoutDisposer(); } get parentScaling() { diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 247f7d1ea..d86aab09c 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -33,8 +33,8 @@ } .formattedTextBox-inner-rounded { - height: calc(100% - 25px); - width: calc(100% - 40px); + height: calc(90%); + width: calc(85%); position: absolute; overflow: auto; top: 15; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a304cb297..9d6c6861e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -617,7 +617,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let dh = NumCast(this.props.Document.height, 0); let sh = scrBounds.height; const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight; - this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0); + this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0)); this.dataDoc.nativeHeight = nh ? sh : undefined; } } diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 497ce96c9..b1afa3f7d 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -62,17 +62,40 @@ position:relative; width:100%; margin:0 auto; + display:flex; + align-items: center; + height:100%; + .imageBox-fadeBlocker { + width:100%; + height:100%; + background: black; + display:flex; + flex-direction: row; + align-items: center; + z-index: 1; + .imageBox-fadeaway { + object-fit: contain; + width:100%; + height:100%; + } + } } #cf img { position:absolute; left:0; + } + + .imageBox-fadeBlocker { -webkit-transition: opacity 1s ease-in-out; -moz-transition: opacity 1s ease-in-out; -o-transition: opacity 1s ease-in-out; transition: opacity 1s ease-in-out; } - - #cf img.fadeaway:hover { + .imageBox-fadeBlocker:hover { + -webkit-transition: opacity 1s ease-in-out; + -moz-transition: opacity 1s ease-in-out; + -o-transition: opacity 1s ease-in-out; + transition: opacity 1s ease-in-out; opacity:0; }
\ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 582a50637..708e00576 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -420,13 +420,13 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD width={nativeWidth} ref={this._imgRef} onError={this.onError} /> - {fadepath === srcpath ? (null) : <img id="fadeaway" className="fadeaway" + {fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker"> <img className="imageBox-fadeaway" key={"fadeaway" + this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys src={fadepath} style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }} width={nativeWidth} ref={this._imgRef} - onError={this.onError} />} + onError={this.onError} /></div>} </div> {paths.length > 1 ? this.dots(paths) : (null)} <div className="imageBox-audioBackground" diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index fcdc79220..5ed33a596 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -37,6 +37,11 @@ margin-left: 2px; margin-right: 2px } + + &.searchBox-close { + color: $light-color; + max-height: 32px; + } } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 2214ac8af..4dc409e77 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -4,6 +4,8 @@ import { observable, action, runInAction, flow, computed } from 'mobx'; import "./SearchBox.scss"; import "./FilterBox.scss"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTimes } from '@fortawesome/free-solid-svg-icons'; +import { library } from '@fortawesome/fontawesome-svg-core'; import { SetupDrag } from '../../util/DragManager'; import { Docs } from '../../documents/Documents'; import { NumCast, Cast } from '../../../new_fields/Types'; @@ -14,8 +16,12 @@ import { Id } from '../../../new_fields/FieldSymbols'; import { SearchUtil } from '../../util/SearchUtil'; import { RouteStore } from '../../../server/RouteStore'; import { FilterBox } from './FilterBox'; +import { ReadStream } from 'fs'; +import * as $ from 'jquery'; +import { MainView } from '../MainView'; import { Utils } from '../../../Utils'; +library.add(faTimes); @observer export class SearchBox extends React.Component { @@ -29,6 +35,7 @@ export class SearchBox extends React.Component { @observable private _visibleElements: JSX.Element[] = []; private resultsRef = React.createRef<HTMLDivElement>(); + public inputRef = React.createRef<HTMLInputElement>(); private _isSearch: ("search" | "placeholder" | undefined)[] = []; private _numTotalResults = -1; @@ -46,6 +53,15 @@ export class SearchBox extends React.Component { this.resultsScrolled = this.resultsScrolled.bind(this); } + componentDidMount = () => { + if (this.inputRef.current) { + this.inputRef.current.focus(); + runInAction(() => { + this._searchbarOpen = true; + }); + } + } + @action getViews = async (doc: Doc) => { const results = await SearchUtil.GetViewsOfDocument(doc); @@ -229,6 +245,7 @@ export class SearchBox extends React.Component { @action.bound closeSearch = () => { + console.log("closing search") FilterBox.Instance.closeFilter(); this.closeResults(); this._searchbarOpen = false; @@ -321,11 +338,12 @@ export class SearchBox extends React.Component { <span className="searchBox-barChild searchBox-collection" onPointerDown={SetupDrag(this.collectionRef, this.startDragCollection)} ref={this.collectionRef} title="Drag Results as Collection"> <FontAwesomeIcon icon="object-group" size="lg" /> </span> - <input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..." + <input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef} className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} style={{ width: this._searchbarOpen ? "500px" : "100px" }} /> <button className="searchBox-barChild searchBox-submit" onClick={this.submitSearch} onPointerDown={FilterBox.Instance.stopProp}>Submit</button> <button className="searchBox-barChild searchBox-filter" onClick={FilterBox.Instance.openFilter} onPointerDown={FilterBox.Instance.stopProp}>Filter</button> + <button className="searchBox-barChild searchBox-close" title={"Close Search Bar"} onPointerDown={MainView.Instance.toggleSearch}><FontAwesomeIcon icon={faTimes} size="lg" /></button> </div> <div className="searchBox-results" onScroll={this.resultsScrolled} style={{ display: this._resultsOpen ? "flex" : "none", @@ -336,5 +354,4 @@ export class SearchBox extends React.Component { </div> ); } - }
\ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index bd99a5008..d634cf57f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -7,7 +7,7 @@ import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast, BoolCast, StrCa import { listSpec } from "./Schema"; import { ObjectField } from "./ObjectField"; import { RefField, FieldId } from "./RefField"; -import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; +import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id, Copy } from "./FieldSymbols"; import { scriptingGlobal, CompileScript, Scripting } from "../client/util/Scripting"; import { List } from "./List"; import { DocumentType } from "../client/documents/Documents"; @@ -526,6 +526,7 @@ export namespace Doc { target.nativeHeight = Doc.GetProto(target).nativeHeight = undefined; target.width = templateDoc.width; target.height = templateDoc.height; + target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy](); Doc.GetProto(target).type = DocumentType.TEMPLATE; if (targetData && targetData.layout === target) { targetData.layout = temp; |