aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/linking
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2020-07-16 13:06:55 +0530
committerusodhi <61431818+usodhi@users.noreply.github.com>2020-07-16 13:06:55 +0530
commitf6cfb6f68fdf6e987b867b9ece37b53845ff426e (patch)
tree9e2ccba4aa319b13e353ee86b2b369c8578879f2 /src/client/views/linking
parentb442fc347abc267697575c517949ca0ee0dad2f1 (diff)
parent21284a84b6d9930b5ddfddaa600b6916613748c4 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into grid_view_secondary
Diffstat (limited to 'src/client/views/linking')
-rw-r--r--src/client/views/linking/LinkEditor.scss170
-rw-r--r--src/client/views/linking/LinkEditor.tsx152
-rw-r--r--src/client/views/linking/LinkMenu.scss72
-rw-r--r--src/client/views/linking/LinkMenu.tsx42
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx12
-rw-r--r--src/client/views/linking/LinkMenuItem.scss111
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx101
7 files changed, 585 insertions, 75 deletions
diff --git a/src/client/views/linking/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss
index b47c8976e..d26b7920a 100644
--- a/src/client/views/linking/LinkEditor.scss
+++ b/src/client/views/linking/LinkEditor.scss
@@ -3,38 +3,188 @@
.linkEditor {
width: 100%;
height: auto;
- font-size: 12px; // TODO
+ font-size: 13px; // TODO
user-select: none;
}
-.linkEditor-back {
- margin-bottom: 6px;
+.linkEditor-button-back {
+ //margin-bottom: 6px;
+ border-radius: 10px;
+ width: 18px;
+ height: 18px;
+ padding: 0;
+
+ &:hover {
+ cursor: pointer;
+ }
}
.linkEditor-info {
- border-bottom: 0.5px solid $light-color-secondary;
- padding-bottom: 6px;
- margin-bottom: 6px;
+ //border-bottom: 0.5px solid $light-color-secondary;
+ //padding-bottom: 1px;
+ padding-top: 5px;
+ padding-left: 5px;
+ //margin-bottom: 6px;
display: flex;
justify-content: space-between;
+ color: black;
.linkEditor-linkedTo {
width: calc(100% - 26px);
+ padding-left: 5px;
+ padding-right: 5px;
+
+ .linkEditor-downArrow {
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ }
+}
+
+.linkEditor-moreInfo {
+ margin-left: 12px;
+ padding-left: 13px;
+ padding-right: 6.5px;
+ padding-bottom: 4px;
+ font-size: 9px;
+ //font-style: italic;
+ text-decoration-color: grey;
+
+ .button {
+ color: black;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+}
+
+.linkEditor-description {
+ padding-left: 6.5px;
+ padding-right: 6.5px;
+ padding-bottom: 3.5px;
+
+ .linkEditor-description-label {
+ text-decoration-color: black;
+ color: black;
+ }
+
+ .linkEditor-description-input {
+ display: flex;
+
+ .linkEditor-description-editing {
+ min-width: 85%;
+ //border: 1px solid grey;
+ //border-radius: 4px;
+ padding-left: 2px;
+ padding-right: 2px;
+ //margin-right: 4px;
+ color: black;
+ text-decoration-color: grey;
+ }
+
+ .linkEditor-description-add-button {
+ display: inline;
+ /* float: right; */
+ border-radius: 7px;
+ font-size: 9px;
+ background-color: black;
+ /* padding: 3px; */
+ padding-top: 4px;
+ padding-left: 7px;
+ padding-bottom: 4px;
+ padding-right: 8px;
+ height: 80%;
+ color: white;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
}
}
-.linkEditor-button, .linkEditor-addbutton {
+.linkEditor-followingDropdown {
+ padding-left: 6.5px;
+ padding-right: 6.5px;
+ padding-bottom: 6px;
+
+ &:hover {
+ cursor: pointer;
+ }
+
+ .linkEditor-followingDropdown-label {
+ color: black;
+ }
+
+ .linkEditor-followingDropdown-dropdown {
+
+ .linkEditor-followingDropdown-header {
+
+ border: 1px solid grey;
+ border-radius: 4px;
+ //background-color: rgb(236, 236, 236);
+ padding-left: 2px;
+ padding-right: 2px;
+ text-decoration-color: black;
+ color: rgb(94, 94, 94);
+
+ .linkEditor-followingDropdown-icon {
+ float: right;
+ color: black;
+ }
+ }
+
+ .linkEditor-followingDropdown-optionsList {
+ padding-left: 3px;
+ padding-right: 3px;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ .linkEditor-followingDropdown-option {
+ border: 0.25px solid grey;
+ //background-color: rgb(236, 236, 236);
+ padding-left: 2px;
+ padding-right: 2px;
+ color: grey;
+ text-decoration-color: grey;
+ font-size: 9px;
+ border-top: none;
+
+ &:hover {
+ background-color: rgb(187, 220, 231);
+ }
+ }
+
+ }
+ }
+
+
+}
+
+
+
+
+
+
+.linkEditor-button,
+.linkEditor-addbutton {
width: 18px;
height: 18px;
padding: 0;
// font-size: 12px;
border-radius: 10px;
+
&:disabled {
background-color: gray;
}
}
-.linkEditor-addbutton{
+
+.linkEditor-addbutton {
margin-left: 0px;
}
@@ -44,7 +194,7 @@
}
.linkEditor-group {
- background-color: $light-color-secondary;
+ background-color: $light-color-secondary;
padding: 6px;
margin: 3px 0;
border-radius: 3px;
@@ -56,7 +206,7 @@
.linkEditor-group-row-label {
margin-right: 6px;
- display:inline-block;
+ display: inline-block;
}
.linkEditor-metadata-row {
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 13b9a2459..ed2bea722 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -1,14 +1,19 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faArrowLeft, faCog, faEllipsisV, faExchangeAlt, faPlus, faTable, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable } from "mobx";
+import { action, observable, computed, toJS } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../fields/Doc";
-import { StrCast } from "../../../fields/Types";
+import { Doc, Opt } from "../../../fields/Doc";
+import { StrCast, DateCast } from "../../../fields/Types";
import { Utils } from "../../../Utils";
import { LinkManager } from "../../util/LinkManager";
import './LinkEditor.scss';
import React = require("react");
+import { DocumentView } from "../nodes/DocumentView";
+import { DocumentLinksButton } from "../nodes/DocumentLinksButton";
+import { EditableView } from "../EditableView";
+import { RefObject } from "react";
+import { Tooltip } from "@material-ui/core";
library.add(faArrowLeft, faEllipsisV, faTable, faTrash, faCog, faExchangeAlt, faTimes, faPlus);
@@ -281,27 +286,158 @@ interface LinkEditorProps {
@observer
export class LinkEditor extends React.Component<LinkEditorProps> {
+ @observable description = StrCast(LinkManager.currentLink?.description);
+ @observable openDropdown: boolean = false;
+ @observable showInfo: boolean = false;
+ @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; }
+ @observable private buttonColor: string = "black";
+
+
+ //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
+
@action
deleteLink = (): void => {
LinkManager.Instance.deleteLink(this.props.linkDoc);
this.props.showLinks();
}
+ @action
+ setDescripValue = (value: string) => {
+ if (LinkManager.currentLink) {
+ LinkManager.currentLink.description = value;
+ this.buttonColor = "rgb(62, 133, 55)";
+ setTimeout(action(() => {
+ this.buttonColor = "black";
+ }), 750);
+ return true;
+ }
+ }
+
+ @action
+ onKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ if (e.key === "Enter") {
+ this.setDescripValue(this.description);
+ document.getElementById('input')?.blur();
+ }
+ }
+
+ @action
+ onDown = () => {
+ this.setDescripValue(this.description);
+ }
+
+ @action
+ handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this.description = e.target.value;
+ }
+
+
+ @computed
+ get editDescription() {
+ return <div className="linkEditor-description">
+ <div className="linkEditor-description-label">
+ Link Label:</div>
+ <div className="linkEditor-description-input">
+ <div className="linkEditor-description-editing">
+ <input
+ style={{ width: "100%" }}
+ id="input"
+ value={this.description}
+ placeholder={"enter link label"}
+ // color={"rgb(88, 88, 88)"}
+ onKeyDown={this.onKey}
+ onChange={this.handleChange}
+ ></input>
+ </div>
+ <div className="linkEditor-description-add-button"
+ style={{ backgroundColor: this.buttonColor }}
+ onPointerDown={this.onDown}>Set</div>
+ </div></div>;
+ }
+
+ @action
+ changeDropdown = () => {
+ this.openDropdown = !this.openDropdown;
+ }
+
+ @action
+ changeFollowBehavior = (follow: string) => {
+ this.openDropdown = false;
+ Doc.GetProto(this.props.linkDoc).followLinkLocation = follow;
+ }
+
+ @computed
+ get followingDropdown() {
+ return <div className="linkEditor-followingDropdown">
+ <div className="linkEditor-followingDropdown-label">
+ Follow Behavior:</div>
+ <div className="linkEditor-followingDropdown-dropdown">
+ <div className="linkEditor-followingDropdown-header"
+ onPointerDown={this.changeDropdown}>
+ {StrCast(this.props.linkDoc.followLinkLocation, "Default")}
+ <FontAwesomeIcon className="linkEditor-followingDropdown-icon"
+ icon={this.openDropdown ? "chevron-up" : "chevron-down"}
+ size={"lg"} />
+ </div>
+ <div className="linkEditor-followingDropdown-optionsList"
+ style={{ display: this.openDropdown ? "" : "none" }}>
+ <div className="linkEditor-followingDropdown-option"
+ onPointerDown={() => this.changeFollowBehavior("Default")}>
+ Default
+ </div>
+ <div className="linkEditor-followingDropdown-option"
+ onPointerDown={() => this.changeFollowBehavior("onRight")}>
+ Always open in right tab
+ </div>
+ <div className="linkEditor-followingDropdown-option"
+ onPointerDown={() => this.changeFollowBehavior("inTab")}>
+ Always open in new tab
+ </div>
+ </div>
+ </div>
+ </div>;
+ }
+
+ @action
+ changeInfo = () => {
+ this.showInfo = !this.showInfo;
+ }
+
render() {
const destination = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
const groups = [this.props.linkDoc].map(groupDoc => {
- return <LinkGroupEditor key={"gred-" + StrCast(groupDoc.linkRelationship)} linkDoc={this.props.linkDoc} sourceDoc={this.props.sourceDoc} groupDoc={groupDoc} />;
+ return <LinkGroupEditor key={"gred-" + StrCast(groupDoc.linkRelationship)} linkDoc={this.props.linkDoc}
+ sourceDoc={this.props.sourceDoc} groupDoc={groupDoc} />;
});
return !destination ? (null) : (
<div className="linkEditor">
- {this.props.hideback ? (null) : <button className="linkEditor-back" onPointerDown={() => this.props.showLinks()}><FontAwesomeIcon icon="arrow-left" size="sm" /></button>}
<div className="linkEditor-info">
- <p className="linkEditor-linkedTo">editing link to: <b>{destination.proto?.title ?? destination.title ?? "untitled"}</b></p>
- <button className="linkEditor-button" onPointerDown={() => this.deleteLink()} title="Delete link"><FontAwesomeIcon icon="trash" size="sm" /></button>
+ <Tooltip title={<><div className="dash-tooltip">Return to link menu</div></>} placement="top">
+ <button className="linkEditor-button-back"
+ style={{ display: this.props.hideback ? "none" : "" }}
+ onClick={this.props.showLinks}>
+ <FontAwesomeIcon icon="arrow-left" size="sm" /> </button>
+ </Tooltip>
+ <p className="linkEditor-linkedTo">Editing Link to: <b>{
+ destination.proto?.title ?? destination.title ?? "untitled"}</b></p>
+ {/* <button className="linkEditor-button" onPointerDown={() => this.deleteLink()} title="Delete link">
+ <FontAwesomeIcon icon="trash" size="sm" /></button> */}
+ <Tooltip title={<><div className="dash-tooltip">Show more link information</div></>} placement="top">
+ <div className="linkEditor-downArrow"><FontAwesomeIcon className="button" icon={this.infoIcon} size="lg" onPointerDown={this.changeInfo} /></div>
+ </Tooltip>
</div>
- {groups.length > 0 ? groups : <div className="linkEditor-group">There are currently no relationships associated with this link.</div>}
+ {this.showInfo ? <div className="linkEditor-moreInfo">
+ <div>{this.props.linkDoc.author ? <div> <b>Author:</b> {this.props.linkDoc.author}</div> : null}</div>
+ <div>{this.props.linkDoc.creationDate ? <div> <b>Creation Date:</b>
+ {DateCast(this.props.linkDoc.creationDate).toString()}</div> : null}</div>
+ </div> : null}
+
+ <div>{this.editDescription}</div>
+ <div>{this.followingDropdown}</div>
+
+ {/* {groups.length > 0 ? groups : <div className="linkEditor-group">There are currently no relationships associated with this link.</div>} */}
</div>
);
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss
index 6468ccd3d..98e4171f0 100644
--- a/src/client/views/linking/LinkMenu.scss
+++ b/src/client/views/linking/LinkMenu.scss
@@ -1,22 +1,67 @@
@import "../globalCssVariables";
.linkMenu {
- width: 100%;
+ width: auto;
height: auto;
-}
-
-.linkMenu-list {
- max-height: 200px;
- overflow-y: scroll;
position: absolute;
- z-index: 10;
- background: $link-color;
- min-width: 150px
+ top: 0;
+ left: 0;
+
+ .linkMenu-list {
+
+ display: inline-block;
+
+ border: 1px solid black;
+
+ box-shadow: 3px 3px 1.5px grey;
+
+ max-height: 170px;
+ overflow-y: scroll;
+ position: relative;
+ z-index: 10;
+ background: white;
+ min-width: 170px;
+ //border-radius: 5px;
+ //padding-top: 6.5px;
+ //padding-bottom: 6.5px;
+ //padding-left: 6.5px;
+ //padding-right: 2px;
+ //width: calc(auto + 50px);
+
+ white-space: nowrap;
+ overflow-x: hidden;
+ width: 240px;
+ scrollbar-color: white;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ &:hover {
+ scrollbar-color: rgb(201, 239, 252);
+ }
+ }
+
+ .linkMenu-listEditor {
+
+ display: inline-block;
+
+ border: 1px solid black;
+
+ box-shadow: 3px 3px 1.5px grey;
+
+ max-height: 170px;
+ overflow-y: scroll;
+ position: relative;
+ z-index: 10;
+ background: white;
+ min-width: 170px;
+ }
}
.linkMenu-group {
border-bottom: 0.5px solid lightgray;
- padding: 5px 0;
+ //@extend: 5px 0;
&:last-child {
@@ -24,15 +69,16 @@
}
.linkMenu-group-name {
- display: flex;
+
&:hover {
p {
background-color: lightgray;
+
}
p.expand-one {
- width: calc(100% - 26px);
+ width: calc(100% + 20px);
}
.linkEditor-tableButton {
@@ -42,7 +88,7 @@
p {
width: 100%;
- padding: 4px 6px;
+ //padding: 4px 6px;
line-height: 12px;
border-radius: 5px;
font-weight: bold;
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index c672511ac..2d151e9bc 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -1,4 +1,4 @@
-import { action, observable } from "mobx";
+import { action, observable, computed } from "mobx";
import { observer } from "mobx-react";
import { DocumentView } from "../nodes/DocumentView";
import { LinkEditor } from "./LinkEditor";
@@ -11,6 +11,7 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { library } from "@fortawesome/fontawesome-svg-core";
import { DocumentLinksButton } from "../nodes/DocumentLinksButton";
import { LinkDocPreview } from "../nodes/LinkDocPreview";
+import { isUndefined } from "util";
library.add(faTrash);
@@ -25,19 +26,29 @@ interface Props {
export class LinkMenu extends React.Component<Props> {
@observable private _editingLink?: Doc;
- @observable private _linkMenuRef: Opt<HTMLDivElement | null>;
+ @observable private _linkMenuRef = React.createRef<HTMLDivElement>();
+ private _editorRef = React.createRef<HTMLDivElement>();
+
+ //@observable private _numLinks: number = 0;
+
+ // @computed get overflow() {
+ // if (this._numLinks) {
+ // return "scroll";
+ // }
+ // return "auto";
+ // }
@action
onClick = (e: PointerEvent) => {
LinkDocPreview.LinkInfo = undefined;
- if (this._linkMenuRef?.contains(e.target as any)) {
- DocumentLinksButton.EditLink = undefined;
- }
- if (this._linkMenuRef && !this._linkMenuRef.contains(e.target as any)) {
- DocumentLinksButton.EditLink = undefined;
+ if (this._linkMenuRef && !this._linkMenuRef.current?.contains(e.target as any)) {
+ if (this._editorRef && !this._editorRef.current?.contains(e.target as any)) {
+ console.log("outside click");
+ DocumentLinksButton.EditLink = undefined;
+ }
}
}
@action
@@ -78,12 +89,19 @@ export class LinkMenu extends React.Component<Props> {
render() {
const sourceDoc = this.props.docView.props.Document;
const groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc);
- return <div className="linkMenu-list"
- ref={(r) => this._linkMenuRef = r} style={{ left: this.props.location[0], top: this.props.location[1] }}>
- {!this._editingLink ?
- this.renderAllGroups(groups) :
- <LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)} />
+ return <div className="linkMenu" ref={this._linkMenuRef} >
+ {!this._editingLink ? <div className="linkMenu-list" style={{
+ left: this.props.location[0], top: this.props.location[1]
+ }}>
+ {this.renderAllGroups(groups)}
+ </div> : <div className="linkMenu-listEditor" style={{
+ left: this.props.location[0], top: this.props.location[1]
+ }}>
+ <LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink}
+ showLinks={action(() => this._editingLink = undefined)} />
+ </div>
}
+
</div>;
}
} \ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 7892d381b..2ae87ac13 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -11,6 +11,7 @@ import { DocumentView } from "../nodes/DocumentView";
import './LinkMenu.scss';
import { LinkMenuItem, StartLinkTargetsDrag } from "./LinkMenuItem";
import React = require("react");
+import { Cast } from "../../../fields/Types";
interface LinkMenuGroupProps {
sourceDoc: Doc;
@@ -26,6 +27,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
private _drag = React.createRef<HTMLDivElement>();
private _table = React.createRef<HTMLDivElement>();
+ private _menuRef = React.createRef<HTMLDivElement>();
onLinkButtonDown = (e: React.PointerEvent): void => {
e.stopPropagation();
@@ -65,7 +67,8 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
render() {
const groupItems = this.props.group.map(linkDoc => {
- const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
+ const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc) ||
+ LinkManager.Instance.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={destination[Id] + this.props.sourceDoc[Id]}
groupType={this.props.groupType}
@@ -74,17 +77,20 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
linkDoc={linkDoc}
sourceDoc={this.props.sourceDoc}
destinationDoc={destination}
- showEditor={this.props.showEditor} />;
+ showEditor={this.props.showEditor}
+ menuRef={this._menuRef} />;
}
});
return (
- <div className="linkMenu-group">
+ <div className="linkMenu-group" ref={this._menuRef}>
+
{/* <div className="linkMenu-group-name">
<p ref={this._drag} onPointerDown={this.onLinkButtonDown}
className={this.props.groupType === "*" || this.props.groupType === "" ? "" : "expand-one"} > {this.props.groupType}:</p>
{this.props.groupType === "*" || this.props.groupType === "" ? <></> : this.viewGroupAsTable(this.props.groupType)}
</div> */}
+
<div className="linkMenu-group-wrapper">
{groupItems}
</div>
diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss
index e3ce69cd7..4e13ef8c8 100644
--- a/src/client/views/linking/LinkMenuItem.scss
+++ b/src/client/views/linking/LinkMenuItem.scss
@@ -4,19 +4,95 @@
// border-top: 0.5px solid $main-accent;
position: relative;
display: flex;
- font-size: 12px;
+ border-bottom: 0.5px solid black;
+
+ padding-left: 6.5px;
+ padding-right: 2px;
+
+ padding-top: 6.5px;
+ padding-bottom: 6.5px;
+
+ background-color: white;
.linkMenu-name {
position: relative;
+ width: auto;
+
+ .linkMenu-text {
+
+ padding: 4px 2px;
+ //display: inline;
+
+ .linkMenu-source-title {
+ text-decoration: none;
+ color: rgb(43, 43, 43);
+ font-size: 7px;
+ padding-bottom: 0.75px;
+
+ margin-left: 20px;
+ }
+
+
+ .linkMenu-title-wrapper {
+
+ display: flex;
+
+ .destination-icon-wrapper {
+ //border: 0.5px solid rgb(161, 161, 161);
+ margin-right: 2px;
+ padding-right: 2px;
+
+ .destination-icon {
+ float: left;
+ width: 12px;
+ height: 12px;
+ padding: 1px;
+ margin-right: 3px;
+ color: rgb(161, 161, 161);
+ }
+ }
+
+ .linkMenu-destination-title {
+ text-decoration: none;
+ color: rgb(85, 120, 196);
+ font-size: 14px;
+ padding-bottom: 2px;
+ padding-right: 4px;
+ margin-right: 4px;
+ float: right;
+
+ &:hover {
+ text-decoration: underline;
+ color: rgb(60, 90, 156);
+ //display: inline;
+ text-overflow: break;
+ cursor: pointer;
+ }
+ }
+ }
+
+ .linkMenu-description {
+ text-decoration: none;
+ font-style: italic;
+ color: rgb(95, 97, 102);
+ font-size: 10px;
+ margin-left: 20px;
+ max-width: 125px;
+ height: auto;
+ white-space: break-spaces;
+ }
+
+ p {
+ padding-right: 4px;
+ line-height: 12px;
+ border-radius: 5px;
+ //overflow-wrap: break-word;
+ user-select: none;
+ }
- p {
- padding: 4px 6px;
- line-height: 12px;
- border-radius: 5px;
- overflow-wrap: break-word;
- user-select: none;
}
+
}
.linkMenu-item-content {
@@ -32,25 +108,27 @@
}
&:hover {
+
+ background-color: rgb(201, 239, 252);
+
.linkMenu-item-buttons {
display: flex;
}
.linkMenu-item-content {
- &.expand-two p {
- width: calc(100% - 52px);
- background-color: lightgray;
- }
- &.expand-three p {
- width: calc(100% - 84px);
- background-color: lightgray;
+ .linkMenu-destination-title {
+ text-decoration: underline;
+ color: rgb(60, 90, 156);
+ //display: inline;
+ text-overflow: break;
}
}
}
}
.linkMenu-item-buttons {
+ //@extend: right;
position: absolute;
top: 50%;
right: 0;
@@ -61,7 +139,8 @@
width: 20px;
height: 20px;
margin: 0;
- margin-right: 6px;
+ margin-right: 4px;
+ padding-right: 6px;
border-radius: 50%;
pointer-events: auto;
background-color: $dark-color;
@@ -84,7 +163,7 @@
&:hover {
background: $main-accent;
- cursor: grab;
+ cursor: pointer;
}
}
} \ No newline at end of file
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 04cd83ee0..0e847632b 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -1,6 +1,6 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes, faPencilAlt, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import { Doc, DocListCast } from '../../../fields/Doc';
@@ -15,7 +15,9 @@ import { setupMoveUpEvents, emptyFunction } from '../../../Utils';
import { DocumentView } from '../nodes/DocumentView';
import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
import { LinkDocPreview } from '../nodes/LinkDocPreview';
-library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt);
+import { Tooltip } from '@material-ui/core';
+import { DocumentType } from '../../documents/DocumentTypes';
+library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt, faEyeSlash);
interface LinkMenuItemProps {
@@ -26,6 +28,7 @@ interface LinkMenuItemProps {
destinationDoc: Doc;
showEditor: (linkDoc: Doc) => void;
addDocTab: (document: Doc, where: string) => boolean;
+ menuRef: React.Ref<HTMLDivElement>;
}
// drag links and drop link targets (aliasing them if needed)
@@ -77,6 +80,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
@action toggleShowMore(e: React.PointerEvent) { e.stopPropagation(); this._showMore = !this._showMore; }
onEdit = (e: React.PointerEvent): void => {
+
+ console.log("Edit");
+ LinkManager.currentLink = this.props.linkDoc;
+ console.log(this.props.linkDoc);
setupMoveUpEvents(this, e, this.editMoved, emptyFunction, () => this.props.showEditor(this.props.linkDoc));
}
@@ -110,7 +117,8 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
document.removeEventListener("pointerup", this.onLinkButtonUp);
document.addEventListener("pointerup", this.onLinkButtonUp);
- if (this._buttonRef && this._buttonRef.current?.contains(e.target as any)) {
+ if (this._buttonRef && !!!this._buttonRef.current?.contains(e.target as any)) {
+ console.log("outside click");
LinkDocPreview.LinkInfo = undefined;
}
}
@@ -147,7 +155,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
console.log("FOLLOWWW");
DocumentLinksButton.EditLink = undefined;
LinkDocPreview.LinkInfo = undefined;
- DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false);
+
+ if (this.props.linkDoc.followLinkLocation && this.props.linkDoc.followLinkLocation !== "Default") {
+ this.props.addDocTab(this.props.destinationDoc, StrCast(this.props.linkDoc.followLinkLocation));
+ } else {
+ DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false);
+ }
}
@action
@@ -158,13 +171,53 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
DocumentLinksButton.EditLink = undefined;
}
+ @action
+ showLink = () => {
+ this.props.linkDoc.hidden = !this.props.linkDoc.hidden;
+ }
+
render() {
const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType);
const canExpand = keys ? keys.length > 0 : false;
+ const eyeIcon = this.props.linkDoc.hidden ? "eye-slash" : "eye";
+
+ let destinationIcon: FontAwesomeIconProps["icon"] = "question";
+ switch (this.props.destinationDoc.type) {
+ case DocumentType.IMG: destinationIcon = "image"; break;
+ case DocumentType.COMPARISON: destinationIcon = "columns"; break;
+ case DocumentType.RTF: destinationIcon = "font"; break;
+ case DocumentType.COL: destinationIcon = "folder"; break;
+ case DocumentType.WEB: destinationIcon = "globe-asia"; break;
+ case DocumentType.SCREENSHOT: destinationIcon = "photo-video"; break;
+ case DocumentType.WEBCAM: destinationIcon = "video"; break;
+ case DocumentType.AUDIO: destinationIcon = "microphone"; break;
+ case DocumentType.BUTTON: destinationIcon = "bolt"; break;
+ case DocumentType.PRES: destinationIcon = "tv"; break;
+ case DocumentType.QUERY: destinationIcon = "search"; break;
+ case DocumentType.SCRIPTING: destinationIcon = "terminal"; break;
+ case DocumentType.IMPORT: destinationIcon = "cloud-upload-alt"; break;
+ case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
+ case DocumentType.VID: destinationIcon = "video"; break;
+ case DocumentType.INK: destinationIcon = "pen-nib"; break;
+ default: destinationIcon = "question"; break;
+ }
+
+ const title = StrCast(this.props.destinationDoc.title).length > 18 ?
+ StrCast(this.props.destinationDoc.title).substr(0, 14) + "..." : this.props.destinationDoc.title;
+
+ // ...
+ // from anika to bob: here's where the text that is specifically linked would show up (linkDoc.storedText)
+ // ...
+ const source = this.props.sourceDoc.type === DocumentType.RTF ? this.props.linkDoc.storedText ?
+ StrCast(this.props.linkDoc.storedText).length > 17 ?
+ StrCast(this.props.linkDoc.storedText).substr(0, 18)
+ : this.props.linkDoc.storedText : undefined : undefined;
+
return (
<div className="linkMenu-item">
<div className={canExpand ? "linkMenu-item-content expand-three" : "linkMenu-item-content expand-two"}>
+
<div ref={this._drag} className="linkMenu-name" //title="drag to view target. click to customize."
onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)}
onPointerEnter={action(e => this.props.linkDoc && (LinkDocPreview.LinkInfo = {
@@ -174,18 +227,40 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
Location: [e.clientX, e.clientY + 20]
}))}
onPointerDown={this.onLinkButtonDown}>
- <p >{StrCast(this.props.destinationDoc.title)}</p>
+
+ <div className="linkMenu-text">
+ {source ? <p className="linkMenu-source-title">
+ <b>Source: {source}</b></p> : null}
+ <div className="linkMenu-title-wrapper">
+ <div className="destination-icon-wrapper" >
+ <FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" /></div>
+ <p className="linkMenu-destination-title"
+ onPointerDown={this.followDefault}>
+ {title}
+ </p>
+ </div>
+ {this.props.linkDoc.description !== "" ? <p className="linkMenu-description">
+ {StrCast(this.props.linkDoc.description)}</p> : null} </div>
+
<div className="linkMenu-item-buttons" ref={this._buttonRef} >
{canExpand ? <div title="Show more" className="button" onPointerDown={e => this.toggleShowMore(e)}>
<FontAwesomeIcon className="fa-icon" icon={this._showMore ? "chevron-up" : "chevron-down"} size="sm" /></div> : <></>}
- {/* <div title="Edit link" className="button" ref={this._editRef} onPointerDown={this.onEdit}>
- <FontAwesomeIcon className="fa-icon" icon="pencil-alt" size="sm" /></div> */}
- <div title="Delete link" className="button" onPointerDown={this.deleteLink}>
- <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div>
- <div title="Follow link" className="button" onPointerDown={this.followDefault} onContextMenu={this.onContextMenu}>
- <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" />
- </div>
+ <Tooltip title={<><div className="dash-tooltip">{this.props.linkDoc.hidden ? "Show link" : "Hide link"}</div></>}>
+ <div className="button" ref={this._editRef} onPointerDown={this.showLink}>
+ <FontAwesomeIcon className="fa-icon" icon={eyeIcon} size="sm" /></div>
+ </Tooltip>
+
+ <Tooltip title={<><div className="dash-tooltip">Edit Link</div></>}>
+ <div className="button" ref={this._editRef} onPointerDown={this.onEdit}>
+ <FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
+ </Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">Delete Link</div></>}>
+ <div className="button" onPointerDown={this.deleteLink}>
+ <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div>
+ </Tooltip>
+ {/* <div title="Follow link" className="button" onPointerDown={this.followDefault} onContextMenu={this.onContextMenu}>
+ <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div> */}
</div>
</div>
{this._showMore ? this.renderMetadata() : <></>}