diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/DragManager.ts | 2 | ||||
-rw-r--r-- | src/client/views/DocumentButtonBar.tsx | 2 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentLinksButton.scss | 28 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentLinksButton.tsx | 15 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 10 | ||||
-rw-r--r-- | src/client/views/nodes/LinkAnchorBox.tsx | 8 | ||||
-rw-r--r-- | src/client/views/nodes/LinkDocPreview.tsx | 107 |
8 files changed, 148 insertions, 28 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 91bc51101..417ddf989 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -353,7 +353,7 @@ export namespace DragManager { const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; const rect = ele.getBoundingClientRect(); const scaleX = rect.width / ele.offsetWidth, - scaleY = rect.height / ele.offsetHeight; + scaleY = ele.offsetHeight ? rect.height / ele.offsetHeight : scaleX; elesCont.left = Math.min(rect.left, elesCont.left); elesCont.top = Math.min(rect.top, elesCont.top); elesCont.right = Math.max(rect.right, elesCont.right); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 8cd1b650e..106b7163e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -248,7 +248,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get linkButton() { const view0 = this.view0; const linkCount = view0 && DocListCast(view0.props.Document.links).length; - return !view0 || linkCount ? (null) : + return !view0 ? (null) : <div className="documentButtonBar-button"> <div title="Drag(create link) Tap(view links)" className="documentButtonBar-linkFlyout" ref={this._linkButton}> <div className={"documentButtonBar-linkButton-" + (linkCount ? "nonempty" : "empty")} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 374fd7421..4e2c067ac 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -57,6 +57,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { DocumentManager } from '../util/DocumentManager'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { LinkMenu } from './linking/LinkMenu'; +import { LinkDocPreview } from './nodes/LinkDocPreview'; @observer export class MainView extends React.Component { @@ -581,6 +582,9 @@ export class MainView extends React.Component { </GestureOverlay> <PreviewCursor /> {DocumentLinksButton.EditLink ? <LinkMenu location={DocumentLinksButton.EditLinkLoc} docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)} + {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors} + linkDoc={LinkDocPreview.LinkInfo.linkDoc} linkSrc={LinkDocPreview.LinkInfo.linkSrc} href={LinkDocPreview.LinkInfo.href} + addDocTab={LinkDocPreview.LinkInfo.addDocTab} /> : (null)} <ContextMenu /> <RadialMenu /> <PDFMenu /> diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index b4c59b91c..79364ab8e 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -1,21 +1,9 @@ @import "../globalCssVariables.scss"; -.documentLinksButton-button-empty:hover { - background: $main-accent; - transform: scale(1.05); - cursor: pointer; -} - -.documentLinksButton-button-nonempty:hover { - background: $main-accent; - transform: scale(1.05); - cursor: pointer; -} - -.documentLinksButton-button, -.documentLinksButton-button-empty, -.documentLinksButton-button-nonempty { +.documentLinksButton, +.documentLinksButton-endLink, +.documentLinksButton-startLink { height: 20px; width: 20px; left: -15px; @@ -34,18 +22,18 @@ align-items: center; &:hover { - background: $main-accent; + background: deepskyblue; transform: scale(1.05); - cursor: pointer; + cursor: default; } } -.documentLinksButton-button-nonempty { +.documentLinksButton { background-color: $link-color; } -.documentLinksButton-button-empty { +.documentLinksButton-endLink { border: red solid 2px; } -.documentLinksButton-button { +.documentLinksButton-startLink { border: red solid 2px; background-color: rgba(255, 192, 203, 0.5); }
\ No newline at end of file diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index c9083a65f..fc314ae8b 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -9,6 +9,7 @@ import { DocumentView } from "./DocumentView"; import React = require("react"); import { DocUtils } from "../../documents/Documents"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { LinkDocPreview } from "./LinkDocPreview"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -80,11 +81,19 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp const links = DocListCast(this.props.View.props.Document.links); return !links.length || links[0].hidden ? (null) : <div title="Drag(create link) Tap(view links)" ref={this._linkButton}> - <div className={"documentLinksButton-button-nonempty"} onPointerDown={this.onLinkButtonDown} > + <div className={"documentLinksButton"} style={{ backgroundColor: DocumentLinksButton.StartLink ? "transparent" : "" }} + onPointerDown={this.onLinkButtonDown} + onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} + onPointerEnter={action(e => LinkDocPreview.LinkInfo = { + addDocTab: this.props.View.props.addDocTab, + linkSrc: this.props.View.props.Document, + linkDoc: links[0], + Location: [e.clientX, e.clientY + 20] + })} > {links.length ? links.length : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />} </div> - {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-button-empty"} onPointerDown={this.completeLink} /> : (null)} - {DocumentLinksButton.StartLink === this.props.View ? <div className={"documentLinksButton-button"} /> : (null)} + {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} onPointerDown={this.completeLink} /> : (null)} + {DocumentLinksButton.StartLink === this.props.View ? <div className={"documentLinksButton-startLink"} /> : (null)} </div>; } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 20a606937..4cb08bab3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1047,7 +1047,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu onClick={this.onClickHandler} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.showLinks ? this.anchors : (null)} - {this.props.forcedBackgroundColor?.(this.Document) === "transparent" ? (null) : <DocumentLinksButton View={this} />} + {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.props.dontRegisterView ? (null) : <DocumentLinksButton View={this} />} </div> ); } @@ -1071,7 +1071,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu anchorPanelHeight = () => this.props.PanelHeight() || 1; @computed get anchors() { TraceMobx(); - return this.layoutDoc.presBox ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => + return this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.presBox || this.props.dontRegisterView ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => <DocumentView {...this.props} key={i + 1} Document={d} ContainingCollectionView={this.props.ContainingCollectionView} @@ -1079,6 +1079,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu PanelWidth={this.anchorPanelWidth} PanelHeight={this.anchorPanelHeight} ContentScaling={returnOne} + dontRegisterView={false} forcedBackgroundColor={returnTransparent} removeDocument={this.hideLinkAnchor} pointerEvents={false} @@ -1202,7 +1203,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu color: StrCast(this.layoutDoc.color, "inherit"), outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, - boxShadow: this.Document.isLinkButton ? StrCast(this.props.Document._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, + boxShadow: this.Document.isLinkButton && !this.props.dontRegisterView && this.props.forcedBackgroundColor?.(this.Document) !== "transparent" ? + StrCast(this.props.Document._linkButtonShadow, "lightblue 0em 0em 1em") : + this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : + undefined, background: finalColor, opacity: finalOpacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 2b64cdab6..2bcc6168b 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -18,6 +18,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SelectionManager } from "../../util/SelectionManager"; import { TraceMobx } from "../../../fields/util"; import { Id } from "../../../fields/FieldSymbols"; +import { LinkDocPreview } from "./LinkDocPreview"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -132,6 +133,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch ); const small = this.props.PanelWidth() <= 1; return <div className={`linkAnchorBox-cont${small ? "-small" : ""} ${this.rootDoc[Id]}`} + onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} + onPointerEnter={action(e => LinkDocPreview.LinkInfo = { + addDocTab: this.props.addDocTab, + linkSrc: this.props.ContainingCollectionDoc!, + linkDoc: this.rootDoc, + Location: [e.clientX, e.clientY + 20] + })} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu} ref={this._ref} style={{ background: c, diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx new file mode 100644 index 000000000..126dc240a --- /dev/null +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -0,0 +1,107 @@ +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from "mobx-react"; +import wiki from "wikijs"; +import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { Cast, FieldValue, NumCast } from "../../../fields/Types"; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils"; +import { Docs } from "../../documents/Documents"; +import { DocumentManager } from "../../util/DocumentManager"; +import { Transform } from "../../util/Transform"; +import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; +import React = require("react"); +import { DocumentView } from './DocumentView'; + +interface Props { + linkDoc?: Doc; + linkSrc?: Doc; + href?: string; + backgroundColor: (doc: Doc) => string; + addDocTab: (document: Doc, where: string) => boolean; + location: number[]; +} +@observer +export class LinkDocPreview extends React.Component<Props> { + @observable public static LinkInfo: Opt<{ linkDoc?: Doc; addDocTab: (document: Doc, where: string) => boolean, linkSrc: Doc; href?: string; Location: number[] }>; + @observable _targetDoc: Opt<Doc>; + @observable _toolTipText = ""; + + componentDidUpdate() { this.updatePreview() } + componentDidMount() { this.updatePreview() } + async updatePreview() { + const linkDoc = this.props.linkDoc; + const linkSrc = this.props.linkSrc; + if (this.props.href) { + if (this.props.href.startsWith("https://en.wikipedia.org/wiki/")) { + wiki().page(this.props.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500)))); + } else { + runInAction(() => this._toolTipText = "external => " + this.props.href); + } + } else if (linkDoc && linkSrc) { + const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), linkSrc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); + const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; + runInAction(() => { + this._toolTipText = ""; + this._targetDoc = target; + if (anchor !== this._targetDoc && anchor && this._targetDoc) { + this._targetDoc._scrollY = NumCast(anchor?.y); + } + }); + } + } + pointerDown = (e: React.PointerEvent) => { + if (this.props.linkDoc && this.props.linkSrc) { + DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.linkSrc, + (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } else if (this.props.href) { + this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, UseCors: true }), "onRight"); + } + } + width = () => Math.min(350, NumCast(this._targetDoc?.[WidthSym](), 350)); + height = () => Math.min(350, NumCast(this._targetDoc?.[HeightSym](), 350)); + @computed get targetDocView() { + return !this._targetDoc ? + <div style={{ pointerEvents: "all", maxWidth: 350, maxHeight: 250, width: "100%", height: "100%", overflow: "hidden" }}> + <div style={{ width: "100%", height: "100%", textOverflow: "ellipsis", }} onPointerDown={this.pointerDown}> + {this._toolTipText} + </div> + </div> : + <ContentFittingDocumentView + Document={this._targetDoc} + LibraryPath={emptyPath} + fitToBox={true} + backgroundColor={this.props.backgroundColor} + moveDocument={returnFalse} + rootSelected={returnFalse} + ScreenToLocalTransform={Transform.Identity} + parentActive={returnFalse} + addDocument={returnFalse} + removeDocument={returnFalse} + addDocTab={returnFalse} + pinToPres={returnFalse} + dontRegisterView={true} + docFilters={returnEmptyFilter} + ContainingCollectionDoc={undefined} + ContainingCollectionView={undefined} + renderDepth={0} + PanelWidth={this.width} + PanelHeight={this.height} + focus={emptyFunction} + whenActiveChanged={returnFalse} + bringToFront={returnFalse} + ContentScaling={returnOne} + NativeWidth={returnZero} + NativeHeight={returnZero} + />; + } + + render() { + return <div className="linkDocPreview" + style={{ + position: "absolute", left: this.props.location[0], + top: this.props.location[1], width: this.width(), height: this.height(), + boxShadow: "black 2px 2px 1em" + }}> + {this.targetDocView} + </div>; + } +}
\ No newline at end of file |