diff options
Diffstat (limited to 'src/client/views/linking')
| -rw-r--r-- | src/client/views/linking/LinkEditor.scss | 18 | ||||
| -rw-r--r-- | src/client/views/linking/LinkEditor.tsx | 30 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenu.scss | 9 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenu.tsx | 28 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuGroup.tsx | 13 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuItem.scss | 14 | ||||
| -rw-r--r-- | src/client/views/linking/LinkMenuItem.tsx | 21 | ||||
| -rw-r--r-- | src/client/views/linking/LinkPopup.tsx | 3 |
8 files changed, 100 insertions, 36 deletions
diff --git a/src/client/views/linking/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss index abd413f57..1d6496d3c 100644 --- a/src/client/views/linking/LinkEditor.scss +++ b/src/client/views/linking/LinkEditor.scss @@ -60,6 +60,24 @@ } } +.linkEditor-zoomFollow { + padding-left: 26px; + padding-right: 6.5px; + padding-bottom: 3.5px; + display: flex; + + .linkEditor-zoomFollow-label { + text-decoration-color: black; + color: black; + line-height: 1.7; + } + + .linkEditor-zoomFollow-input { + display: block; + width: 20px; + } +} + .linkEditor-description { padding-left: 26px; padding-right: 6.5px; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index db331bb75..1414bfdf7 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -9,7 +9,6 @@ import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import { LinkRelationshipSearch } from "./LinkRelationshipSearch"; import React = require("react"); -import { ToString } from "../../../fields/FieldSymbols"; interface LinkEditorProps { @@ -23,6 +22,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { @observable description = Field.toString(LinkManager.currentLink?.description as any as Field); @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship); + @observable zoomFollow = StrCast(this.props.sourceDoc.followLinkZoom); @observable openDropdown: boolean = false; @observable showInfo: boolean = false; @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; } @@ -114,6 +114,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { this.setDescripValue(this.description); document.getElementById('input')?.blur(); } + e.stopPropagation(); } onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => { @@ -121,6 +122,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { this.setRelationshipValue(this.relationship); document.getElementById('input')?.blur(); } + e.stopPropagation(); } onDescriptionDown = () => this.setDescripValue(this.description); @@ -143,9 +145,9 @@ export class LinkEditor extends React.Component<LinkEditorProps> { @action handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; } @action - handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { - this.relationship = e.target.value; - } + handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; } + @action + handleZoomFollowChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.props.sourceDoc.followLinkZoom = e.target.checked; } @action handleRelationshipSearchChange = (result: string) => { this.setRelationshipValue(result); @@ -183,6 +185,22 @@ export class LinkEditor extends React.Component<LinkEditorProps> { </div> </div>; } + @computed + get editZoomFollow() { + //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS + return <div className="linkEditor-zoomFollow"> + <div className="linkEditor-zoomFollow-label">Zoom To Link Target:</div> + <div className="linkEditor-zoomFollow-input"> + <div className="linkEditor-zoomFollow-editing"> + <input + style={{ width: "100%" }} + type="checkbox" + value={this.zoomFollow} + onChange={this.handleZoomFollowChange} /> + </div> + </div> + </div >; + } @computed get editDescription() { @@ -279,9 +297,8 @@ export class LinkEditor extends React.Component<LinkEditorProps> { render() { const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc); - return !destination ? (null) : ( - <div className="linkEditor"> + <div className="linkEditor" tabIndex={0} onKeyDown={e => e.stopPropagation()}> <div className="linkEditor-info"> <Tooltip title={<><div className="dash-tooltip">Return to link menu</div></>} placement="top"> <button className="linkEditor-button-back" @@ -303,6 +320,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { {this.editDescription} {this.editRelationship} + {this.editZoomFollow} {this.followingDropdown} </div> diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index 19c6463d3..77c16a28f 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -45,8 +45,11 @@ } .linkMenu-group-name { - padding: 10px; - + padding: 1px; + padding-left: 5px; + font-size: 10px; + font-style: italic; + font-weight: bold; &:hover { // p { @@ -64,7 +67,7 @@ p { width: 100%; - line-height: 12px; + line-height: 1; border-radius: 5px; text-transform: capitalize; } diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 53fe3f682..17d28e886 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -2,8 +2,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../fields/Doc"; import { LinkManager } from "../../util/LinkManager"; -import { DocumentLinksButton } from "../nodes/DocumentLinksButton"; -import { DocumentView, DocumentViewSharedProps } from "../nodes/DocumentView"; +import { DocumentView } from "../nodes/DocumentView"; import { LinkDocPreview } from "../nodes/LinkDocPreview"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; @@ -12,7 +11,9 @@ import React = require("react"); interface Props { docView: DocumentView; - changeFlyout: () => void; + position?: { x?: number, y?: number }; + itemHandler?: (doc: Doc) => void; + clearLinkEditor: () => void; } /** @@ -20,24 +21,29 @@ interface Props { */ @observer export class LinkMenu extends React.Component<Props> { - private _editorRef = React.createRef<HTMLDivElement>(); + _editorRef = React.createRef<HTMLDivElement>(); @observable _editingLink?: Doc; @observable _linkMenuRef = React.createRef<HTMLDivElement>(); @computed get position() { - return ((dv) => ({ x: dv?.left || 0, y: dv?.top || 0, r: dv?.right || 0, b: dv?.bottom || 0 }))(this.props.docView.getBounds()); + return this.props.position ?? (dv => ({ x: dv?.left || 0, y: (dv?.bottom || 0) + 15 }))(this.props.docView.getBounds()); } + clear = action(() => { + this.props.clearLinkEditor(); + this._editingLink = undefined; + }); + componentDidMount() { document.addEventListener("pointerdown", this.onPointerDown); } componentWillUnmount() { document.removeEventListener("pointerdown", this.onPointerDown); } - onPointerDown = (e: PointerEvent) => { + onPointerDown = action((e: PointerEvent) => { LinkDocPreview.Clear(); if (!this._linkMenuRef.current?.contains(e.target as any) && !this._editorRef.current?.contains(e.target as any)) { - DocumentLinksButton.ClearLinkEditor(); + this.clear(); } - } + }); /** * maps each link to a JSX element to be rendered @@ -48,19 +54,21 @@ export class LinkMenu extends React.Component<Props> { const linkItems = Array.from(groups.entries()).map(group => <LinkMenuGroup key={group[0]} + itemHandler={this.props.itemHandler} docView={this.props.docView} sourceDoc={this.props.docView.props.Document} group={group[1]} groupType={group[0]} + clearLinkEditor={this.clear} showEditor={action(linkDoc => this._editingLink = linkDoc)} />); - return linkItems.length ? linkItems : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>]; + return linkItems.length ? linkItems : this.props.position ? [<></>] : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>]; } render() { const sourceDoc = this.props.docView.props.Document; return <div className="linkMenu" ref={this._linkMenuRef} - style={{ left: this.position.x, top: this.props.docView.topMost ? undefined : this.position.b + 15, bottom: this.props.docView.topMost ? 20 : undefined }} + style={{ left: this.position.x, top: this.props.docView.topMost ? undefined : this.position.y, bottom: this.props.docView.topMost ? 20 : undefined }} > {this._editingLink ? <div className="linkMenu-listEditor"> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 03377ad4e..fa6a2f506 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -1,4 +1,5 @@ import { observer } from "mobx-react"; +import { observable, action } from "mobx"; import { Doc, StrListCast } from "../../../fields/Doc"; import { Id } from "../../../fields/FieldSymbols"; import { Cast } from "../../../fields/Types"; @@ -12,8 +13,10 @@ interface LinkMenuGroupProps { sourceDoc: Doc; group: Doc[]; groupType: string; + clearLinkEditor: () => void; showEditor: (linkDoc: Doc) => void; docView: DocumentView; + itemHandler?: (doc: Doc) => void; } @observer @@ -36,6 +39,8 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { return color; } + @observable _collapsed = false; + render() { const set = new Set<Doc>(this.props.group); const groupItems = Array.from(set.keys()).map(linkDoc => { @@ -43,11 +48,13 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null)); if (destination && this.props.sourceDoc) { return <LinkMenuItem key={linkDoc[Id]} + itemHandler={this.props.itemHandler} groupType={this.props.groupType} docView={this.props.docView} linkDoc={linkDoc} sourceDoc={this.props.sourceDoc} destinationDoc={destination} + clearLinkEditor={this.props.clearLinkEditor} showEditor={this.props.showEditor} menuRef={this._menuRef} />; } @@ -55,12 +62,12 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { return ( <div className="linkMenu-group" ref={this._menuRef}> - <div className="linkMenu-group-name" style={{ background: this.getBackgroundColor() }}> + <div className="linkMenu-group-name" onClick={action(() => this._collapsed = !this._collapsed)} style={{ background: this.getBackgroundColor() }}> <p className={this.props.groupType === "*" || this.props.groupType === "" ? "" : "expand-one"}> {this.props.groupType}:</p> </div> - <div className="linkMenu-group-wrapper"> + {this._collapsed ? (null) : <div className="linkMenu-group-wrapper"> {groupItems} - </div> + </div>} </div > ); } diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index 90722daf9..8333aa374 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -9,8 +9,8 @@ padding-left: 6.5px; padding-right: 2px; - padding-top: 6.5px; - padding-bottom: 6.5px; + padding-top: 1px; + padding-bottom: 1px; background-color: white; @@ -18,10 +18,12 @@ .linkMenu-name { position: relative; width: auto; + align-items: center; + display: flex; .linkMenu-text { - padding: 4px 2px; + // padding: 4px 2px; //display: inline; .linkMenu-source-title { @@ -37,6 +39,8 @@ .linkMenu-title-wrapper { display: flex; + align-items: center; + min-height: 20px; .destination-icon-wrapper { //border: 0.5px solid rgb(161, 161, 161); @@ -56,7 +60,8 @@ .linkMenu-destination-title { text-decoration: none; color: #4476F7; - font-size: 16px; + font-size: 13px; + line-height: 0.9; padding-bottom: 2px; padding-right: 4px; margin-right: 4px; @@ -77,6 +82,7 @@ font-style: italic; color: rgb(95, 97, 102); font-size: 9px; + line-height: 0.9; margin-left: 20px; max-width: 125px; height: auto; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 96cc6d600..3ddcf803d 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,24 +1,22 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, observable, runInAction } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import { Doc, DocListCast } from '../../../fields/Doc'; import { Cast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; -import { emptyFunction, setupMoveUpEvents, returnFalse } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { Hypothesis } from '../../util/HypothesisUtils'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; -import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewSharedProps } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require("react"); -import { setup } from 'mocha'; interface LinkMenuItemProps { @@ -27,8 +25,10 @@ interface LinkMenuItemProps { docView: DocumentView; sourceDoc: Doc; destinationDoc: Doc; + clearLinkEditor: () => void; showEditor: (linkDoc: Doc) => void; menuRef: React.Ref<HTMLDivElement>; + itemHandler?: (doc: Doc) => void; } // drag links and drop link targets (aliasing them if needed) @@ -92,13 +92,18 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { const eleClone: any = this._drag.current!.cloneNode(true); eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`; StartLinkTargetsDrag(eleClone, this.props.docView, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]); - DocumentLinksButton.ClearLinkEditor(); + this.props.clearLinkEditor(); return true; }, emptyFunction, () => { - DocumentLinksButton.ClearLinkEditor(); - LinkManager.FollowLink(this.props.linkDoc, this.props.sourceDoc, this.props.docView.props, false); + this.props.clearLinkEditor(); + if (this.props.itemHandler) { + + this.props.itemHandler?.(this.props.linkDoc); + } else { + LinkManager.FollowLink(this.props.linkDoc, this.props.sourceDoc, this.props.docView.props, false); + } }); } diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index c8be9069c..4b33ef8ae 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -67,7 +67,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> { <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input" className="linkPopup-searchBox searchBox-input" /> */} - <SearchBox + <SearchBox Document={CurrentUserUtils.MySearchPanelDoc} DataDoc={CurrentUserUtils.MySearchPanelDoc} linkFrom={linkDoc} @@ -83,7 +83,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> { pinToPres={emptyFunction} rootSelected={returnTrue} styleProvider={DefaultStyleProvider} - layerProvider={undefined} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} PanelWidth={this.getPWidth} |
