aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-04-13 10:57:08 -0400
committerbobzel <zzzman@gmail.com>2022-04-13 10:57:08 -0400
commit594f585b74bf6ecec3795a4b780da619c66f341d (patch)
tree6deb0f0589351e53294f524aca628d7566b0c44c /src
parent9fe8d2f771d5029b7c4c9fbd9c6dd316c88f02cd (diff)
added images to treeView bullets for docs with icons. fixed following pushpin links to prototypes to toggle delegates when shown. gave groups a default padding. fixed creating icons to not create unnecessary template docs. fixed toggling isPushpin. made summaries simple links instead of templates.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts38
-rw-r--r--src/client/util/DocumentManager.ts5
-rw-r--r--src/client/views/DocumentDecorations.tsx5
-rw-r--r--src/client/views/StyleProvider.tsx13
-rw-r--r--src/client/views/collections/TreeView.scss2
-rw-r--r--src/client/views/collections/TreeView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx9
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx9
9 files changed, 59 insertions, 35 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 652f8e7e0..465cdf3ec 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -223,6 +223,7 @@ export class DocumentOptions {
dockingConfig?: string;
annotationOn?: Doc;
isPushpin?: boolean;
+ isGroup?: boolean; // whether a collection should use a grouping UI behavior
_removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
// BACKGROUND GRID
@@ -807,7 +808,7 @@ export namespace Docs {
}
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Freeform }, id);
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _viewType: CollectionViewType.Freeform }, id);
documents.map(d => d.context = inst);
return inst;
}
@@ -1317,22 +1318,25 @@ export namespace DocUtils {
const _height = NumCast(doc._height);
const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false };
- let fieldTemplate: Opt<Doc>;
- if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
- fieldTemplate = Docs.Create.TextDocument("", options);
- } else if (doc.data instanceof PdfField) {
- fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
- } else if (doc.data instanceof VideoField) {
- fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof AudioField) {
- fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof ImageField) {
- fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
- }
- const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
-
- fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
- docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+ if (docLayoutTemplate) {
+ Doc.ApplyTemplateTo(docLayoutTemplate, doc, customName, undefined);
+ } else {
+ let fieldTemplate: Opt<Doc>;
+ if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
+ fieldTemplate = Docs.Create.TextDocument("", options);
+ } else if (doc.data instanceof PdfField) {
+ fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
+ } else if (doc.data instanceof VideoField) {
+ fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof AudioField) {
+ fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof ImageField) {
+ fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
+ }
+ const docTemplate = creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
+ fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
+ docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+ }
}
export function makeCustomView(doc: Doc, custom: boolean, layout: string) {
Doc.setNativeView(doc);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 1d603e18f..fb50ecb4a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -176,12 +176,13 @@ export class DocumentManager {
}); // if the target is hidden, un-hide it here.
}
const focusAndFinish = (didFocus: boolean) => {
+ const finalTargetDoc = docView?.Document ?? targetDoc;
if (originatingDoc?.isPushpin) {
if (!didFocus && !wasHidden) { // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal
- targetDoc.hidden = !targetDoc.hidden;
+ finalTargetDoc.hidden = !finalTargetDoc.hidden;
}
} else {
- targetDoc.hidden && (targetDoc.hidden = undefined);
+ finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined);
!noSelect && docView?.select(false);
}
finished?.();
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 062ca1181..a8d91e0a2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -453,6 +453,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
return (collectionAcl === AclAdmin || collectionAcl === AclEdit || GetEffectiveAcl(docView.rootDoc) === AclAdmin);
});
}
+ @computed get hasIcons() {
+ return SelectionManager.Views().some(docView => docView.rootDoc.layoutKey === "layout_icon");
+ }
render() {
const bounds = this.Bounds;
@@ -516,7 +519,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
}}>
- {!canDelete ? <div /> : topBtn("close", "times", undefined, this.onCloseClick, "Close")}
+ {!canDelete ? <div /> : topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, this.onCloseClick, "Close")}
{titleArea}
{!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")}
{hideResizers ? (null) :
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 9803f9782..dba290b46 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -3,10 +3,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import 'golden-layout/src/css/goldenlayout-base.css';
import 'golden-layout/src/css/goldenlayout-dark-theme.css';
import { action, runInAction } from 'mobx';
+import { extname } from 'path';
import { Doc, Opt, StrListCast } from "../../fields/Doc";
import { List } from '../../fields/List';
import { listSpec } from '../../fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
+import { BoolCast, Cast, ImageCast, NumCast, StrCast } from "../../fields/Types";
import { DashColor, lightOrDark } from '../../Utils';
import { DocumentType } from '../documents/DocumentTypes';
import { CurrentUserUtils } from '../util/CurrentUserUtils';
@@ -88,7 +89,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min);
switch (property.split(":")[0]) {
- case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);
+ case StyleProp.TreeViewIcon:
+ const icon = Cast(doc?.layout_icon, Doc, null) ? Doc.expandTemplateLayout(Cast(doc?.layout_icon, Doc, null), doc) : undefined;
+ if (icon && ImageCast(doc?.icon, ImageCast(doc?.data))) {
+ const img = ImageCast(doc?.icon, ImageCast(doc?.data));
+ const ext = extname(img.url.href);
+ const url = doc?.icon ? img.url.href : img.url.href.replace(ext, "_s" + ext);
+ return <img src={url} width={20} height={15} style={{ margin: "auto", display: "block", objectFit: "contain" }} />;
+ }
+ return Doc.toIcon(doc, isOpen);
case StyleProp.DocContents: return undefined;
case StyleProp.WidgetColor: return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 2e33d3564..7c75810d3 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -47,7 +47,7 @@
width: $TREE_BULLET_WIDTH;
color: $medium-gray;
margin-top: 3px;
- transform: scale(1.3, 1.3);
+ // transform: scale(1.3, 1.3); // bcz: why was this here? It makes displaying images in the treeView for documents that have icons harder.
border: #80808030 1px solid;
border-radius: 4px;
}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ff5c4bab1..c2d0983da 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -31,6 +31,7 @@ import { CollectionTreeView } from './CollectionTreeView';
import { CollectionView, CollectionViewType } from './CollectionView';
import "./TreeView.scss";
import React = require("react");
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
export interface TreeViewProps {
treeView: CollectionTreeView;
@@ -471,7 +472,7 @@ export class TreeView extends React.Component<TreeViewProps> {
onClick={this.bulletClick}
style={this.props.treeView.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
- opacity: checked === "unchecked" ? undefined : 0.4
+ opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4
}}>
{this.props.treeView.outlineMode ?
!(this.doc.text as RichTextField)?.Text ? (null) :
@@ -484,7 +485,7 @@ export class TreeView extends React.Component<TreeViewProps> {
checked === "unchecked" ? "square" :
!this.treeViewOpen ? "caret-right" : "caret-down"} />
</div>
- {this.onCheckedClick ? (null) : <FontAwesomeIcon icon={iconType} />}
+ {this.onCheckedClick ? (null) : typeof iconType === "string" ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
</div>
}
</div>;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b8f687489..5405ab500 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -519,13 +519,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.y = NumCast(d.y) - this.Bounds.top;
return d;
});
- const summary = Docs.Create.TextDocument("", { x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
- const portal = Doc.MakeAlias(summary);
- Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List<Doc>(selected);
- Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations");
- summary._backgroundColor = "#e2ad32";
- portal.layoutKey = "layout_portal";
- portal.title = "document collection";
+ const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
+ const portal = Docs.Create.FreeformDocument(selected, { isGroup: true, backgroundColor: "transparent" });
DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summarizing", "");
this.props.addLiveTextDocument(summary);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 195f6c9e5..8bf9348c7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -594,8 +594,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@undoBatch @action
toggleFollowLink = (location: Opt<string>, zoom: boolean, setPushpin: boolean): void => {
this.Document.ignoreClick = false;
- this.Document._isLinkButton = !this.Document._isLinkButton;
- setPushpin && (this.Document.isPushpin = this.Document._isLinkButton);
+ if (setPushpin) {
+ this.Document.isPushpin = !this.Document.isPushpin;
+ this.Document._isLinkButton = this.Document.isPushpin || this.Document._isLinkButton;
+ } else {
+ this.Document._isLinkButton = !this.Document._isLinkButton;
+ }
if (this.Document._isLinkButton && !this.onClickHandler) {
this.Document.followLinkZoom = zoom;
this.Document.followLinkLocation = location;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d5f3f3b4e..eca2e3cfd 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -15,6 +15,7 @@ import { DocumentView, DocumentViewSharedProps } from "./DocumentView";
import './LinkDocPreview.scss';
import React = require("react");
import { DocumentType } from '../../documents/DocumentTypes';
+import { DragManager } from '../../util/DragManager';
interface LinkDocPreviewProps {
linkDoc?: Doc;
@@ -137,7 +138,13 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
@computed get previewHeader() {
return !this._linkDoc || !this._targetDoc || !this._linkSrc ? (null) :
<div className="linkDocPreview-info" ref={this._infoRef}>
- <div className="linkDocPreview-title">
+ <div className="linkDocPreview-title" style={{ pointerEvents: "all" }}
+ onPointerDown={e => {
+ DragManager.StartDocumentDrag([this._infoRef.current!],
+ new DragManager.DocumentDragData([this._targetDoc!]), e.pageX, e.pageY);
+ e.stopPropagation();
+ LinkDocPreview.Clear();
+ }}>
{StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + "..." : this._targetDoc.title}
<p className="linkDocPreview-description"> {StrCast(this._linkDoc.description)}</p>
</div>