aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx56
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx193
-rw-r--r--src/client/views/collections/CollectionMenu.scss1255
-rw-r--r--src/client/views/collections/CollectionMenu.tsx144
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx10
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx47
-rw-r--r--src/client/views/collections/CollectionStackingView.scss24
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx126
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx90
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx14
-rw-r--r--src/client/views/collections/CollectionTreeView.scss8
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx140
-rw-r--r--src/client/views/collections/CollectionView.tsx56
-rw-r--r--src/client/views/collections/TabDocView.scss30
-rw-r--r--src/client/views/collections/TabDocView.tsx53
-rw-r--r--src/client/views/collections/TreeView.tsx68
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx32
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx44
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx25
-rw-r--r--src/client/views/collections/collectionFreeForm/index.ts7
-rw-r--r--src/client/views/collections/collectionGrid/index.ts2
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.scss (renamed from src/client/views/collections/CollectionLinearView.scss)62
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx226
-rw-r--r--src/client/views/collections/collectionLinear/index.ts1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx4
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx4
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx12
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.scss120
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTable.tsx5
33 files changed, 1679 insertions, 1211 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a8471f8e2..5325d5827 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -4,7 +4,7 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from "mo
import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
import * as GoldenLayout from "../../../client/goldenLayout";
-import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt, DocListCastAsync, DataSym } from "../../../fields/Doc";
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
@@ -24,6 +24,7 @@ import React = require("react");
import { DocumentType } from '../../documents/DocumentTypes';
import { listSpec } from '../../../fields/Schema';
import { LightboxView } from '../LightboxView';
+import { inheritParentAcls } from '../../../fields/util';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -160,6 +161,18 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
}
const instance = CollectionDockingView.Instance;
if (!instance) return false;
+ else {
+ const docList = DocListCast(instance.props.Document[DataSym]["data-all"]);
+ // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
+ !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document);
+ // adds an alias of the doc to the data-all field of the layoutdocs of the aliases
+ DocListCast(instance.props.Document[DataSym].aliases).forEach(alias => {
+ const aliasDocList = DocListCast(alias["data-all"]);
+ // if aliasDocList contains the alias, don't do anything
+ // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias
+ !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data-all", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document);
+ });
+ }
const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
if (!pullSide && stack) {
@@ -381,15 +394,22 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
setTimeout(async () => {
const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]);
const tabs = sublists && Cast(sublists[0], Doc, null);
- const other = sublists && Cast(sublists[1], Doc, null);
+ // const other = sublists && Cast(sublists[1], Doc, null);
const tabdocs = await DocListCastAsync(tabs?.data);
- const otherdocs = await DocListCastAsync(other?.data);
- tabs && (Doc.GetProto(tabs).data = new List<Doc>(docs));
- const otherSet = new Set<Doc>();
- otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc));
- tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc));
- const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP);
- other && (Doc.GetProto(other).data = new List<Doc>(vals));
+ // const otherdocs = await DocListCastAsync(other?.data);
+ if (tabs) {
+ tabs.data = new List<Doc>(docs);
+ // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List<Doc>(docs)));
+ }
+ // const otherSet = new Set<Doc>();
+ // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc));
+ // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc));
+ // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP);
+ // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List<Doc>([...docs, ...vals]);
+ // if (other) {
+ // other.data = new List<Doc>(vals);
+ // // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List<Doc>(vals)));
+ // }
}, 0);
}
@@ -399,7 +419,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
}
tabCreated = (tab: any) => {
- tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous abs (ie, when dragging a tab around a new tab is created for the old content)
+ tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content)
}
stackCreated = (stack: any) => {
@@ -407,9 +427,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
if (e.target === stack.header?.element[0] && e.button === 2) {
const emptyPane = CurrentUserUtils.EmptyPane;
emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1;
- CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], {
- _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`
- }), "", stack);
+ const docToAdd = Docs.Create.FreeformDocument([], {
+ _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _backgroundGridShow: true, _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`,
+ });
+ this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
+ CollectionDockingView.AddSplit(docToAdd, "", stack);
}
});
@@ -430,9 +452,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
// stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size
const emptyPane = CurrentUserUtils.EmptyPane;
emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1;
- CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], {
- _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`
- }), "", stack);
+ const docToAdd = Docs.Create.FreeformDocument([], {
+ _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, _backgroundGridShow: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`
+ });
+ this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
+ CollectionDockingView.AddSplit(docToAdd, "", stack);
}));
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
deleted file mode 100644
index 52c836556..000000000
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-import { Tooltip } from '@material-ui/core';
-import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
-import { documentSchema } from '../../../fields/documentSchemas';
-import { Id } from '../../../fields/FieldSymbols';
-import { makeInterface } from '../../../fields/Schema';
-import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, Utils } from '../../../Utils';
-import { DragManager } from '../../util/DragManager';
-import { Transform } from '../../util/Transform';
-import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
-import { DocumentView } from '../nodes/DocumentView';
-import { LinkDescriptionPopup } from '../nodes/LinkDescriptionPopup';
-import { StyleProp } from '../StyleProvider';
-import "./CollectionLinearView.scss";
-import { CollectionSubView } from './CollectionSubView';
-import { CollectionViewType } from './CollectionView';
-
-
-type LinearDocument = makeInterface<[typeof documentSchema,]>;
-const LinearDocument = makeInterface(documentSchema);
-
-@observer
-export class CollectionLinearView extends CollectionSubView(LinearDocument) {
- @observable public addMenuToggle = React.createRef<HTMLInputElement>();
- @observable private _selectedIndex = -1;
- private _dropDisposer?: DragManager.DragDropDisposer;
- private _widthDisposer?: IReactionDisposer;
- private _selectedDisposer?: IReactionDisposer;
-
- componentWillUnmount() {
- this._dropDisposer?.();
- this._widthDisposer?.();
- this._selectedDisposer?.();
- this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
- }
-
- componentDidMount() {
- this._widthDisposer = reaction(() => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * (this.rootDoc[HeightSym]()) : 10),
- width => this.childDocs.length && (this.layoutDoc._width = width),
- { fireImmediately: true }
- );
-
- this._selectedDisposer = reaction(
- () => NumCast(this.layoutDoc.selectedIndex),
- (i) => runInAction(() => {
- this._selectedIndex = i;
- let selected: any = undefined;
- this.childLayoutPairs.map(async (pair, ind) => {
- const isSelected = this._selectedIndex === ind;
- if (isSelected) {
- selected = pair;
- }
- else {
- ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
- }
- });
- if (selected && selected.layout) {
- ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
- }
- }),
- { fireImmediately: true }
- );
- }
- protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
- this._dropDisposer && this._dropDisposer();
- if (ele) {
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
- }
- }
-
- dimension = () => NumCast(this.rootDoc._height); // 2 * the padding
- getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
- if (!ele.current) return Transform.Identity();
- const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current);
- return new Transform(-translateX, -translateY, 1);
- }
-
- @action
- exitLongLinks = () => {
- if (DocumentLinksButton.StartLink) {
- if (DocumentLinksButton.StartLink.Document) {
- action((e: React.PointerEvent<HTMLDivElement>) => {
- Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc);
- });
- }
- }
- DocumentLinksButton.StartLink = undefined;
- DocumentLinksButton.StartLinkView = undefined;
- }
-
- @action
- changeDescriptionSetting = () => {
- if (LinkDescriptionPopup.showDescriptions) {
- if (LinkDescriptionPopup.showDescriptions === "ON") {
- LinkDescriptionPopup.showDescriptions = "OFF";
- LinkDescriptionPopup.descriptionPopup = false;
- } else {
- LinkDescriptionPopup.showDescriptions = "ON";
- }
- } else {
- LinkDescriptionPopup.showDescriptions = "OFF";
- LinkDescriptionPopup.descriptionPopup = false;
- }
- }
-
- render() {
- const guid = Utils.GenerateGuid();
- const flexDir: any = StrCast(this.Document.flexDirection);
- const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
- const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
-
- const menuOpener = <label htmlFor={`${guid}`} style={{ pointerEvents: "all", cursor: "pointer", background: backgroundColor === color ? "black" : backgroundColor, }}
- onPointerDown={e => e.stopPropagation()} >
- <p>{BoolCast(this.layoutDoc.linearViewIsExpanded) ? "–" : "+"}</p>
- </label>;
-
- return <div className="collectionLinearView-outer">
- <div className="collectionLinearView" ref={this.createDashEventsTarget} >
- <Tooltip title={<><div className="dash-tooltip">{BoolCast(this.layoutDoc.linearViewIsExpanded) ? "Close menu" : "Open menu"}</div></>} placement="top">
- {menuOpener}
- </Tooltip>
- <input id={`${guid}`} type="checkbox" checked={BoolCast(this.layoutDoc.linearViewIsExpanded)} ref={this.addMenuToggle}
- onChange={action(() => this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
-
- <div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
- {this.childLayoutPairs.map((pair, ind) => {
- const nested = pair.layout._viewType === CollectionViewType.Linear;
- const dref = React.createRef<HTMLDivElement>();
- const scalable = pair.layout.onClick || pair.layout.onDragStart;
- return <div className={`collectionLinearView-docBtn` + (scalable ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
- style={{
- pointerEvents: "all",
- minWidth: 30,
- width: nested ? pair.layout[WidthSym]() : this.dimension(),
- height: nested && pair.layout.linearViewIsExpanded ? pair.layout[HeightSym]() : this.dimension(),
- }} >
- <DocumentView
- Document={pair.layout}
- DataDoc={pair.data}
- isContentActive={returnFalse}
- isDocumentActive={returnTrue}
- addDocument={this.props.addDocument}
- moveDocument={this.props.moveDocument}
- addDocTab={this.props.addDocTab}
- pinToPres={emptyFunction}
- rootSelected={this.props.isSelected}
- removeDocument={this.props.removeDocument}
- ScreenToLocalTransform={this.getTransform(dref)}
- PanelWidth={nested ? pair.layout[WidthSym] : this.dimension}
- PanelHeight={nested ? pair.layout[HeightSym] : this.dimension}
- renderDepth={this.props.renderDepth + 1}
- focus={emptyFunction}
- styleProvider={this.props.styleProvider}
- layerProvider={this.props.layerProvider}
- docViewPath={returnEmptyDoclist}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />
- </div>;
- })}
- </div>
- {DocumentLinksButton.StartLink ? <span className="bottomPopup-background" style={{
- pointerEvents: "all"
- }}
- onPointerDown={e => e.stopPropagation()} >
- <span className="bottomPopup-text" >
- Creating link from: <b>{DocumentLinksButton.AnnotationId ? "Annotation in " : " "} {StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...'}</b>
- </span>
-
- <Tooltip title={<><div className="dash-tooltip">{"Toggle description pop-up"} </div></>} placement="top">
- <span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
- Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"}
- </span>
- </Tooltip>
-
- <Tooltip title={<><div className="dash-tooltip">Exit linking mode</div></>} placement="top">
- <span className="bottomPopup-exit" onClick={this.exitLongLinks}>
- Stop
- </span>
- </Tooltip>
-
- </span> : null}
- </div>
- </div>;
- }
-} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index f04b19ef7..c35f088a6 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -1,628 +1,659 @@
@import "../global/globalCssVariables";
-.collectionMenu-cont {
- position: relative;
- display: inline-flex;
- width: 100%;
- opacity: 0.9;
- z-index: 901;
- transition: top .5s;
- background: $dark-gray;
- color: $white;
- transform-origin: top left;
- top: 0;
- width: 100%;
-
- .recordButtonOutline {
- border-radius: 100%;
- width: 18px;
- height: 18px;
- border: solid 1px $white;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- .recordButtonInner {
- border-radius: 100%;
- width: 70%;
- height: 70%;
- background: $white;
- }
-
- .collectionMenu {
- display: flex;
- height: 100%;
- overflow: visible;
- z-index: 901;
- border: unset;
-
- .collectionMenu-divider {
- height: 100%;
- margin-left: 3px;
- margin-right: 3px;
- width: 2px;
- background-color: $medium-gray;
- }
-
- .collectionViewBaseChrome {
- display: flex;
- align-items: center;
-
- .collectionViewBaseChrome-viewPicker {
- font-size: $small-text;
- outline-color: $black;
- color: $white;
- border: none;
- background: $dark-gray;
- }
-
- .collectionViewBaseChrome-viewPicker:focus {
- outline: none;
- border: none;
- }
-
- .collectionViewBaseChrome-viewPicker:active {
- outline-color: $black;
- }
-
- .collectionViewBaseChrome-button {
- font-size: $small-text;
- text-transform: uppercase;
- letter-spacing: 2px;
- background: $white;
- color: $pink;
- outline-color: $black;
- border: none;
- padding: 12px 10px 11px 10px;
- margin-left: 10px;
- }
-
- .collectionViewBaseChrome-cmdPicker {
- margin-left: 3px;
- margin-right: 0px;
- font-size: $small-text;
- text-transform: capitalize;
- color: $white;
- border: none;
- background: $dark-gray;
- }
-
- .collectionViewBaseChrome-cmdPicker:focus {
- border: none;
- outline: none;
- }
-
- .commandEntry-outerDiv {
- pointer-events: all;
- background-color: transparent;
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- height: 100%;
- overflow: hidden;
-
- .commandEntry-drop {
- color: $white;
- width: 30px;
- margin-top: auto;
- margin-bottom: auto;
- }
- }
-
- .commandEntry-outerDiv:hover{
- background-color: $drop-shadow;
-
- .collectionViewBaseChrome-viewPicker,
- .collectionViewBaseChrome-cmdPicker{
- background: $dark-gray;
- }
- }
-
- .collectionViewBaseChrome-collapse {
- transition: all .5s, opacity 0.3s;
- position: absolute;
- width: 30px;
- transform-origin: top left;
- pointer-events: all;
- // margin-top: 10px;
- }
-
- @media only screen and (max-device-width: 480px) {
- .collectionViewBaseChrome-collapse {
- display: none;
- }
- }
-
- .collectionViewBaseChrome-template,
- .collectionViewBaseChrome-viewModes {
- align-items: center;
- height: 100%;
- display: flex;
- background: transparent;
- color: $medium-gray;
- justify-content: center;
- }
-
- .collectionViewBaseChrome-viewSpecs {
- margin-left: 5px;
- display: grid;
- border: none;
- border-right: solid $medium-gray 1px;
-
- .collectionViewBaseChrome-filterIcon {
- position: relative;
- display: flex;
- margin: auto;
- background: $dark-gray;
- color: $white;
- width: 30px;
- height: 30px;
- align-items: center;
- justify-content: center;
- border: none;
- border-right: solid $medium-gray 1px;
- }
-
- .collectionViewBaseChrome-viewSpecsInput {
- padding: 12px 10px 11px 10px;
- border: 0px;
- color: $medium-gray;
- text-align: center;
- letter-spacing: 2px;
- outline-color: $black;
- font-size: $small-text;
- background: $white;
- height: 100%;
- width: 75px;
- }
-
- .collectionViewBaseChrome-viewSpecsMenu {
- overflow: hidden;
- transition: height .5s, display .5s;
- position: absolute;
- top: 60px;
- z-index: 100;
- display: flex;
- flex-direction: column;
- background: $white;
- box-shadow: $medium-gray 2px 2px 4px;
-
- .qs-datepicker {
- left: unset;
- right: 0;
- }
-
- .collectionViewBaseChrome-viewSpecsMenu-row {
- display: grid;
- grid-template-columns: 150px 200px 150px;
- margin-top: 10px;
- margin-right: 10px;
-
- .collectionViewBaseChrome-viewSpecsMenu-rowLeft,
- .collectionViewBaseChrome-viewSpecsMenu-rowMiddle,
- .collectionViewBaseChrome-viewSpecsMenu-rowRight {
- font-size: $small-text;
- letter-spacing: 2px;
- color: $medium-gray;
- margin-left: 10px;
- padding: 5px;
- border: none;
- outline-color: $black;
- }
- }
-
- .collectionViewBaseChrome-viewSpecsMenu-lastRow {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- grid-gap: 10px;
- margin: 10px;
- }
- }
- }
- }
-
- .collectionStackingViewChrome-cont,
- .collectionTreeViewChrome-cont,
- .collection3DCarouselViewChrome-cont {
- display: flex;
- justify-content: space-between;
- }
-
- .collectionGridViewChrome-cont {
- display: flex;
- margin-left: 10;
-
- .collectionGridViewChrome-viewPicker {
- font-size: $small-text;
- //text-transform: uppercase;
- //letter-spacing: 2px;
- background: $dark-gray;
- color: $white;
- outline-color: $black;
- color: $white;
- border: none;
- border-right: solid $medium-gray 1px;
- }
-
- .collectionGridViewChrome-viewPicker:active {
- outline-color: $black;
- }
-
- .grid-control {
- align-self: center;
- display: flex;
- flex-direction: row;
- margin-right: 5px;
-
- .grid-icon {
- margin-right: 5px;
- align-self: center;
- }
-
- .flexLabel {
- margin-bottom: 0;
- }
-
- .collectionGridViewChrome-entryBox {
- width: 50%;
- color: $black;
- }
-
- .collectionGridViewChrome-columnButton {
- color: $black;
- }
- }
- }
-
- .collectionStackingViewChrome-sort,
- .collectionTreeViewChrome-sort {
- display: flex;
- align-items: center;
- justify-content: space-between;
-
- .collectionStackingViewChrome-sortIcon,
- .collectionTreeViewChrome-sortIcon {
- transition: transform .5s;
- margin-left: 10px;
- }
- }
-
- button:hover {
- transform: scale(1);
- }
-
-
- .collectionStackingViewChrome-pivotField-cont,
- .collectionTreeViewChrome-pivotField-cont,
- .collection3DCarouselViewChrome-scrollSpeed-cont {
- justify-self: right;
- align-items: center;
- display: flex;
- grid-auto-columns: auto;
- font-size: $small-text;
- letter-spacing: 2px;
-
- .collectionStackingViewChrome-pivotField-label,
- .collectionTreeViewChrome-pivotField-label,
- .collection3DCarouselViewChrome-scrollSpeed-label {
- grid-column: 1;
- margin-right: 7px;
- user-select: none;
- font-family: $sans-serif;
- letter-spacing: normal;
- }
-
- .collectionStackingViewChrome-sortIcon {
- transition: transform .5s;
- grid-column: 3;
- text-align: center;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- width: 25px;
- height: 25px;
- border-radius: 100%;
- }
-
- .collectionStackingViewChrome-sortIcon:hover {
- background-color: $drop-shadow;
- }
-
- .collectionStackingViewChrome-pivotField,
- .collectionTreeViewChrome-pivotField,
- .collection3DCarouselViewChrome-scrollSpeed {
- color: $white;
- grid-column: 2;
- grid-row: 1;
- width: 90%;
- min-width: 100px;
- display: flex;
- height: 80%;
- border-radius: 7px;
- align-items: center;
- background: $white;
-
- .editable-view-input,
- input,
- .editableView-container-editing-oneLine,
- .editableView-container-editing {
- margin: auto;
- border: 0px;
- color: $light-gray !important;
- text-align: center;
- letter-spacing: 2px;
- outline-color: $black;
- height: 100%;
- }
-
- .react-autosuggest__container {
- margin: 0;
- color: $medium-gray;
- padding: 0px;
- }
- }
- }
-
- .collectionStackingViewChrome-pivotField:hover,
- .collectionTreeViewChrome-pivotField:hover,
- .collection3DCarouselViewChrome-scrollSpeed:hover {
- cursor: text;
- }
-
- }
-}
-
-.collectionMenu-webUrlButtons {
- margin-left: 44;
- background: lightGray;
+.collectionMenu-container {
display: flex;
-}
-
-.webBox-urlEditor {
- position: relative;
- opacity: 0.9;
- z-index: 901;
- transition: top .5s;
-
- .urlEditor {
- display: grid;
- grid-template-columns: 1fr auto;
- padding-bottom: 10px;
- overflow: hidden;
- margin-top: 5px;
- height: 35px;
-
- .editorBase {
- display: flex;
-
- .editor-collapse {
- transition: all .5s, opacity 0.3s;
- position: absolute;
- width: 40px;
- transform-origin: top left;
- }
-
- .switchToText {
- color: $medium-gray;
- }
-
- .switchToText:hover {
- color: $dark-gray;
- }
- }
-
- button:hover {
- transform: scale(1);
- }
- }
-}
-
-.collectionMenu-urlInput {
- padding: 12px 10px 11px 10px;
- border: 0px;
- color: $black;
- font-size: $small-text;
- letter-spacing: 2px;
- outline-color: $black;
- background: $white;
- width: 100%;
- min-width: 350px;
- margin-right: 10px;
- height: 100%;
-}
-
-.collectionFreeFormMenu-cont {
- display: inline-flex;
position: relative;
+ align-content: center;
+ justify-content: space-between;
+ background-color: $dark-gray;
+ height: 35px;
+ border-bottom: $standard-border;
+ padding-right: 5px;
align-items: center;
- height: 100%;
-
- .color-previewI {
- width: 60%;
- top: 80%;
- position: absolute;
- height: 4px;
- }
-
- .color-previewII {
- width: 80%;
- height: 80%;
- margin-left: 10%;
- position: absolute;
- bottom: 5;
- }
-
- .btn-group {
- display: grid;
- grid-template-columns: auto auto auto auto;
- margin: auto;
- /* Make the buttons appear below each other */
- }
- .btn-draw {
- display: inline-flex;
- margin: auto;
- /* Make the buttons appear below each other */
- }
-
- .fwdKeyframe,
- .numKeyframe,
- .backKeyframe {
+ .collectionMenu-hardCodedButton {
cursor: pointer;
- position: relative;
- width: 20;
- height: 30;
- bottom: 0;
- background: $dark-gray;
- display: inline-flex;
- align-items: center;
color: $white;
- }
-
- .backKeyframe {
- svg {
- display: block;
- margin: auto;
- }
- }
-
-
- .numKeyframe {
- flex-direction: column;
- padding-top: 5px;
- }
-
- .fwdKeyframe {
- svg {
- display: block;
- margin: auto;
- }
-
- border-right: solid $medium-gray 1px;
- }
-}
-
-.collectionSchemaViewChrome-cont {
- display: flex;
- font-size: $small-text;
-
- .collectionSchemaViewChrome-toggle {
- display: flex;
- margin-left: 10px;
- }
-
- .collectionSchemaViewChrome-label {
- text-transform: uppercase;
- letter-spacing: 2px;
- margin-right: 5px;
+ width: 25px;
+ height: 25px;
+ padding: 5;
+ text-align: center;
display: flex;
- flex-direction: column;
justify-content: center;
- }
-
- .collectionSchemaViewChrome-toggler {
- width: 100px;
- height: 35px;
- background-color: $black;
+ align-items: center;
position: relative;
- }
-
- .collectionSchemaViewChrome-togglerButton {
- width: 47px;
- height: 30px;
- background-color: $light-gray;
- // position: absolute;
- transition: all 0.5s ease;
- // top: 3px;
- margin-top: 3px;
- color: $medium-gray;
- letter-spacing: 2px;
- text-transform: uppercase;
- display: flex;
- flex-direction: column;
- justify-content: center;
- text-align: center;
+ transition: 0.2s;
+ border-radius: 3px;
- &.on {
- margin-left: 3px;
- }
-
- &.off {
- margin-left: 50px;
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.2);
}
}
}
-
-.commandEntry-outerDiv {
- display: flex;
- flex-direction: column;
- height: 40px;
-}
-
-.commandEntry-inputArea {
- display: flex;
- flex-direction: row;
- width: 150px;
- margin: auto auto auto auto;
-}
-
-.react-autosuggest__container {
- position: relative;
- width: 100%;
- margin-left: 5px;
- margin-right: 5px;
-}
-
-.react-autosuggest__input {
- border: 1px solid $light-gray;
- border-radius: 4px;
- width: 100%;
-}
-
-.react-autosuggest__input--focused {
- outline: none;
-}
-
-.react-autosuggest__input--open {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
-}
-
-.react-autosuggest__suggestions-container {
- display: none;
-}
-
-.react-autosuggest__suggestions-container--open {
- display: block;
- position: fixed;
- overflow-y: auto;
- max-height: 400px;
- width: 180px;
- border: 1px solid $light-gray;
- background-color: $white;
- font-family: $sans-serif;
- font-weight: 300;
- font-size: $large-header;
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- z-index: 2;
-}
-
-.react-autosuggest__suggestions-list {
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-
-.react-autosuggest__suggestion {
- cursor: pointer;
- padding: 10px 20px;
-}
-
-.react-autosuggest__suggestion--highlighted {
- background-color: $light-gray;
-} \ No newline at end of file
+// .collectionMenu-cont {
+// position: relative;
+// display: inline-flex;
+// width: 100%;
+// opacity: 0.9;
+// z-index: 901;
+// transition: top .5s;
+// background: $dark-gray;
+// color: $white;
+// transform-origin: top left;
+// top: 0;
+// width: 100%;
+
+// .recordButtonOutline {
+// border-radius: 100%;
+// width: 18px;
+// height: 18px;
+// border: solid 1px $white;
+// display: flex;
+// align-items: center;
+// justify-content: center;
+// }
+
+// .recordButtonInner {
+// border-radius: 100%;
+// width: 70%;
+// height: 70%;
+// background: $white;
+// }
+
+// .collectionMenu {
+// display: flex;
+// height: 100%;
+// overflow: visible;
+// z-index: 901;
+// border: unset;
+
+// .collectionMenu-divider {
+// height: 100%;
+// margin-left: 3px;
+// margin-right: 3px;
+// width: 2px;
+// background-color: $medium-gray;
+// }
+
+// .collectionViewBaseChrome {
+// display: flex;
+// align-items: center;
+
+// .collectionViewBaseChrome-viewPicker {
+// font-size: $small-text;
+// outline-color: $black;
+// color: $white;
+// border: none;
+// background: $dark-gray;
+// }
+
+// .collectionViewBaseChrome-viewPicker:focus {
+// outline: none;
+// border: none;
+// }
+
+// .collectionViewBaseChrome-viewPicker:active {
+// outline-color: $black;
+// }
+
+// .collectionViewBaseChrome-button {
+// font-size: $small-text;
+// text-transform: uppercase;
+// letter-spacing: 2px;
+// background: $white;
+// color: $pink;
+// outline-color: $black;
+// border: none;
+// padding: 12px 10px 11px 10px;
+// margin-left: 10px;
+// }
+
+// .collectionViewBaseChrome-cmdPicker {
+// margin-left: 3px;
+// margin-right: 0px;
+// font-size: $small-text;
+// text-transform: capitalize;
+// color: $white;
+// border: none;
+// background: $dark-gray;
+// }
+
+// .collectionViewBaseChrome-cmdPicker:focus {
+// border: none;
+// outline: none;
+// }
+
+// .commandEntry-outerDiv {
+// pointer-events: all;
+// background-color: transparent;
+// display: flex;
+// flex-direction: row;
+// align-items: center;
+// justify-content: center;
+// height: 100%;
+// overflow: hidden;
+
+// .commandEntry-drop {
+// color: $white;
+// width: 30px;
+// margin-top: auto;
+// margin-bottom: auto;
+// }
+// }
+
+// .commandEntry-outerDiv:hover{
+// background-color: $drop-shadow;
+
+// .collectionViewBaseChrome-viewPicker,
+// .collectionViewBaseChrome-cmdPicker{
+// background: $dark-gray;
+// }
+// }
+
+// .collectionViewBaseChrome-collapse {
+// transition: all .5s, opacity 0.3s;
+// position: absolute;
+// width: 30px;
+// transform-origin: top left;
+// pointer-events: all;
+// // margin-top: 10px;
+// }
+
+// @media only screen and (max-device-width: 480px) {
+// .collectionViewBaseChrome-collapse {
+// display: none;
+// }
+// }
+
+// .collectionViewBaseChrome-template,
+// .collectionViewBaseChrome-viewModes {
+// align-items: center;
+// height: 100%;
+// display: flex;
+// background: transparent;
+// color: $medium-gray;
+// justify-content: center;
+// }
+
+// .collectionViewBaseChrome-viewSpecs {
+// margin-left: 5px;
+// display: grid;
+// border: none;
+// border-right: solid $medium-gray 1px;
+
+// .collectionViewBaseChrome-filterIcon {
+// position: relative;
+// display: flex;
+// margin: auto;
+// background: $dark-gray;
+// color: $white;
+// width: 30px;
+// height: 30px;
+// align-items: center;
+// justify-content: center;
+// border: none;
+// border-right: solid $medium-gray 1px;
+// }
+
+// .collectionViewBaseChrome-viewSpecsInput {
+// padding: 12px 10px 11px 10px;
+// border: 0px;
+// color: $medium-gray;
+// text-align: center;
+// letter-spacing: 2px;
+// outline-color: $black;
+// font-size: $small-text;
+// background: $white;
+// height: 100%;
+// width: 75px;
+// }
+
+// .collectionViewBaseChrome-viewSpecsMenu {
+// overflow: hidden;
+// transition: height .5s, display .5s;
+// position: absolute;
+// top: 60px;
+// z-index: 100;
+// display: flex;
+// flex-direction: column;
+// background: $white;
+// box-shadow: $medium-gray 2px 2px 4px;
+
+// .qs-datepicker {
+// left: unset;
+// right: 0;
+// }
+
+// .collectionViewBaseChrome-viewSpecsMenu-row {
+// display: grid;
+// grid-template-columns: 150px 200px 150px;
+// margin-top: 10px;
+// margin-right: 10px;
+
+// .collectionViewBaseChrome-viewSpecsMenu-rowLeft,
+// .collectionViewBaseChrome-viewSpecsMenu-rowMiddle,
+// .collectionViewBaseChrome-viewSpecsMenu-rowRight {
+// font-size: $small-text;
+// letter-spacing: 2px;
+// color: $medium-gray;
+// margin-left: 10px;
+// padding: 5px;
+// border: none;
+// outline-color: $black;
+// }
+// }
+
+// .collectionViewBaseChrome-viewSpecsMenu-lastRow {
+// display: grid;
+// grid-template-columns: 1fr 1fr 1fr;
+// grid-gap: 10px;
+// margin: 10px;
+// }
+// }
+// }
+// }
+
+// .collectionStackingViewChrome-cont,
+// .collectionTreeViewChrome-cont,
+// .collection3DCarouselViewChrome-cont {
+// display: flex;
+// justify-content: space-between;
+// }
+
+// .collectionGridViewChrome-cont {
+// display: flex;
+// margin-left: 10;
+
+// .collectionGridViewChrome-viewPicker {
+// font-size: $small-text;
+// //text-transform: uppercase;
+// //letter-spacing: 2px;
+// background: $dark-gray;
+// color: $white;
+// outline-color: $black;
+// color: $white;
+// border: none;
+// border-right: solid $medium-gray 1px;
+// }
+
+// .collectionGridViewChrome-viewPicker:active {
+// outline-color: $black;
+// }
+
+// .grid-control {
+// align-self: center;
+// display: flex;
+// flex-direction: row;
+// margin-right: 5px;
+
+// .grid-icon {
+// margin-right: 5px;
+// align-self: center;
+// }
+
+// .flexLabel {
+// margin-bottom: 0;
+// }
+
+// .collectionGridViewChrome-entryBox {
+// width: 50%;
+// color: $black;
+// }
+
+// .collectionGridViewChrome-columnButton {
+// color: $black;
+// }
+// }
+// }
+
+// .collectionStackingViewChrome-sort,
+// .collectionTreeViewChrome-sort {
+// display: flex;
+// align-items: center;
+// justify-content: space-between;
+
+// .collectionStackingViewChrome-sortIcon,
+// .collectionTreeViewChrome-sortIcon {
+// transition: transform .5s;
+// margin-left: 10px;
+// }
+// }
+
+// button:hover {
+// transform: scale(1);
+// }
+
+
+// .collectionStackingViewChrome-pivotField-cont,
+// .collectionTreeViewChrome-pivotField-cont,
+// .collection3DCarouselViewChrome-scrollSpeed-cont {
+// justify-self: right;
+// align-items: center;
+// display: flex;
+// grid-auto-columns: auto;
+// font-size: $small-text;
+// letter-spacing: 2px;
+
+// .collectionStackingViewChrome-pivotField-label,
+// .collectionTreeViewChrome-pivotField-label,
+// .collection3DCarouselViewChrome-scrollSpeed-label {
+// grid-column: 1;
+// margin-right: 7px;
+// user-select: none;
+// font-family: $sans-serif;
+// letter-spacing: normal;
+// }
+
+// .collectionStackingViewChrome-sortIcon {
+// transition: transform .5s;
+// grid-column: 3;
+// text-align: center;
+// display: flex;
+// justify-content: center;
+// align-items: center;
+// cursor: pointer;
+// width: 25px;
+// height: 25px;
+// border-radius: 100%;
+// }
+
+// .collectionStackingViewChrome-sortIcon:hover {
+// background-color: $drop-shadow;
+// }
+
+// .collectionStackingViewChrome-pivotField,
+// .collectionTreeViewChrome-pivotField,
+// .collection3DCarouselViewChrome-scrollSpeed {
+// color: $white;
+// grid-column: 2;
+// grid-row: 1;
+// width: 90%;
+// min-width: 100px;
+// display: flex;
+// height: 80%;
+// border-radius: 7px;
+// align-items: center;
+// background: $white;
+
+// .editable-view-input,
+// input,
+// .editableView-container-editing-oneLine,
+// .editableView-container-editing {
+// margin: auto;
+// border: 0px;
+// color: $light-gray !important;
+// text-align: center;
+// letter-spacing: 2px;
+// outline-color: $black;
+// height: 100%;
+// }
+
+// .react-autosuggest__container {
+// margin: 0;
+// color: $medium-gray;
+// padding: 0px;
+// }
+// }
+// }
+
+// .collectionStackingViewChrome-pivotField:hover,
+// .collectionTreeViewChrome-pivotField:hover,
+// .collection3DCarouselViewChrome-scrollSpeed:hover {
+// cursor: text;
+// }
+
+// }
+// }
+
+// .collectionMenu-webUrlButtons {
+// margin-left: 44;
+// background: lightGray;
+// display: flex;
+// }
+
+// .webBox-urlEditor {
+// position: relative;
+// opacity: 0.9;
+// z-index: 901;
+// transition: top .5s;
+
+// .urlEditor {
+// display: grid;
+// grid-template-columns: 1fr auto;
+// padding-bottom: 10px;
+// overflow: hidden;
+// margin-top: 5px;
+// height: 35px;
+
+// .editorBase {
+// display: flex;
+
+// .editor-collapse {
+// transition: all .5s, opacity 0.3s;
+// position: absolute;
+// width: 40px;
+// transform-origin: top left;
+// }
+
+// .switchToText {
+// color: $medium-gray;
+// }
+
+// .switchToText:hover {
+// color: $dark-gray;
+// }
+// }
+
+// button:hover {
+// transform: scale(1);
+// }
+// }
+// }
+
+// .collectionMenu-urlInput {
+// padding: 12px 10px 11px 10px;
+// border: 0px;
+// color: $black;
+// font-size: $small-text;
+// letter-spacing: 2px;
+// outline-color: $black;
+// background: $white;
+// width: 100%;
+// min-width: 350px;
+// margin-right: 10px;
+// height: 100%;
+// }
+
+// .collectionFreeFormMenu-cont {
+// display: inline-flex;
+// position: relative;
+// align-items: center;
+// height: 100%;
+
+// .color-previewI {
+// width: 60%;
+// top: 80%;
+// position: absolute;
+// height: 4px;
+// }
+
+// .color-previewII {
+// width: 80%;
+// height: 80%;
+// margin-left: 10%;
+// position: absolute;
+// bottom: 5;
+// }
+
+// .btn-group {
+// display: grid;
+// grid-template-columns: auto auto auto auto;
+// margin: auto;
+// /* Make the buttons appear below each other */
+// }
+
+// .btn-draw {
+// display: inline-flex;
+// margin: auto;
+// /* Make the buttons appear below each other */
+// }
+
+// .fwdKeyframe,
+// .numKeyframe,
+// .backKeyframe {
+// cursor: pointer;
+// position: relative;
+// width: 20;
+// height: 30;
+// bottom: 0;
+// background: $dark-gray;
+// display: inline-flex;
+// align-items: center;
+// color: $white;
+// }
+
+// .backKeyframe {
+// svg {
+// display: block;
+// margin: auto;
+// }
+// }
+
+
+// .numKeyframe {
+// flex-direction: column;
+// padding-top: 5px;
+// }
+
+// .fwdKeyframe {
+// svg {
+// display: block;
+// margin: auto;
+// }
+
+// border-right: solid $medium-gray 1px;
+// }
+// }
+
+// .collectionSchemaViewChrome-cont {
+// display: flex;
+// font-size: $small-text;
+
+// .collectionSchemaViewChrome-toggle {
+// display: flex;
+// margin-left: 10px;
+// }
+
+// .collectionSchemaViewChrome-label {
+// text-transform: uppercase;
+// letter-spacing: 2px;
+// margin-right: 5px;
+// display: flex;
+// flex-direction: column;
+// justify-content: center;
+// }
+
+// .collectionSchemaViewChrome-toggler {
+// width: 100px;
+// height: 35px;
+// background-color: $black;
+// position: relative;
+// }
+
+// .collectionSchemaViewChrome-togglerButton {
+// width: 47px;
+// height: 30px;
+// background-color: $light-gray;
+// // position: absolute;
+// transition: all 0.5s ease;
+// // top: 3px;
+// margin-top: 3px;
+// color: $medium-gray;
+// letter-spacing: 2px;
+// text-transform: uppercase;
+// display: flex;
+// flex-direction: column;
+// justify-content: center;
+// text-align: center;
+
+// &.on {
+// margin-left: 3px;
+// }
+
+// &.off {
+// margin-left: 50px;
+// }
+// }
+// }
+
+
+// .commandEntry-outerDiv {
+// display: flex;
+// flex-direction: column;
+// height: 40px;
+// }
+
+// .commandEntry-inputArea {
+// display: flex;
+// flex-direction: row;
+// width: 150px;
+// margin: auto auto auto auto;
+// }
+
+// .react-autosuggest__container {
+// position: relative;
+// width: 100%;
+// margin-left: 5px;
+// margin-right: 5px;
+// }
+
+// .react-autosuggest__input {
+// border: 1px solid $light-gray;
+// border-radius: 4px;
+// width: 100%;
+// }
+
+// .react-autosuggest__input--focused {
+// outline: none;
+// }
+
+// .react-autosuggest__input--open {
+// border-bottom-left-radius: 0;
+// border-bottom-right-radius: 0;
+// }
+
+// .react-autosuggest__suggestions-container {
+// display: none;
+// }
+
+// .react-autosuggest__suggestions-container--open {
+// display: block;
+// position: fixed;
+// overflow-y: auto;
+// max-height: 400px;
+// width: 180px;
+// border: 1px solid $light-gray;
+// background-color: $white;
+// font-family: $sans-serif;
+// font-weight: 300;
+// font-size: $large-header;
+// border-bottom-left-radius: 4px;
+// border-bottom-right-radius: 4px;
+// z-index: 2;
+// }
+
+// .react-autosuggest__suggestions-list {
+// margin: 0;
+// padding: 0;
+// list-style-type: none;
+// }
+
+// .react-autosuggest__suggestion {
+// cursor: pointer;
+// padding: 10px 20px;
+// }
+
+// .react-autosuggest__suggestion--highlighted {
+// background-color: $light-gray;
+// } \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a9b978c4e..aefa1ec3d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -2,7 +2,7 @@ import React = require("react");
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
import { Tooltip } from "@material-ui/core";
-import { action, computed, Lambda, observable, reaction, runInAction } from "mobx";
+import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import { ColorState } from "react-color";
import { Doc, DocListCast, Opt } from "../../../fields/Doc";
@@ -15,29 +15,32 @@ import { RichTextField } from "../../../fields/RichTextField";
import { listSpec } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { DragManager } from "../../util/DragManager";
import { Scripting } from "../../util/Scripting";
import { SelectionManager } from "../../util/SelectionManager";
+import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
import { EditableView } from "../EditableView";
import { GestureOverlay } from "../GestureOverlay";
-import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, ActiveArrowStart, ActiveArrowEnd } from "../InkingStroke";
+import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
+import { LightboxView } from "../LightboxView";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DocumentView } from "../nodes/DocumentView";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
import { RichTextMenu } from "../nodes/formattedText/RichTextMenu";
import { PresBox } from "../nodes/trails/PresBox";
+import { DefaultStyleProvider } from "../StyleProvider";
+import { CollectionDockingView } from "./CollectionDockingView";
+import { CollectionLinearView } from "./collectionLinear";
import "./CollectionMenu.scss";
import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
import { TabDocView } from "./TabDocView";
-import { LightboxView } from "../LightboxView";
-import { Docs } from "../../documents/Documents";
-import { DocumentManager } from "../../util/DocumentManager";
-import { CollectionDockingView } from "./CollectionDockingView";
-import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
+import { Colors } from "../global/globalEnums";
@observer
export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -46,6 +49,8 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable SelectedCollection: DocumentView | undefined;
@observable FieldKey: string;
+ private _docBtnRef = React.createRef<HTMLDivElement>();
+
constructor(props: any) {
super(props);
this.FieldKey = "";
@@ -57,7 +62,7 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
componentDidMount() {
reaction(() => SelectionManager.Views().length && SelectionManager.Views()[0],
- (doc) => doc && this.SetSelection(doc));
+ view => view && this.SetSelection(view));
}
@action
@@ -82,30 +87,92 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
}
}
+ buttonBarXf = () => {
+ if (!this._docBtnRef.current) return Transform.Identity();
+ const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current);
+ return new Transform(-translateX, -translateY, 1 / scale);
+ }
+
+ panelWidth100 = () => 100;
+ panelHeight35 = () => 35;
+
+ @computed get contMenuButtons() {
+ trace();
+ const selDoc = Doc.UserDoc().contextMenuBtns;
+ return !(selDoc instanceof Doc) ? (null) : <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: "35px" }} >
+ <CollectionLinearView
+ Document={selDoc}
+ DataDoc={undefined}
+ fieldKey={"data"}
+ dropAction={"alias"}
+ setHeight={returnFalse}
+ styleProvider={DefaultStyleProvider}
+ layerProvider={undefined}
+ rootSelected={returnTrue}
+ bringToFront={emptyFunction}
+ select={emptyFunction}
+ isContentActive={returnTrue}
+ isAnyChildContentActive={returnFalse}
+ isSelected={returnFalse}
+ docViewPath={returnEmptyDoclist}
+ moveDocument={returnFalse}
+ CollectionView={undefined}
+ addDocument={returnFalse}
+ addDocTab={returnFalse}
+ pinToPres={emptyFunction}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={this.buttonBarXf}
+ PanelWidth={this.panelWidth100}
+ PanelHeight={this.panelHeight35}
+ renderDepth={0}
+ focus={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined} />
+ </div>;
+ }
+
render() {
- const button = <Tooltip title={<div className="dash-tooltip">Pin Menu</div>} key="pin menu" placement="bottom">
- <button className="antimodeMenu-button" onClick={this.toggleMenuPin} style={{ backgroundColor: "#121721" }}>
- <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
- </button>
- </Tooltip>;
const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel";
const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="properties" placement="bottom">
- <button className="antimodeMenu-button" key="properties" style={{ backgroundColor: "#424242" }}
+ <div className="collectionMenu-hardCodedButton"
+ style={{ backgroundColor: CurrentUserUtils.propertiesWidth > 0 ? Colors.MEDIUM_BLUE : undefined }}
+ key="properties"
onPointerDown={this.toggleProperties}>
<FontAwesomeIcon icon={propIcon} size="lg" />
- </button>
+ </div>
</Tooltip>;
- return this.getElement(!this.SelectedCollection ? [/*button*/] :
- [<CollectionViewBaseChrome key="chrome"
- docView={this.SelectedCollection}
- fieldKey={this.SelectedCollection.LayoutFieldKey}
- type={StrCast(this.SelectedCollection?.props.Document._viewType, CollectionViewType.Invalid) as CollectionViewType} />,
- prop,
- /*button*/]);
+ // NEW BUTTONS
+ //dash col linear view buttons
+ const contMenuButtons =
+ <div className="collectionMenu-container">
+ {this.contMenuButtons}
+ {prop}
+ </div>;
+
+ return contMenuButtons;
+
+ // const button = <Tooltip title={<div className="dash-tooltip">Pin Menu</div>} key="pin menu" placement="bottom">
+ // <button className="antimodeMenu-button" onClick={this.toggleMenuPin} style={{ backgroundColor: "#121721" }}>
+ // <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
+ // </button>
+ // </Tooltip>;
+
+ // OLD BUTTONS
+ // return this.getElement(!this.SelectedCollection ? [/*button*/] :
+ // [<CollectionViewBaseChrome key="chrome"
+ // docView={this.SelectedCollection}
+ // fieldKey={this.SelectedCollection.LayoutFieldKey}
+ // type={StrCast(this.SelectedCollection?.props.Document._viewType, CollectionViewType.Invalid) as CollectionViewType} />,
+ // prop,
+ // /*button*/]);
}
}
@@ -374,10 +441,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
</div>);
}
- @computed get selectedDocumentView() {
- return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
- }
- @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+ @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
+ @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
@computed get notACollection() {
if (this.selectedDoc) {
const layoutField = Doc.LayoutField(this.selectedDoc);
@@ -485,8 +550,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@undoBatch
onAliasButtonMoved = (e: PointerEvent) => {
const contentDiv = this.selectedDocumentView?.ContentDiv;
- if (contentDiv) {
- const dragData = new DragManager.DocumentDragData([this.selectedDocumentView!.props.Document]);
+ if (contentDiv && this.selectedDoc) {
+ const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y];
dragData.defaultDropAction = "alias";
dragData.canEmbed = true;
@@ -581,11 +646,9 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
}
@computed get childDocs() { return DocListCast(this.dataField); }
- @computed get selectedDocumentView() { return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; }
- @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
- @computed get isText() {
- return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
- }
+ @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
+ @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
+ @computed get isText() { return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; }
@undoBatch
@action
@@ -665,7 +728,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
}
@computed get drawButtons() {
- const func = action((i: number, keep: boolean) => {
+ const func = action((e: React.MouseEvent | React.PointerEvent, i: number, keep: boolean) => {
this._keepPrimitiveMode = keep;
if (this._selectedPrimitive !== i) {
this._selectedPrimitive = i;
@@ -683,13 +746,14 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
GestureOverlay.Instance.InkShape = "";
SetActiveBezierApprox("0");
}
+ e.stopPropagation();
});
return <div className="btn-draw" key="draw">
{this._draw.map((icon, i) =>
<Tooltip key={icon} title={<div className="dash-tooltip">{this._title[i]}</div>} placement="bottom">
<button className="antimodeMenu-button"
- onPointerDown={() => func(i, false)}
- onDoubleClick={() => func(i, true)}
+ onPointerDown={e => func(e, i, false)}
+ onDoubleClick={e => func(e, i, true)}
style={{ backgroundColor: i === this._selectedPrimitive ? "525252" : "", fontSize: "20" }}>
<FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
</button>
@@ -719,7 +783,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })}
style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}>
- </button>
+ </button>
</Tooltip>)}
</div>;
}
@@ -758,7 +822,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</div>;
}
- @observable viewType = this.selectedDoc?._viewType;
render() {
return !this.props.docView.layoutDoc ? (null) :
@@ -990,7 +1053,7 @@ export class CollectionTreeViewChrome extends React.Component<CollectionMenuProp
<button className="collectionTreeViewChrome-sort" onClick={this.toggleSort}>
<div className="collectionTreeViewChrome-sortLabel">
Sort
- </div>
+ </div>
<div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.ascending === undefined ? "90" : this.ascending ? "180" : "0"}deg)` }}>
<FontAwesomeIcon icon="caret-up" size="2x" color="white" />
</div>
@@ -1224,3 +1287,4 @@ Scripting.addGlobal(function gotoFrame(doc: any, newFrame: any) {
CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
});
+
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index e1e04915a..6a22acae8 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -18,6 +18,7 @@ import { SnappingManager } from "../../util/SnappingManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/global/globalCssVariables.scss';
+import { SchemaTable } from "../collections/collectionSchema/SchemaTable";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
import '../DocumentDecorations.scss';
@@ -25,7 +26,6 @@ import { DocumentView } from "../nodes/DocumentView";
import { DefaultStyleProvider } from "../StyleProvider";
import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { SchemaTable } from "../collections/collectionSchema/SchemaTable";
// bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
export enum ColumnType {
@@ -338,7 +338,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{this.renderColors(this._col)}
<div className="collectionSchema-headerMenu-group">
<button onClick={() => { this.deleteColumn(this._col.heading); }}
- >Delete Column</button>
+ >Hide Column</button>
</div>
</div>;
}
@@ -413,8 +413,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
isContentActive={returnTrue}
isDocumentActive={returnFalse}
ScreenToLocalTransform={this.getPreviewTransform}
- docFilters={this.docFilters}
- docRangeFilters={this.docRangeFilters}
+ docFilters={this.childDocFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
styleProvider={DefaultStyleProvider}
layerProvider={undefined}
@@ -556,7 +556,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
style={{
overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined,
- width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
+ width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 56621d6d5..eee1df921 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -141,25 +141,26 @@ export class CollectionStackedTimeline extends CollectionSubView<
}
componentWillUnmount() {
document.removeEventListener("keydown", this.keyEvents, true);
- if (CollectionStackedTimeline.SelectingRegion === this)
+ if (CollectionStackedTimeline.SelectingRegion === this) {
runInAction(
() => (CollectionStackedTimeline.SelectingRegion = undefined)
);
+ }
}
anchorStart = (anchor: Doc) =>
- NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]));
+ NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]))
anchorEnd = (anchor: Doc, val: any = null) => {
const endVal = NumCast(anchor[this.props.endTag], val);
return NumCast(
anchor._timecodeToHide,
endVal === undefined ? null : endVal
);
- };
+ }
toTimeline = (screen_delta: number, width: number) => {
return Math.max(
this.trimStart,
- Math.min(this.trimEnd, (screen_delta / width) * this.props.trimDuration + this.trimStart))
+ Math.min(this.trimEnd, (screen_delta / width) * this.props.trimDuration + this.trimStart));
}
rangeClickScript = () => CollectionStackedTimeline.RangeScript;
@@ -190,7 +191,7 @@ export class CollectionStackedTimeline extends CollectionSubView<
}
}
}
- };
+ }
getLinkData(l: Doc) {
let la1 = l.anchor1 as Doc;
@@ -279,12 +280,12 @@ export class CollectionStackedTimeline extends CollectionSubView<
this.props.setTime(((clientX - rect.x) / rect.width) * this.duration)
:
this.props.setTime(((clientX - rect.x) / rect.width) * this.props.trimDuration + this.trimStart)
- )
+ );
}
);
}
- };
+ }
@action
trimLeft = (e: React.PointerEvent): void => {
@@ -312,7 +313,7 @@ export class CollectionStackedTimeline extends CollectionSubView<
}
})
);
- };
+ }
@action
trimRight = (e: React.PointerEvent): void => {
@@ -340,7 +341,7 @@ export class CollectionStackedTimeline extends CollectionSubView<
}
})
);
- };
+ }
@undoBatch
@action
@@ -395,12 +396,13 @@ export class CollectionStackedTimeline extends CollectionSubView<
}
}
return { select: true };
- };
+ }
@action
clickAnchor = (anchorDoc: Doc, clientX: number) => {
- if (anchorDoc.isLinkButton)
+ if (anchorDoc.isLinkButton) {
LinkManager.FollowLink(undefined, anchorDoc, this.props, false);
+ }
const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25;
const endTime = this.anchorEnd(anchorDoc);
if (
@@ -415,14 +417,15 @@ export class CollectionStackedTimeline extends CollectionSubView<
this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
} else {
- if (this.layoutDoc.autoPlayAnchors)
+ if (this.layoutDoc.autoPlayAnchors) {
this.props.playFrom(seekTimeInSeconds, endTime);
+ }
else {
this.props.setTime(seekTimeInSeconds);
}
}
return { select: true };
- };
+ }
// makes sure no anchors overlaps each other by setting the correct position and width
getLevel = (
@@ -456,17 +459,17 @@ export class CollectionStackedTimeline extends CollectionSubView<
placed.push({ anchorStartTime: x1, anchorEndTime: x2, level });
return level;
- };
+ }
dictationHeightPercent = 50;
dictationHeight = () =>
- (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100;
+ (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100
timelineContentHeight = () =>
- (this.props.PanelHeight() * this.dictationHeightPercent) / 100;
+ (this.props.PanelHeight() * this.dictationHeightPercent) / 100
dictationScreenToLocalTransform = () =>
this.props
.ScreenToLocalTransform()
- .translate(0, -this.timelineContentHeight());
+ .translate(0, -this.timelineContentHeight())
@computed get renderDictation() {
const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
return !dictation ? null : (
@@ -727,17 +730,19 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
const changeAnchor = (anchor: Doc, left: boolean, time: number) => {
const timelineOnly =
Cast(anchor[this.props.startTag], "number", null) !== undefined;
- if (timelineOnly)
+ if (timelineOnly) {
Doc.SetInPlace(
anchor,
left ? this.props.startTag : this.props.endTag,
time,
true
);
- else
+ }
+ else {
left
? (anchor._timecodeToShow = time)
: (anchor._timecodeToHide = time);
+ }
return false;
};
setupMoveUpEvents(
@@ -750,13 +755,13 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
},
emptyFunction
);
- };
+ }
@action
computeTitle = () => {
const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart;
const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart;
- return `#${formatTime(start)}-${formatTime(end)}`
+ return `#${formatTime(start)}-${formatTime(end)}`;
}
renderInner = computedFn(function (
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 4b123c8b6..2f002736d 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -14,6 +14,30 @@
width: 100%;
}
+// TODO:glr Turn this into a seperate class
+.documentButtonMenu {
+ position: relative;
+ height: fit-content;
+ border-bottom: $standard-border;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ align-content: center;
+ padding: 5px 0 5px 0;
+
+ .documentExplanation {
+ width: 90%;
+ margin: 5px;
+ font-size: 11px;
+ background-color: $light-blue;
+ color: $medium-blue;
+ padding: 10px;
+ border-radius: 10px;
+ border: solid 2px $medium-blue;
+ }
+}
+
.collectionStackingView,
.collectionMasonryView {
height: 100%;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7aa8dfd56..540bfd1ef 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { CursorProperty } from "csstype";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { DataSym, Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../fields/Doc";
import { collectionSchema, documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
@@ -11,7 +11,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema";
import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils, returnTrue, returnEmptyDoclist, returnEmptyFilter } from "../../../Utils";
import { DocUtils, Docs } from "../../documents/Documents";
import { DragManager, dropActionType } from "../../util/DragManager";
import { SnappingManager } from "../../util/SnappingManager";
@@ -23,12 +23,14 @@ import { EditableView } from "../EditableView";
import { LightboxView } from "../LightboxView";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView";
-import { StyleProp } from "../StyleProvider";
+import { StyleProp, DefaultStyleProvider } from "../StyleProvider";
import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
import "./CollectionStackingView.scss";
import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
import { CollectionSubView } from "./CollectionSubView";
import { CollectionViewType } from "./CollectionView";
+import { FontIconBox } from "../nodes/button/FontIconBox";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
const _global = (window /* browser */ || global /* node */) as any;
type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
@@ -144,7 +146,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
() => this.layoutDoc._columnHeaders = new List()
);
this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight,
- () => this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
+ autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
this.headerMargin + (this.isStackingView ?
Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) :
this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0)))));
@@ -234,15 +236,16 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
rootSelected={this.rootSelected}
+ showTitle={this.props.childShowTitle}
dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
onClick={this.onChildClickHandler}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={stackedDocTransform}
focus={this.focusDocument}
- docFilters={this.docFilters}
+ docFilters={this.childDocFilters}
hideDecorationTitle={this.props.childHideDecorationTitle?.()}
hideTitle={this.props.childHideTitle?.()}
- docRangeFilters={this.docRangeFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
@@ -514,6 +517,47 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
return sections.map((section, i) => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0));
}
+ @computed get buttonMenu() {
+ const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+ // TODO:glr Allow support for multiple buttons
+ if (menuDoc) {
+ const width: number = NumCast(menuDoc._width, 30);
+ const height: number = NumCast(menuDoc._height, 30);
+ console.log(menuDoc.title, width, height);
+ return (<div className="buttonMenu-docBtn"
+ style={{ width: width, height: height }}>
+ <DocumentView
+ Document={menuDoc}
+ DataDoc={menuDoc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={() => 35}
+ PanelHeight={() => 35}
+ renderDepth={this.props.renderDepth}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ layerProvider={this.props.layerProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>
+ );
+ }
+ }
+
@computed get nativeWidth() { return this.props.NativeWidth?.() ?? Doc.NativeWidth(this.layoutDoc); }
@computed get nativeHeight() { return this.props.NativeHeight?.() ?? Doc.NativeHeight(this.layoutDoc); }
@@ -529,34 +573,50 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
SetValue: this.addGroup,
contents: "+ ADD A GROUP"
};
+ const buttonMenu = this.rootDoc.buttonMenu;
+ const noviceExplainer = this.rootDoc.explainer;
+ console.log(noviceExplainer);
return (
- <div className="collectionStackingMasonry-cont" >
- <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
- ref={this.createRef}
- style={{
- overflowY: this.props.isContentActive() ? "auto" : "hidden",
- background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
- pointerEvents: this.backgroundEvents ? "all" : undefined
- }}
- onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
- onDrop={this.onExternalDrop.bind(this)}
- onContextMenu={this.onContextMenu}
- onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} >
- {this.renderedSections}
- {!this.showAddAGroup ? (null) :
- <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
- style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
- <EditableView {...editableViewProps} />
- </div>}
- {/* {this.chromeHidden || !this.props.isSelected() ? (null) :
- <Switch
- onChange={this.onToggle}
- onClick={this.onToggle}
- defaultChecked={true}
- checkedChildren="edit"
- unCheckedChildren="view"
- />} */}
- </div> </div>
+ <>
+ {buttonMenu || noviceExplainer ? <div className="documentButtonMenu">
+ {buttonMenu ? this.buttonMenu : null}
+ {Doc.UserDoc().noviceMode && noviceExplainer ?
+ <div className="documentExplanation">
+ {noviceExplainer}
+ </div>
+ : null
+ }
+ </div> : null}
+ <div className="collectionStackingMasonry-cont" >
+ <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
+ ref={this.createRef}
+ style={{
+ overflowY: this.props.isContentActive() ? "auto" : "hidden",
+ background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
+ pointerEvents: this.backgroundEvents ? "all" : undefined
+ }}
+ onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
+ onDrop={this.onExternalDrop.bind(this)}
+ onContextMenu={this.onContextMenu}
+ onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} >
+ {this.renderedSections}
+ {!this.showAddAGroup ? (null) :
+ <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
+ style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
+ <EditableView {...editableViewProps} />
+ </div>}
+ {/* {this.chromeHidden || !this.props.isSelected() ? (null) :
+ <Switch
+ onChange={this.onToggle}
+ onClick={this.onToggle}
+ defaultChecked={true}
+ checkedChildren="edit"
+ unCheckedChildren="view"
+ />} */}
+ </div>
+ </div>
+ </>
+
);
}
}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 47733994b..58289a161 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -111,7 +111,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4");
@action pointerLeave = () => this._background = "inherit";
- textCallback = (char: string) => this.addNewTextDoc("", false, true);
+ textCallback = (char: string) => this.addNewTextDoc("-typed text-", false, true);
@action
addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a5d27f038..06d20f015 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,6 +1,6 @@
import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
import CursorField from "../../../fields/CursorField";
-import { Doc, Opt, Field, DocListCast, AclPrivate } from "../../../fields/Doc";
+import { Doc, Opt, Field, DocListCast, AclPrivate, StrListCast } from "../../../fields/Doc";
import { Id, ToString } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
@@ -8,7 +8,7 @@ import { ScriptField } from "../../../fields/ScriptField";
import { WebField } from "../../../fields/URLField";
import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { Utils, returnFalse } from "../../../Utils";
+import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { Networking } from "../../Network";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -22,6 +22,8 @@ import ReactLoading from 'react-loading';
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: Opt<CollectionView>;
+ SetSubView?: (subView: any) => void;
+ isAnyChildContentActive: () => boolean;
}
export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
@@ -30,6 +32,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
private gestureDisposer?: GestureUtils.GestureEventDisposer;
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
protected _mainCont?: HTMLDivElement;
+ @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
+ @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this.dropDisposer?.();
this.gestureDisposer?.();
@@ -45,6 +49,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.createDashEventsTarget(ele);
}
+ componentDidMount() {
+ this.props.SetSubView?.(this);
+ }
+
componentWillUnmount() {
this.gestureDisposer?.();
this._multiTouchDisposer?.();
@@ -73,23 +81,22 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
const { Document, DataDoc } = this.props;
const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
- filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys
- return pair.layout && /*!pair.layout.hidden &&*/ (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
+ filter(pair => { // filter out any documents that have a proto that we don't have permissions to
+ return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
});
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
- docFilters = () => {
- return [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
- }
- docRangeFilters = () => {
- return [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])];
- }
- searchFilterDocs = () => {
- return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)];
- }
+ collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
+ collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+ unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
+ childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
+ IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
+ this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
+ searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -108,10 +115,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
- const docFilters = this.docFilters();
- const docRangeFilters = this.docRangeFilters();
+ const childDocFilters = this.childDocFilters();
+ const docRangeFilters = this.childDocRangeFilters();
const searchDocs = this.searchFilterDocs();
- if (this.props.Document.dontRegisterView || (!docFilters.length && !docRangeFilters.length && !searchDocs.length)) {
+ if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !docRangeFilters.length && !searchDocs.length)) {
return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
}
@@ -122,24 +129,27 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const docsforFilter: Doc[] = [];
childDocs.forEach((d) => {
// if (DocUtils.Excluded(d, docFilters)) return;
- let notFiltered = d.z || Doc.IsSystem(d) || ((!searchDocs.length || searchDocs.includes(d)) && (DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0));
- const fieldKey = Doc.LayoutFieldKey(d);
- const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
- const data = d[annos ? fieldKey + "-annotations" : fieldKey];
- if (data !== undefined) {
- let subDocs = DocListCast(data);
- if (subDocs.length > 0) {
- let newarray: Doc[] = [];
- notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, docFilters, docRangeFilters, viewSpecScript, d).length);
- while (subDocs.length > 0 && !notFiltered) {
- newarray = [];
- subDocs.forEach((t) => {
- const fieldKey = Doc.LayoutFieldKey(t);
- const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
- notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!docFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], docFilters, docRangeFilters, viewSpecScript, d).length));
- DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
- });
- subDocs = newarray;
+ let notFiltered = d.z || Doc.IsSystem(d) || (DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, viewSpecScript, this.props.Document).length > 0);
+ if (notFiltered) {
+ notFiltered = ((!searchDocs.length || searchDocs.includes(d)) && (DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0));
+ const fieldKey = Doc.LayoutFieldKey(d);
+ const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
+ const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+ if (data !== undefined) {
+ let subDocs = DocListCast(data);
+ if (subDocs.length > 0) {
+ let newarray: Doc[] = [];
+ notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, viewSpecScript, d).length);
+ while (subDocs.length > 0 && !notFiltered) {
+ newarray = [];
+ subDocs.forEach((t) => {
+ const fieldKey = Doc.LayoutFieldKey(t);
+ const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
+ notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, viewSpecScript, d).length));
+ DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
+ });
+ subDocs = newarray;
+ }
}
}
}
@@ -303,7 +313,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
} else {
const path = window.location.origin + "/doc/";
if (text.startsWith(path)) {
- const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
+ const docid = text.replace(Doc.globalServerPath(), "").split("?")[0];
DocServer.GetRefField(docid).then(f => {
if (f instanceof Doc) {
if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
@@ -311,12 +321,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}
});
} else {
- let srcUrl: string | undefined;
- let srcWeb: Doc | undefined;
- if (SelectionManager.Views().length) {
- srcWeb = SelectionManager.Views()[0].props.Document;
- srcUrl = (srcWeb.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
- }
+ const srcWeb = SelectionManager.Docs().lastElement();
+ const srcUrl = (srcWeb?.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
const reg = new RegExp(Utils.prepend(""), "g");
const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 });
@@ -481,7 +487,5 @@ import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTex
import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
import { SelectionManager } from "../../util/SelectionManager";
import { OverlayView } from "../OverlayView";
-import { Hypothesis } from "../../util/HypothesisUtils";
import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
-import { FilterBox } from "../nodes/FilterBox";
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 339163510..292dfd77c 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -32,12 +32,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@observable _collapsed: boolean = false;
@observable _childClickedScript: Opt<ScriptField>;
@observable _viewDefDivClick: Opt<ScriptField>;
- @observable _focusDocFilters: Opt<string[]>; // fields that get overridden by a focus anchor
@observable _focusPivotField: Opt<string>;
- @observable _focusRangeFilters: Opt<string[]>;
getAnchor = () => {
- const anchor = Docs.Create.HTMLAnchorDocument({
+ const anchor = Docs.Create.HTMLAnchorDocument([], {
title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any,
annotationOn: this.rootDoc
});
@@ -72,9 +70,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@action
setViewSpec = (anchor: Doc, preview: boolean) => {
if (preview) { // if in preview, then override document's fields with view spec
+ this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
+ this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters);
this._focusPivotField = StrCast(anchor.pivotField);
- this._focusDocFilters = StrListCast(anchor.docFilters);
- this._focusRangeFilters = StrListCast(anchor.docRangeFilters);
} else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec
this.layoutDoc._prevFilterIndex = 1;
this.layoutDoc._pivotField = StrCast(anchor.pivotField);
@@ -84,8 +82,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
return 0;
}
- pivotDocFilters = () => this._focusDocFilters || this.props.docFilters();
- pivotDocRangeFilters = () => this._focusRangeFilters || this.props.docRangeFilters();
layoutEngine = () => this._layoutEngine;
toggleVisibility = action(() => this._collapsed = !this._collapsed);
@@ -139,10 +135,8 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : "none" }}
onClick={this.contentsDown}>
<CollectionFreeFormView {...this.props}
- engineProps={{ pivotField: this.pivotField, docFilters: this.docFilters, docRangeFilters: this.docRangeFilters }}
+ engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
fitContentsToDoc={returnTrue}
- docFilters={this.pivotDocFilters}
- docRangeFilters={this.pivotDocRangeFilters}
childClickScript={this._childClickedScript}
viewDefDivClick={this._viewDefDivClick}
childFreezeDimensions={true}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index ec461ab94..d370d21ab 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -1,5 +1,8 @@
@import "../global/globalCssVariables";
+.collectionTreeView-container {
+ transform-origin: top left;
+}
.collectionTreeView-dropTarget {
border-width: $COLLECTION_BORDER_WIDTH;
border-color: transparent;
@@ -35,6 +38,11 @@
width: max-content;
}
+ .no-indent-outline {
+ padding-left: 0;
+ width: 100%;
+ }
+
.editableView-container {
font-weight: bold;
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3eece0086..4d62a1af4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,15 +1,16 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, reaction, IReactionDisposer, observable } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
-import { DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
-import { List } from '../../../fields/List';
-import { Document } from '../../../fields/Schema';
+import { InkTool } from '../../../fields/InkField';
+import { Document, listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
+import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyFunction } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from "../../util/DragManager";
import { SelectionManager } from '../../util/SelectionManager';
@@ -25,8 +26,7 @@ import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
import { TreeView } from "./TreeView";
import React = require("react");
-import { InkTool } from '../../../fields/InkField';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { Transform } from '../../util/Transform';
const _global = (window /* browser */ || global /* node */) as any;
export type collectionTreeViewProps = {
@@ -52,6 +52,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
@computed get treeChildren() { TraceMobx(); return this.props.childDocuments || this.childDocs; }
@computed get outlineMode() { return this.doc.treeViewType === "outline"; }
@computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
+ @computed get dashboardMode() { return this.doc === Doc.UserDoc().myDashboards; }
// these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
@observable _isAnyChildContentActive = false;
@@ -61,7 +62,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
this.props.isSelected(outsideReaction) || this._isAnyChildContentActive ||
this.props.rootSelected(outsideReaction)) ? true : false)
+ isDisposing = false;
componentWillUnmount() {
+ this.isDisposing = true;
super.componentWillUnmount();
this.treedropDisposer?.();
Object.values(this._disposers).forEach(disposer => disposer?.());
@@ -76,15 +79,16 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
refList: Set<any> = new Set();
observer: any;
computeHeight = () => {
- const hgt = this.paddingTop() + 26/* bcz: ugh: title bar height hack ... get ref and compute instead */ +
- Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
- this.props.setHeight(hgt);
+ if (this.isDisposing) return;
+ const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), this.paddingTop() + this.paddingBot());
+ this.layoutDoc._autoHeightMargins = bodyHeight;
+ this.props.setHeight(this.documentTitleHeight() + bodyHeight);
}
unobserveHeight = (ref: any) => {
this.refList.delete(ref);
this.rootDoc.autoHeight && this.computeHeight();
}
- observerHeight = (ref: any) => {
+ observeHeight = (ref: any) => {
if (ref) {
this.refList.add(ref);
this.observer = new _global.ResizeObserver(action((entries: any) => {
@@ -199,6 +203,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
NativeWidth={this.documentTitleWidth}
NativeHeight={this.documentTitleHeight}
focus={this.props.focus}
+ treeViewDoc={this.props.Document}
ScreenToLocalTransform={this.titleTransform}
docFilters={returnEmptyFilter}
docRangeFilters={returnEmptyFilter}
@@ -215,6 +220,12 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
/>
</div>;
}
+ childContextMenuItems = () => {
+ const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
+ const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
+ const icons = StrListCast(this.doc.childContextMenuIcons);
+ return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
+ }
@computed get treeViewElements() {
TraceMobx();
const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
@@ -246,48 +257,109 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
true,
this.whenChildContentsActiveChanged,
this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null),
- this.observerHeight,
- this.unobserveHeight);
+ this.observeHeight,
+ this.unobserveHeight,
+ this.childContextMenuItems()
+ );
}
@computed get titleBar() {
const hideTitle = this.props.treeViewHideTitle || this.doc.treeViewHideTitle;
- return hideTitle ? (null) : (this.doc.treeViewType === "outline" ? this.documentTitle : this.editableTitle)(this.treeChildren);
+ return hideTitle ? (null) : (this.outlineMode ? this.documentTitle : this.editableTitle)(this.treeChildren);
}
- @computed get renderClearButton() {
- return !this.doc.treeViewShowClearButton ? (null) : <div key="toolbar">
- <button className="toolbar-button round-button" title="Empty" onClick={undoBatch(action(() => Doc.GetProto(this.doc)[this.props.fieldKey] = undefined))}>
- <FontAwesomeIcon icon={"trash"} size="sm" />
- </button>
- </div >;
+ @computed get buttonMenu() {
+ const menuDoc:Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+ // To create a multibutton menu add a CollectionLinearView
+ if (menuDoc){
+
+ const width: number = NumCast(menuDoc._width, 30);
+ const height: number = NumCast(menuDoc._height, 30);
+ console.log(menuDoc.title, width, height);
+ return (<div className="buttonMenu-docBtn"
+ style = {{width: width, height: height}}>
+ <DocumentView
+ Document={menuDoc}
+ DataDoc={menuDoc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={() => 35}
+ PanelHeight={() => 35}
+ renderDepth={this.props.renderDepth + 1}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ layerProvider={this.props.layerProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ />
+ </div>);
+ }
}
+
+ @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); }
+ @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); }
+
+ @computed get contentScaling() {
+ const nw = this.nativeWidth;
+ const nh = this.nativeHeight;
+ const hscale = nh ? this.props.PanelHeight() / nh : 1;
+ const wscale = nw ? this.props.PanelWidth() / nw : 1;
+ return wscale < hscale ? wscale : hscale;
+ }
paddingX = () => NumCast(this.doc._xPadding, 15);
paddingTop = () => NumCast(this.doc._yPadding, 20);
+ paddingBot = () => NumCast(this.doc._yPadding, 20);
documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth());
- documentTitleHeight = () => Math.min(this.layoutDoc?.[HeightSym](), (StrCast(this.layoutDoc?._fontSize) ? Number(StrCast(this.layoutDoc?._fontSize, "32px").replace("px", "")) : NumCast(this.layoutDoc?._fontSize)) * 2);
+ documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins);
titleTransform = () => this.props.ScreenToLocalTransform().translate(-NumCast(this.doc._xPadding, 10), -NumCast(this.doc._yPadding, 20));
truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
- panelWidth = () => this.props.PanelWidth() - 2 * this.paddingX();
+ panelWidth = () => (this.props.PanelWidth() - 2 * this.paddingX()) * (this.props.scaling?.() || 1);
render() {
TraceMobx();
const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined;
+ const buttonMenu = this.rootDoc.buttonMenu;
+ const noviceExplainer = this.rootDoc.explainer;
return !(this.doc instanceof Doc) || !this.treeChildren ? (null) :
- <div className="collectionTreeView-container" onContextMenu={this.onContextMenu}>
- <div className="collectionTreeView-dropTarget"
- style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }}
- onWheel={e => e.stopPropagation()}
- onDrop={this.onTreeDrop}
- ref={this.createTreeDropTarget}>
+ <>
{this.titleBar}
- {this.renderClearButton}
- <ul className="no-indent">
- {this.treeViewElements}
- </ul>
- </div >
- </div>;
+ <div className="collectionTreeView-container"
+ style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}}
+ onContextMenu={this.onContextMenu}>
+ {buttonMenu || noviceExplainer ? <div className="documentButtonMenu">
+ {buttonMenu ? this.buttonMenu : null}
+ {Doc.UserDoc().noviceMode && noviceExplainer ?
+ <div className="documentExplanation">
+ {noviceExplainer}
+ </div>
+ : null
+ }
+ </div> : null}
+ <div className="collectionTreeView-dropTarget"
+ style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }}
+ onWheel={e => e.stopPropagation()}
+ onDrop={this.onTreeDrop}
+ ref={this.createTreeDropTarget}>
+ <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} >
+ {this.treeViewElements}
+ </ul>
+ </div >
+ </div>
+ </>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index e225c4a11..bc02c44f0 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,4 @@
-import { computed, observable, runInAction } from 'mobx';
+import { computed, observable, runInAction, action } from 'mobx';
import { observer } from "mobx-react";
import * as React from 'react';
import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
@@ -24,7 +24,7 @@ import { CollectionCarouselView } from './CollectionCarouselView';
import { CollectionDockingView } from "./CollectionDockingView";
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import { CollectionGridView } from './collectionGrid/CollectionGridView';
-import { CollectionLinearView } from './CollectionLinearView';
+import { CollectionLinearView } from './collectionLinear';
import CollectionMapView from './CollectionMapView';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
@@ -36,6 +36,8 @@ import { CollectionTimeView } from './CollectionTimeView';
import { CollectionTreeView } from "./CollectionTreeView";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import './CollectionView.scss';
+import { returnEmptyString } from '../../../Utils';
+import { InkTool } from '../../../fields/InkField';
export const COLLECTION_BORDER_WIDTH = 2;
const path = require('path');
@@ -62,14 +64,16 @@ export enum CollectionViewType {
export interface CollectionViewProps extends FieldViewProps {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
layoutEngine?: () => string;
- setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+ setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
// property overrides for child documents
children?: never | (() => JSX.Element[]) | React.ReactNode;
childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
childDocumentsActive?: () => boolean;// whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
childFitWidth?: () => boolean;
+ childShowTitle?: () => string;
childOpacity?: () => number;
+ childContextMenuItems?: () => { script: ScriptField, label: string }[];
childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children
childHideDecorationTitle?: () => boolean;
childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection
@@ -83,7 +87,7 @@ export interface CollectionViewProps extends FieldViewProps {
type CollectionDocument = makeInterface<[typeof documentSchema]>;
const CollectionDocument = makeInterface(documentSchema);
@observer
-export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument, "") {
+export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
@observable private static _safeMode = false;
@@ -91,6 +95,11 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+ constructor(props: any) {
+ super(props);
+ runInAction(() => this._annotationKeySuffix = returnEmptyString);
+ }
+
get collectionViewType(): CollectionViewType | undefined {
const viewField = StrCast(this.layoutDoc._viewType);
if (CollectionView._safeMode) {
@@ -112,7 +121,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
// const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
// const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
// return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
- this.isContentActive();
+ //this.isContentActive();
}
screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
@@ -186,15 +195,20 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
}
!Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" });
- optionItems.push({
- description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram"
- });
- optionItems.push({
- description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram"
- });
- optionItems.push({
- description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram"
- });
+ if (!Doc.UserDoc().noviceMode) {
+ optionItems.push({
+ description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram"
+ });
+ optionItems.push({
+ description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram"
+ });
+ optionItems.push({
+ description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram"
+ });
+ }
+ if (this.Document._viewType === CollectionViewType.Docking) {
+ optionItems.push({ description: "Create Dashboard", event: () => CurrentUserUtils.createNewDashboard(Doc.UserDoc()), icon: "project-diagram" });
+ }
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" });
@@ -236,17 +250,25 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
* Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard.
*/
@computed get showFilterIcon() {
- return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && ((StrListCast(this.props.Document._docFilters).length || StrListCast(this.props.Document._docRangeFilters).length || StrListCast(CurrentUserUtils.ActiveDashboard._docFilters).length || StrListCast(CurrentUserUtils.ActiveDashboard._docRangeFilters).length));
+ return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered();
}
+ @observable _subView: any = undefined;
+
+ isContentActive = (outsideReaction?: boolean) => {
+ return this.props.isContentActive() ? true : false;
+ }
render() {
TraceMobx();
const props: SubCollectionViewProps = {
...this.props,
+ SetSubView: action((subView: any) => this._subView = subView),
addDocument: this.addDocument,
moveDocument: this.moveDocument,
removeDocument: this.removeDocument,
isContentActive: this.isContentActive,
+ isAnyChildContentActive: this.isAnyChildContentActive,
+ whenChildContentsActiveChanged: this.whenChildContentsActiveChanged,
PanelWidth: this.bodyPanelWidth,
PanelHeight: this.props.PanelHeight,
ScreenToLocalTransform: this.screenToLocalTransform,
@@ -260,8 +282,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
{this.showFilterIcon ?
<FontAwesomeIcon icon={"filter"} size="lg"
- style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: '#18c718bd', zIndex: 1 }}
- onPointerDown={e => { runInAction(() => CurrentUserUtils.propertiesWidth = 250); e.stopPropagation(); }}
+ style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }}
+ onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })}
/>
: (null)}
</div>);
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index a963f1cb9..7f62ecaa0 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -1,3 +1,6 @@
+@import "../global/globalCssVariables.scss";
+
+
input.lm_title:focus,
input.lm_title {
max-width: unset !important;
@@ -57,12 +60,11 @@ input.lm_title {
}
}
-.miniMap-hidden,
.miniMap {
position: absolute;
overflow: hidden;
- right: 10;
- bottom: 10;
+ right: 15;
+ bottom: 15;
border: solid 1px;
box-shadow: black 0.4vw 0.4vw 0.8vw;
width: 100%;
@@ -82,17 +84,21 @@ input.lm_title {
}
.miniMap-hidden {
+ cursor: pointer;
position: absolute;
- bottom: 0;
- right: 0;
- width: 45px;
- height: 45px;
- transform: translate(20px, 20px) rotate(45deg);
- border-radius: 30px;
+ bottom: 5;
+ display: flex;
+ right: 5;
+ width: 25px;
+ height: 25px;
+ border-radius: 3px;
padding: 2px;
+ justify-content: center;
+ align-items: center;
+ align-content: center;
+ background-color: $light-gray;
- >svg {
- margin-top: 3px;
- transform: translate(0px, 7px);
+ &:hover {
+ box-shadow: none;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index a24f1eb7a..f63e5f844 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -11,7 +11,6 @@ import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym }
import { Id } from '../../../fields/FieldSymbols';
import { FieldId } from "../../../fields/RefField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { TraceMobx } from '../../../fields/util';
import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { DocUtils } from '../../documents/Documents';
@@ -34,6 +33,7 @@ import { CollectionView, CollectionViewType } from './CollectionView';
import "./TabDocView.scss";
import React = require("react");
import Color = require('color');
+import { Colors, Shadows } from '../global/globalEnums';
const _global = (window /* browser */ || global /* node */) as any;
interface TabDocViewProps {
@@ -124,6 +124,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
tab.element[0].prepend(iconWrap);
tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
({ layer, color }) => {
+ // console.log("TabDocView: " + this.tabColor);
+ // console.log("lightOrDark: " + lightOrDark(this.tabColor));
const textColor = lightOrDark(this.tabColor); //not working with StyleProp.Color
titleEle.style.color = textColor;
titleEle.style.backgroundColor = "transparent";
@@ -132,12 +134,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
moreInfoDrag.style.backgroundColor = textColor;
tab.element[0].style.background = !layer ? color : "dimgrey";
}, { fireImmediately: true });
- // TODO:glr fix
- // tab.element[0].style.borderTopRightRadius = "8px";
- // tab.element[0].children[1].appendChild(toggle);
- // tab._disposers.layerDisposer = reaction(() =>
- // ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
- // ({ layer, color }) => toggle.style.background = !layer ? color : "dimgrey", { fireImmediately: true });
}
// shifts the focus to this tab when another tab is dragged over it
tab.element[0].onmouseenter = (e: MouseEvent) => {
@@ -171,10 +167,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
//attach the selection doc buttons menu to the drag handle
const stack: HTMLDivElement = tab.contentItem.parent;
const header: HTMLDivElement = tab;
- console.log("Stack: " + stack.id, stack.className)
stack.onscroll = action((e: any) => {
- console.log('scrolling...')
- })
+ console.log('scrolling...');
+ });
const moreInfoDrag = document.createElement("div");
moreInfoDrag.className = "lm_iconWrap";
tab._disposers.buttonDisposer = reaction(() => this.view, view =>
@@ -314,6 +309,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
}
}
+ remDocTab = (doc: Doc | Doc[]) => {
+ if (doc === this._document) {
+ SelectionManager.DeselectAll();
+ CollectionDockingView.CloseSplit(this._document);
+ return true;
+ }
+ return false;
+ }
getCurrentFrame = () => {
return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
@@ -350,7 +353,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); }
@computed get docView() {
- TraceMobx();
return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
<><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
renderDepth={0}
@@ -363,11 +365,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
PanelHeight={this.PanelHeight}
layerProvider={this.layerProvider}
styleProvider={DefaultStyleProvider}
- docFilters={CollectionDockingView.Instance.docFilters}
- docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
+ docFilters={CollectionDockingView.Instance.childDocFilters}
+ docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
addDocument={undefined}
- removeDocument={undefined}
+ removeDocument={this.remDocTab}
addDocTab={this.addDocTab}
ScreenToLocalTransform={this.ScreenToLocalTransform}
dontCenter={"y"}
@@ -385,8 +387,16 @@ export class TabDocView extends React.Component<TabDocViewProps> {
background={this.miniMapColor}
document={this._document}
tabView={this.tabView} />
- <Tooltip style={{ display: this.disableMinimap() ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
- <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+ <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.hideMinimap ? "Open minimap" : "Close minimap"}</div>}>
+ <div className="miniMap-hidden"
+ style={{
+ display: this.disableMinimap() || this._document._viewType !== "freeform" ? "none" : undefined,
+ color: this._document.hideMinimap ? Colors.BLACK : Colors.WHITE,
+ backgroundColor: this._document.hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
+ boxShadow: this._document.hideMinimap ? Shadows.STANDARD_SHADOW : undefined
+ }}
+ onPointerDown={e => e.stopPropagation()}
+ onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
<FontAwesomeIcon icon={"globe-asia"} size="lg" />
</div>
</Tooltip>
@@ -394,7 +404,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
render() {
- this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
return (
<div className="collectionDockingView-content" style={{
fontFamily: Doc.UserDoc().renderStyle === "comic" ? "Comic Sans MS" : undefined,
@@ -430,7 +439,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
case StyleProp.DocContents:
const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" :
doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : "gray";
- return doc.type === DocumentType.COL ?
+ return doc.type === DocumentType.COL || doc.type === DocumentType.INK ?
undefined :
<div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: "absolute", display: "block", background }} />;
}
@@ -468,6 +477,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
<div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
<CollectionFreeFormView
Document={this.props.document}
+ SetSubView={() => this}
CollectionView={undefined}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
@@ -475,7 +485,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
noOverlay={true} // don't render overlay Docs since they won't scale
setHeight={returnFalse}
- isContentActive={returnTrue}
+ isContentActive={returnFalse}
+ isAnyChildContentActive={returnFalse}
select={emptyFunction}
dropAction={undefined}
isSelected={returnFalse}
@@ -496,8 +507,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
layerProvider={undefined}
addDocTab={this.props.addDocTab}
pinToPres={TabDocView.PinDoc}
- docFilters={CollectionDockingView.Instance.docFilters}
- docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
+ docFilters={CollectionDockingView.Instance.childDocFilters}
+ docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
fitContentsToDoc={returnTrue}
/>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 401bdcb02..8cf34ddcc 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,7 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
-import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym, StrListCast } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { RichTextField } from '../../../fields/RichTextField';
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils, returnOne } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -54,6 +54,7 @@ export interface TreeViewProps {
indentDocument?: (editTitle: boolean) => void;
outdentDocument?: (editTitle: boolean) => void;
ScreenToLocalTransform: () => Transform;
+ contextMenuItems: { script: ScriptField, filter: ScriptField, label: string }[];
dontRegisterView?: boolean;
styleProvider?: StyleProviderFunc | undefined;
treeViewHideHeaderFields: () => boolean;
@@ -99,13 +100,14 @@ export class TreeView extends React.Component<TreeViewProps> {
@observable _dref: DocumentView | undefined | null;
get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
get defaultExpandedView() {
- return this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "aliases") :
- this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
+ return this.doc.viewType === CollectionViewType.Docking ? this.fieldKey :
+ this.props.treeView.fileSysMode ? (this.doc.isFolder ? this.fieldKey : "layout") :
+ this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.UserDoc().noviceMode ? "layout" : StrCast(this.props.treeView.doc.treeViewExpandedView, "fields");
}
@computed get doc() { return this.props.document; }
@computed get treeViewOpen() { return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._transientOpenState; }
- @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.defaultExpandedView); }
+ @computed get treeViewExpandedView() { return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; }
@computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
@computed get dataDoc() { return this.doc[DataSym]; }
@computed get layoutDoc() { return Doc.Layout(this.doc); }
@@ -151,7 +153,10 @@ export class TreeView extends React.Component<TreeViewProps> {
this.treeViewOpen = !this.treeViewOpen;
} else {
// choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias
- this.props.addDocTab(this.props.document, "add:right");
+ // this.props.addDocTab(CurrentUserUtils.ActiveDashboard.isShared ? Doc.MakeAlias(this.props.document) : this.props.document, "add:right");
+ const bestAlias = DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+ this.props.addDocTab(bestAlias ?? Doc.MakeAlias(this.props.document), "add:right");
+
}
}
constructor(props: any) {
@@ -291,7 +296,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const aspect = Doc.NativeAspect(layoutDoc);
if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]());
if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth()));
- return Math.min(this.props.panelWidth() - treeBulletWidth(), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
+ return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
}
docHeight = () => {
const layoutDoc = this.layoutDoc;
@@ -333,7 +338,7 @@ export class TreeView extends React.Component<TreeViewProps> {
this.props.dropAction, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.isContentActive,
this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
[...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView, emptyFunction, emptyFunction);
+ this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems());
} else {
contentElement = <EditableView key="editableView"
contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -360,7 +365,7 @@ export class TreeView extends React.Component<TreeViewProps> {
return rows;
}
- rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.props.panelWidth() - treeBulletWidth());
+ rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), (this.props.panelWidth() - treeBulletWidth())) / (this.props.treeView.props.scaling?.() || 1);
rtfHeight = () => this.rtfWidth() <= this.layoutDoc?.[WidthSym]() ? Math.min(this.layoutDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth());
expandPanelHeight = () => {
@@ -415,7 +420,7 @@ export class TreeView extends React.Component<TreeViewProps> {
StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform,
this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields,
[...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged,
- this.props.dontRegisterView, emptyFunction, emptyFunction)}
+ this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())}
</ul >;
} else if (this.treeViewExpandedView === "fields") {
return <ul key={this.doc[Id] + this.doc.title}>
@@ -472,16 +477,20 @@ export class TreeView extends React.Component<TreeViewProps> {
</div>;
}
+ @computed get validExpandViewTypes() {
+ if (this.doc.viewType === CollectionViewType.Docking) return [this.fieldKey];
+ const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" : "";
+ const links = () => DocListCast(this.doc.links).length ? "links" : "";
+ const data = () => this.childDocs && !this.props.treeView.dashboardMode ? this.fieldKey : "";
+ const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases";
+ const fields = () => Doc.UserDoc().noviceMode ? "" : "fields";
+ return [data(), "layout", ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m);
+ }
@action
expandNextviewType = () => {
if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeViewExpandedViewLock) {
- const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.doc.treeViewExpandedView)) + 1) % modes.length];
- const annos = () => DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" : "";
- const links = () => DocListCast(this.doc.links).length ? "links" : "";
- const children = () => this.childDocs ? this.fieldKey : "";
- this.doc.treeViewExpandedView = next(this.props.treeView.fileSysMode ?
- (Doc.UserDoc().noviceMode ? ["layout", "aliases"] : ["layout", "aliases", "fields"]) :
- (Doc.UserDoc().noviceMode ? [children(), "layout"] : [children(), "fields", "layout", links(), annos()]).filter(mode => mode));
+ const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length];
+ this.doc.treeViewExpandedView = next(this.validExpandViewTypes);
}
this.treeViewOpen = true;
}
@@ -504,13 +513,23 @@ export class TreeView extends React.Component<TreeViewProps> {
}
contextMenuItems = () => {
const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" };
- return this.doc.isFolder ? [makeFolder] :
+ const openAlias = { script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" };
+ const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" };
+ return [...this.props.contextMenuItems.filter(mi => !mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result), ... (this.doc.isFolder ? [makeFolder] :
Doc.IsSystem(this.doc) ? [] :
this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
- [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }, makeFolder] :
- [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }];
+ [openAlias, makeFolder] :
+ this.doc.viewType === CollectionViewType.Docking ? [] :
+ [openAlias, focusDoc])];
+ }
+ childContextMenuItems = () => {
+ const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []);
+ const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []);
+ const icons = StrListCast(this.doc.childContextMenuIcons);
+ return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
}
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
+
onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document);
@@ -526,7 +545,7 @@ export class TreeView extends React.Component<TreeViewProps> {
switch (property.split(":")[0]) {
case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1;
case StyleProp.BackgroundColor: return this.selected ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
- case StyleProp.DocContents: return testDocProps(props) && !props?.treeViewDoc ? (null) :
+ case StyleProp.DocContents: return this.props.treeView.outlineMode ? (null) :
<div className="treeView-label" style={{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props')
maxWidth: props?.PanelWidth() || undefined,
background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor),
@@ -628,6 +647,7 @@ export class TreeView extends React.Component<TreeViewProps> {
searchFilterDocs={returnEmptyDoclist}
ContainingCollectionView={undefined}
ContainingCollectionDoc={this.props.treeView.props.Document}
+ ContentScaling={returnOne}
/>;
const buttons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""));
@@ -684,10 +704,12 @@ export class TreeView extends React.Component<TreeViewProps> {
hideDecorationTitle={this.props.treeView.outlineMode}
hideResizeHandles={this.props.treeView.outlineMode}
focus={this.refocus}
+ ContentScaling={returnOne}
hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
ScreenToLocalTransform={this.docTransform}
renderDepth={this.props.renderDepth + 1}
+ treeViewDoc={this.props.treeView?.props.Document}
rootSelected={returnTrue}
layerProvider={returnTrue}
docViewPath={this.props.treeView.props.docViewPath}
@@ -813,7 +835,8 @@ export class TreeView extends React.Component<TreeViewProps> {
whenChildContentsActiveChanged: (isActive: boolean) => void,
dontRegisterView: boolean | undefined,
observerHeight: (ref: any) => void,
- unobserveHeight: (ref: any) => void
+ unobserveHeight: (ref: any) => void,
+ contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[])
) {
const viewSpecScript = Cast(conainerCollection.viewSpecScript, ScriptField);
if (viewSpecScript) {
@@ -878,6 +901,7 @@ export class TreeView extends React.Component<TreeViewProps> {
parentTreeView={parentTreeView}
observeHeight={observerHeight}
unobserveHeight={unobserveHeight}
+ contextMenuItems={contextMenuItems}
/>;
});
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index a8f5e6dd2..3b3e069d8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -2,14 +2,16 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx"
import { observer } from "mobx-react";
import { Doc } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
+import { List } from "../../../../fields/List";
import { NumCast, StrCast } from "../../../../fields/Types";
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
-import { DocumentType } from "../../../documents/DocumentTypes";
+import { LinkManager } from "../../../util/LinkManager";
import { SnappingManager } from "../../../util/SnappingManager";
import { DocumentView } from "../../nodes/DocumentView";
import "./CollectionFreeFormLinkView.scss";
import React = require("react");
+
export interface CollectionFreeFormLinkViewProps {
A: DocumentView;
B: DocumentView;
@@ -40,8 +42,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if (SnappingManager.GetIsDragging() || !A.ContentDiv || !B.ContentDiv) return;
setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
setTimeout(action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
- const acont = A.rootDoc.type === DocumentType.LINK ? A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : [];
- const bcont = B.rootDoc.type === DocumentType.LINK ? B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : [];
+ const acont = A.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
+ const bcont = B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
const adiv = acont.length ? acont[0] : A.ContentDiv;
const bdiv = bcont.length ? bcont[0] : B.ContentDiv;
const a = adiv.getBoundingClientRect();
@@ -66,8 +68,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
} else {
const m = targetAhyperlink.getBoundingClientRect();
const mp = A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- linkDoc.anchor1_x = Math.min(1, mp[0] / A.props.PanelWidth()) * 100;
- linkDoc.anchor1_y = Math.min(1, mp[1] / A.props.PanelHeight()) * 100;
+ const mpx = mp[0] / A.props.PanelWidth();
+ const mpy = mp[1] / A.props.PanelHeight();
+ if (mpx >= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100;
+ if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100;
}
if (!targetBhyperlink) {
if (linkDoc.linkAutoMove) {
@@ -77,8 +81,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
} else {
const m = targetBhyperlink.getBoundingClientRect();
const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- linkDoc.anchor2_x = Math.min(1, mp[0] / B.props.PanelWidth()) * 100;
- linkDoc.anchor2_y = Math.min(1, mp[1] / B.props.PanelHeight()) * 100;
+ const mpx = mp[0] / B.props.PanelWidth();
+ const mpy = mp[1] / B.props.PanelHeight();
+ if (mpx >= 0 && mpx <= 1) linkDoc.anchor2_x = mpx * 100;
+ if (mpy >= 0 && mpy <= 1) linkDoc.anchor2_y = mpy * 100;
}
}
@@ -137,8 +143,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if (!A.ContentDiv || !B.ContentDiv || !LinkDocs.length) return undefined;
const acont = A.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
const bcont = B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
- const adiv = (acont.length ? acont[0] : A.ContentDiv);
- const bdiv = (bcont.length ? bcont[0] : B.ContentDiv);
+ const adiv = acont.length ? acont[0] : A.ContentDiv;
+ const bdiv = bcont.length ? bcont[0] : B.ContentDiv;
for (let apdiv = adiv; apdiv; apdiv = apdiv.parentElement as any) if ((apdiv as any).hidden) return;
for (let bpdiv = bdiv; bpdiv; bpdiv = bpdiv.parentElement as any) if ((bpdiv as any).hidden) return;
const a = adiv.getBoundingClientRect();
@@ -173,8 +179,14 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
render() {
if (!this.renderData) return (null);
const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
+ LinkManager.currentLink = this.props.LinkDocs[0];
+ const linkRelationship = StrCast(LinkManager.currentLink?.linkRelationship); //get string representing relationship
+ const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
+ const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+ //access stroke color using index of the relationship in the color list (default black)
+ const strokeColor = linkRelationshipList.indexOf(linkRelationship) === -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)];
return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
- <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
+ <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }}
d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
{textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
{StrCast(this.props.LinkDocs[0].description)}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 5e0b31754..dacbb3508 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,29 +1,17 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
-import { Utils } from "../../../../Utils";
import { DocumentManager } from "../../../util/DocumentManager";
-import { DocumentView } from "../../nodes/DocumentView";
import "./CollectionFreeFormLinksView.scss";
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
-import { DocumentType } from "../../../documents/DocumentTypes";
@observer
export class CollectionFreeFormLinksView extends React.Component {
@computed get uniqueConnections() {
- const connections = DocumentManager.Instance.LinkedDocumentViews
- .filter(c => c.a.props.Document.type === DocumentType.LINK || c.b.props.Document.type === DocumentType.LINK)
- .reduce((drawnPairs, connection) => {
- const matchingPairs = drawnPairs.filter(pair => connection.a === pair.a && connection.b === pair.b);
- matchingPairs.forEach(drawnPair => drawnPair.l.add(connection.l));
- if (!matchingPairs.length) drawnPairs.push({ a: connection.a, b: connection.b, l: new Set<Doc>([connection.l]) });
- return drawnPairs;
- }, [] as { a: DocumentView, b: DocumentView, l: Set<Doc> }[]);
- const set = new Map<Doc, { a: DocumentView, b: DocumentView, l: Doc[] }>();
- connections.map(c => !set.has(Array.from(c.l)[0]) && set.set(Array.from(c.l)[0], { a: c.a, b: c.b, l: Array.from(c.l) }));
- return Array.from(set.values()).map(c => <CollectionFreeFormLinkView key={c.l[0][Id]} A={c.a} B={c.b} LinkDocs={c.l} />);
+ return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c =>
+ <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />
+ );
}
render() {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 143d8e070..c8561d901 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,7 @@
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
+import { DateField } from "../../../../fields/DateField";
import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas";
import { Id } from "../../../../fields/FieldSymbols";
@@ -17,6 +18,7 @@ import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUp
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
import { DragManager, dropActionType } from "../../../util/DragManager";
@@ -48,7 +50,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso
import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
-import { DocumentType } from "../../../documents/DocumentTypes";
+import Color = require("color");
export const panZoomSchema = createSchema({
_panX: "number",
@@ -73,6 +75,8 @@ export type collectionFreeformViewProps = {
scaleField?: string;
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
engineProps?: any;
+ dontRenderDocuments?: boolean; // used for annotation overlays which need to distribute documents into different freeformviews with different mixBlendModes depending on whether they are trnasparent or not.
+ // However, this screws up interactions since only the top layer gets events. so we render the freeformview a 3rd time with all documents in order to get interaction events (eg., marquee) but we don't actually want to display the documents.
};
@observer
@@ -110,13 +114,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeRef = React.createRef<HTMLDivElement>();
@observable _keyframeEditing = false;
- @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
- @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
@observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
@computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
@computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
- @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); }
+ @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); }
@computed get fitToContentVals() {
return {
bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -159,8 +161,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.layoutDoc._viewScale = vals.scale;
}
freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined;
- freeformDocFilters = () => this._focusFilters || this.docFilters();
- freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters();
reverseNativeScaling = () => this.fitToContent ? true : false;
panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX);
panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY);
@@ -171,6 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getContainerTransform = () => this.cachedGetContainerTransform.copy();
getTransformOverlay = () => this.getContainerTransform().translate(1, 1);
getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
+ isAnyChildContentActive = () => this.props.isAnyChildContentActive();
addLiveTextBox = (newBox: Doc) => {
FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
this.addDocument(newBox);
@@ -261,6 +262,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
}
+ d._lastModified = new DateField();
const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
layoutDoc._width = NumCast(layoutDoc._width, 300);
layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
@@ -508,7 +510,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const points = ge.points;
const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points,
- { title: "ink stroke", x: B.x - Number(ActiveInkWidth()) / 2, y: B.y - Number(ActiveInkWidth()) / 2, _width: B.width + Number(ActiveInkWidth()), _height: B.height + Number(ActiveInkWidth()) });
+ { title: "ink stroke", x: B.x - ActiveInkWidth() / 2, y: B.y - ActiveInkWidth() / 2, _width: B.width + ActiveInkWidth(), _height: B.height + ActiveInkWidth() });
this.addDocument(inkDoc);
e.stopPropagation();
break;
@@ -1030,10 +1032,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
ScreenToLocalTransform={childLayout.z ? this.getTransformOverlay : this.getTransform}
PanelWidth={childLayout[WidthSym]}
PanelHeight={childLayout[HeightSym]}
- docFilters={this.freeformDocFilters}
- docRangeFilters={this.freeformRangeDocFilters}
+ docFilters={this.childDocFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
- isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
+ isContentActive={returnFalse}
isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
focus={this.focusDocument}
addDocTab={this.addDocTab}
@@ -1050,7 +1052,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
freezeDimensions={this.props.childFreezeDimensions}
dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
bringToFront={this.bringToFront}
- dontRegisterView={this.props.dontRegisterView}
+ showTitle={this.props.childShowTitle}
+ dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
(this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
jitterRotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
@@ -1197,15 +1200,22 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (preview) {
this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters);
- } else if (anchor.pivotField !== undefined) {
- this.layoutDoc._docFilters = new List<string>(StrListCast(anchor.docFilters));
- this.layoutDoc._docRangeFilters = new List<string>(StrListCast(anchor.docRangeFilters));
+ } else {
+ if (anchor.docFilters) {
+ this.layoutDoc._docFilters = new List<string>(StrListCast(anchor.docFilters));
+ }
+ if (anchor.docRangeFilters) {
+ this.layoutDoc._docRangeFilters = new List<string>(StrListCast(anchor.docRangeFilters));
+ }
}
return 0;
}
getAnchor = () => {
- const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc });
+ if (this.props.Document.annotationOn) {
+ return this.rootDoc;
+ }
+ const anchor = Docs.Create.TextanchorDocument({ title: "ViewSpec - " + StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc });
const proto = Doc.GetProto(anchor);
proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType;
proto.docFilters = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List<string>([]);
@@ -1447,8 +1457,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getContainerTransform={this.getContainerTransform}
getTransform={this.getTransform}
isAnnotationOverlay={this.isAnnotationOverlay}>
- <div ref={this._marqueeRef}>
- {this.layoutDoc["_backgroundGrid-show"] ? this.backgroundGrid : (null)}
+ <div ref={this._marqueeRef} style={{ display: this.props.dontRenderDocuments ? "none" : undefined }}>
+ {this.layoutDoc._backgroundGridShow ? this.backgroundGrid : (null)}
<CollectionFreeFormViewPannableContents
isAnnotationOverlay={this.isAnnotationOverlay}
transform={this.contentTransform}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 846d28214..81f6307d1 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,6 +1,6 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { AclAugment, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
@@ -41,7 +41,7 @@ interface MarqueeViewProps {
trySelectCluster: (addToSel: boolean) => boolean;
nudge?: (x: number, y: number, nudgeTime?: number) => boolean;
ungroup?: () => void;
- setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+ setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
}
@observer
export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
@@ -92,7 +92,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: "bing", useCors: true }), "add:right"));
- cm.displayMenu(this._downX, this._downY);
+ cm.displayMenu(this._downX, this._downY, undefined, true);
e.stopPropagation();
} else
if (e.key === "u" && this.props.ungroup) {
@@ -211,7 +211,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
// allow marquee if right click OR alt+left click
if (e.button === 2 || (e.button === 0 && e.altKey)) {
// if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) {
- this.setPreviewCursor(e.clientX, e.clientY, true);
+ this.setPreviewCursor(e.clientX, e.clientY, true, false);
// (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors.
e.preventDefault();
// }
@@ -284,8 +284,13 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
else if (document.getSelection()) { document.getSelection()?.empty(); }
}
- setPreviewCursor = action((x: number, y: number, drag: boolean) => {
- if (drag) {
+ setPreviewCursor = action((x: number, y: number, drag: boolean, hide: boolean) => {
+ if (hide) {
+ this._downX = this._lastX = x;
+ this._downY = this._lastY = y;
+ this._commandExecuted = false;
+ PreviewCursor.Visible = false;
+ } else if (drag) {
this._downX = this._lastX = x;
this._downY = this._lastY = y;
this._commandExecuted = false;
@@ -298,7 +303,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._downX = x;
this._downY = y;
const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
- if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl)) {
+ if ([AclAdmin, AclEdit, AclAugment].includes(effectiveAcl)) {
PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
}
this.clearSelection();
@@ -313,7 +318,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (!(e.nativeEvent as any).marqueeHit) {
(e.nativeEvent as any).marqueeHit = true;
if (!this.props.trySelectCluster(e.shiftKey)) {
- this.setPreviewCursor(e.clientX, e.clientY, false);
+ this.setPreviewCursor(e.clientX, e.clientY, false, false);
} else e.stopPropagation();
}
}
@@ -443,8 +448,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
syntaxHighlight = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "i" : true) {
- const inks = selected.filter(s => s.proto?.type === DocumentType.INK);
- const setDocs = selected.filter(s => s.proto?.type === DocumentType.RTF && s.color);
+ const inks = selected.filter(s => s.type === DocumentType.INK);
+ const setDocs = selected.filter(s => s.type === DocumentType.RTF && s.color);
const sets = setDocs.map((sd) => Cast(sd.data, RichTextField)?.Text as string);
const colors = setDocs.map(sd => FieldValue(sd.color) as string);
const wordToColor = new Map<string, string>();
diff --git a/src/client/views/collections/collectionFreeForm/index.ts b/src/client/views/collections/collectionFreeForm/index.ts
new file mode 100644
index 000000000..702dc8d42
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/index.ts
@@ -0,0 +1,7 @@
+export * from "./CollectionFreeFormLayoutEngines";
+export * from "./CollectionFreeFormLinkView";
+export * from "./CollectionFreeFormLinksView";
+export * from "./CollectionFreeFormRemoteCursors";
+export * from "./CollectionFreeFormView";
+export * from "./MarqueeOptionsMenu";
+export * from "./MarqueeView"; \ No newline at end of file
diff --git a/src/client/views/collections/collectionGrid/index.ts b/src/client/views/collections/collectionGrid/index.ts
new file mode 100644
index 000000000..be5d5667a
--- /dev/null
+++ b/src/client/views/collections/collectionGrid/index.ts
@@ -0,0 +1,2 @@
+export * from "./Grid";
+export * from "./CollectionGridView"; \ No newline at end of file
diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/collectionLinear/CollectionLinearView.scss
index 913a65774..8fe804466 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.scss
@@ -1,15 +1,31 @@
-@import "../global/globalCssVariables";
-@import "../_nodeModuleOverrides";
+@import "../../global/globalCssVariables";
+@import "../../_nodeModuleOverrides";
.collectionLinearView-outer {
overflow: visible;
height: 100%;
pointer-events: none;
+ &.true {
+ padding-left: 5px;
+ padding-right: 5px;
+ border-left: $standard-border;
+ background-color: $medium-blue-alt;
+ }
+
+ >input:not(:checked)~&.true {
+ background-color: transparent;
+ }
+
.collectionLinearView {
display: flex;
height: 100%;
align-items: center;
+ gap: 5px;
+
+ .collectionView {
+ overflow: visible !important;
+ }
>span {
background: $dark-gray;
@@ -22,6 +38,7 @@
.bottomPopup-background {
background: $medium-blue;
display: flex;
+ border-radius: 10px;
height: 35;
transform: translate3d(6px, 0px, 0px);
align-content: center;
@@ -40,6 +57,7 @@
}
.bottomPopup-descriptions {
+ cursor: pointer;
display: inline;
white-space: nowrap;
padding-left: 8px;
@@ -52,6 +70,7 @@
}
.bottomPopup-exit {
+ cursor: pointer;
display: inline;
white-space: nowrap;
margin-right: 10px;
@@ -64,29 +83,26 @@
}
>label {
- margin-top: "auto";
- margin-bottom: "auto";
- background: $dark-gray;
- color: $white;
- display: inline-block;
- border-radius: 18px;
- font-size: 12.5px;
- width: 18px;
- height: 18px;
- margin-top: auto;
- margin-bottom: auto;
- margin-right: 3px;
+ pointer-events: all;
cursor: pointer;
+ background-color: $medium-blue;
+ padding: 5;
+ border-radius: 2px;
+ height: 25;
+ min-width: 25;
+ margin: 0;
+ color: $white;
+ display: flex;
+ font-weight: 100;
+ width: fit-content;
transition: transform 0.2s;
- }
-
- label p {
- padding-left: 5px;
- }
+ align-items: center;
+ justify-content: center;
+ transition: 0.2s;
- label:hover {
- background: $medium-gray;
- transform: scale(1.15);
+ &:hover{
+ filter: brightness(0.85);
+ }
}
>input {
@@ -107,13 +123,11 @@
display: flex;
opacity: 1;
position: relative;
- margin-top: auto;
.collectionLinearView-docBtn,
.collectionLinearView-docBtn-scalable {
position: relative;
margin: auto;
- margin-left: 3px;
transform-origin: center 80%;
}
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
new file mode 100644
index 000000000..7fe95fef0
--- /dev/null
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -0,0 +1,226 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
+import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
+import { documentSchema } from '../../../../fields/documentSchemas';
+import { Id } from '../../../../fields/FieldSymbols';
+import { makeInterface } from '../../../../fields/Schema';
+import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
+import { DragManager } from '../../../util/DragManager';
+import { Transform } from '../../../util/Transform';
+import { Colors, Shadows } from '../../global/globalEnums';
+import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
+import { DocumentView } from '../../nodes/DocumentView';
+import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
+import { StyleProp } from '../../StyleProvider';
+import { CollectionSubView } from '../CollectionSubView';
+import { CollectionViewType } from '../CollectionView';
+import "./CollectionLinearView.scss";
+
+
+type LinearDocument = makeInterface<[typeof documentSchema,]>;
+const LinearDocument = makeInterface(documentSchema);
+
+@observer
+export class CollectionLinearView extends CollectionSubView(LinearDocument) {
+ @observable public addMenuToggle = React.createRef<HTMLInputElement>();
+ @observable private _selectedIndex = -1;
+ private _dropDisposer?: DragManager.DragDropDisposer;
+ private _widthDisposer?: IReactionDisposer;
+ private _selectedDisposer?: IReactionDisposer;
+
+ componentWillUnmount() {
+ this._dropDisposer?.();
+ this._widthDisposer?.();
+ this._selectedDisposer?.();
+ this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
+ }
+
+ componentDidMount() {
+ this._widthDisposer = reaction(() => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * (this.rootDoc[HeightSym]()) : 10),
+ width => this.childDocs.length && (this.layoutDoc._width = width),
+ { fireImmediately: true }
+ );
+
+ this._selectedDisposer = reaction(
+ () => NumCast(this.layoutDoc.selectedIndex),
+ (i) => runInAction(() => {
+ this._selectedIndex = i;
+ let selected: any = undefined;
+ this.childLayoutPairs.map(async (pair, ind) => {
+ const isSelected = this._selectedIndex === ind;
+ if (isSelected) {
+ selected = pair;
+ }
+ else {
+ ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
+ }
+ });
+ if (selected && selected.layout) {
+ ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
+ }
+ }),
+ { fireImmediately: true }
+ );
+ }
+ protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
+ this._dropDisposer && this._dropDisposer();
+ if (ele) {
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
+ }
+ }
+
+ dimension = () => NumCast(this.rootDoc._height); // 2 * the padding
+ getTransform = (ele: Opt<HTMLDivElement>) => {
+ if (!ele) return Transform.Identity();
+ const { scale, translateX, translateY } = Utils.GetScreenTransform(ele);
+ return new Transform(-translateX, -translateY, 1);
+ }
+
+ @action
+ exitLongLinks = () => {
+ if (DocumentLinksButton.StartLink) {
+ if (DocumentLinksButton.StartLink.Document) {
+ action((e: React.PointerEvent<HTMLDivElement>) => {
+ Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc);
+ });
+ }
+ }
+ DocumentLinksButton.StartLink = undefined;
+ DocumentLinksButton.StartLinkView = undefined;
+ }
+
+ @action
+ changeDescriptionSetting = () => {
+ if (LinkDescriptionPopup.showDescriptions) {
+ if (LinkDescriptionPopup.showDescriptions === "ON") {
+ LinkDescriptionPopup.showDescriptions = "OFF";
+ LinkDescriptionPopup.descriptionPopup = false;
+ } else {
+ LinkDescriptionPopup.showDescriptions = "ON";
+ }
+ } else {
+ LinkDescriptionPopup.showDescriptions = "OFF";
+ LinkDescriptionPopup.descriptionPopup = false;
+ }
+ }
+
+ myContextMenu = (e: React.MouseEvent) => {
+ console.log("STOPPING");
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+
+ getDisplayDoc = (doc: Doc) => {
+ const nested = doc._viewType === CollectionViewType.Linear;
+ const hidden = doc.hidden === true;
+
+ let dref: Opt<HTMLDivElement>;
+ const docXf = () => this.getTransform(dref);
+ // const scalable = pair.layout.onClick || pair.layout.onDragStart;
+ return hidden ? (null) : <div className={`collectionLinearView-docBtn`} key={doc[Id]} ref={r => dref = r || undefined}
+ style={{
+ pointerEvents: "all",
+ width: nested ? undefined : NumCast(doc._width),
+ height: nested ? undefined : NumCast(doc._height),
+ marginLeft: !nested ? 2.5 : 0,
+ marginRight: !nested ? 2.5 : 0,
+ // width: NumCast(pair.layout._width),
+ // height: NumCast(pair.layout._height),
+ }} >
+ <DocumentView
+ Document={doc}
+ isContentActive={this.props.isContentActive}
+ isDocumentActive={returnTrue}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ addDocTab={this.props.addDocTab}
+ pinToPres={emptyFunction}
+ rootSelected={this.props.isSelected}
+ removeDocument={this.props.removeDocument}
+ ScreenToLocalTransform={docXf}
+ PanelWidth={nested ? doc[WidthSym] : this.dimension}
+ PanelHeight={nested ? doc[HeightSym] : this.dimension}
+ renderDepth={this.props.renderDepth + 1}
+ focus={emptyFunction}
+ styleProvider={this.props.styleProvider}
+ layerProvider={this.props.layerProvider}
+ docViewPath={returnEmptyDoclist}
+ whenChildContentsActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined} />
+ </div>;
+ }
+
+ render() {
+ const guid = Utils.GenerateGuid(); // Generate a unique ID to use as the label
+ const flexDir: any = StrCast(this.Document.flexDirection); // Specify direction of linear view content
+ const flexGap: number = NumCast(this.Document.flexGap); // Specify the gap between linear view content
+ const expandable: boolean = BoolCast(this.props.Document.linearViewExpandable); // Specify whether it is expandable or not
+ const floating: boolean = BoolCast(this.props.Document.linearViewFloating); // Specify whether it is expandable or not
+
+ const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+ const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+ const icon: string = StrCast(this.props.Document.icon); // Menu opener toggle
+ const menuOpener = <label htmlFor={`${guid}`}
+ style={{
+ boxShadow: floating ? Shadows.STANDARD_SHADOW : undefined,
+ color: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.BLACK,
+ backgroundColor: backgroundColor === color ? "black" : BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : Colors.LIGHT_GRAY
+ }}
+ onPointerDown={e => e.stopPropagation()} >
+ <div className="collectionLinearView-menuOpener">
+ {BoolCast(this.layoutDoc.linearViewIsExpanded) ? icon ? icon : <FontAwesomeIcon icon={"minus"} /> : icon ? icon : <FontAwesomeIcon icon={"plus"} />}
+ </div>
+ </label>;
+
+ return <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: BoolCast(this.layoutDoc.linearViewIsExpanded) ? undefined : "transparent" }}>
+ <div className="collectionLinearView" ref={this.createDashEventsTarget}
+ onContextMenu={this.myContextMenu} >
+ {!expandable ? (null) : <Tooltip title={<><div className="dash-tooltip">{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close" : "Open"}</div></>} placement="top">
+ {menuOpener}
+ </Tooltip>}
+ <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
+ onChange={action(() => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
+
+ <div className="collectionLinearView-content"
+ style={{
+ height: this.dimension(),
+ flexDirection: flexDir,
+ gap: flexGap
+ }}>
+ {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+ </div>
+ {DocumentLinksButton.StartLink && StrCast(this.layoutDoc.title) === "docked buttons" ? <span className="bottomPopup-background" style={{
+ pointerEvents: "all"
+ }}
+ onPointerDown={e => e.stopPropagation()} >
+ <span className="bottomPopup-text" >
+ Creating link from: <b>{DocumentLinksButton.AnnotationId ? "Annotation in " : " "} {StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...'}</b>
+ </span>
+
+ <Tooltip title={<><div className="dash-tooltip">{"Toggle description pop-up"} </div></>} placement="top">
+ <span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
+ Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"}
+ </span>
+ </Tooltip>
+
+ <Tooltip title={<><div className="dash-tooltip">Exit linking mode</div></>} placement="top">
+ <span className="bottomPopup-exit" onClick={this.exitLongLinks}>
+ Stop
+ </span>
+ </Tooltip>
+
+ </span> : null}
+ </div>
+ </div>;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/collectionLinear/index.ts b/src/client/views/collections/collectionLinear/index.ts
new file mode 100644
index 000000000..ff73e14ae
--- /dev/null
+++ b/src/client/views/collections/collectionLinear/index.ts
@@ -0,0 +1 @@
+export * from "./CollectionLinearView"; \ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index f3a39a262..65c345547 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -237,8 +237,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
focus={this.props.focus}
- docFilters={this.docFilters}
- docRangeFilters={this.docRangeFilters}
+ docFilters={this.childDocFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 29cb3511a..30836854a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -236,9 +236,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
focus={this.props.focus}
- docFilters={this.docFilters}
+ docFilters={this.childDocFilters}
isContentActive={returnFalse}
- docRangeFilters={this.docRangeFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
index b2115b22e..a25f962df 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
@@ -191,7 +191,7 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
{this.renderSorting()}
{this.renderColors()}
<div className="collectionSchema-headerMenu-group">
- <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Delete Column</button>
+ <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Hide Column</button>
</div>
</>
}
@@ -413,7 +413,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
bool = fields ? fields[1] === "check" : false;
}
return <div key={key} className="key-option" style={{
- border: "1px solid lightgray", paddingLeft: 5, textAlign: "left",
+ paddingLeft: 5, textAlign: "left",
width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
}}
>
@@ -424,7 +424,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, "remove");
e.target.checked === true ? this.closeResultsVisibility = "contents" : console.log("");
e.target.checked === true ? this.props.col.setColor("green") : this.updateFilter();
- e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove");
+ e.target.checked === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove");
}}
checked={bool}
/>
@@ -489,8 +489,10 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
}
render() {
return (
- <div style={{ display: "flex" }} ref={this.setNode}>
- <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
+ <div style={{ display: "flex", width: '100%', alignContent: 'center', alignItems: 'center' }} ref={this.setNode}>
+ <div className="schema-icon" onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }}>
+ <FontAwesomeIcon icon={this.props.icon} size="lg" style={{ display: "inline" }} />
+ </div>
{/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx
index f48906ba5..0e19ef3d9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx
@@ -134,9 +134,9 @@ export class MovableRow extends React.Component<MovableRowProps> {
<div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
<ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown} >
<div className="row-dragger">
- <div className="row-option" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
- <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
- <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
+ <div className="row-option" onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
+ <div className="row-option" style={{ cursor: "grab" }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
+ <div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
</div>
{children}
</ReactTableDefaults.TrComponent>
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 40cdcd14b..3074ce66e 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -108,9 +108,7 @@
}
.rt-th {
padding: 0;
- border: solid lightgray;
- border-width: 0 1px;
- border-bottom: 2px solid lightgray;
+ border-left: solid 1px $light-gray;
}
}
.rt-th {
@@ -213,6 +211,8 @@
}
}
+
+
.collectionSchemaView-header {
height: 100%;
color: gray;
@@ -227,6 +227,15 @@ button.add-column {
width: 28px;
}
+.collectionSchemaView-menuOptions-wrapper {
+ background: rgb(241, 239, 235);
+ display: flex;
+ cursor: default;
+ height: 100%;
+ align-content: center;
+ align-items: center;
+}
+
.collectionSchema-header-menuOptions {
color: black;
width: 180px;
@@ -272,6 +281,9 @@ button.add-column {
width: 10px;
}
}
+
+
+
.keys-dropdown {
position: relative;
//width: 100%;
@@ -287,26 +299,7 @@ button.add-column {
font-weight: normal;
}
}
- .keys-options-wrapper {
- width: 100%;
- max-height: 150px;
- overflow-y: scroll;
- position: absolute;
- top: 28px;
- box-shadow: 0 10px 16px rgba(0, 0, 0, 0.1);
- background-color: white;
- .key-option {
- background-color: white;
- border: 1px solid lightgray;
- padding: 2px 3px;
- &:not(:first-child) {
- border-top: 0;
- }
- &:hover {
- background-color: $light-gray;
- }
- }
- }
+
}
.columnMenu-colors {
display: flex;
@@ -325,11 +318,53 @@ button.add-column {
}
}
+.schema-icon {
+ cursor: pointer;
+ width: 25px;
+ height: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ align-content: center;
+ background-color: $medium-blue;
+ color: white;
+ margin-right: 5px;
+ font-size: 10px;
+ border-radius: 3px;
+
+}
+
+.keys-options-wrapper {
+ position: absolute;
+ text-align: left;
+ height: fit-content;
+ top: 100%;
+ z-index: 21;
+ background-color: #ffffff;
+ box-shadow: 0px 3px 4px rgba(0,0,0,30%);
+ padding: 1px;
+ .key-option {
+ cursor: pointer;
+ color: #000000;
+ width: 100%;
+ height: 25px;
+ font-weight: 400;
+ display: flex;
+ justify-content: left;
+ align-items: center;
+ padding-left: 5px;
+ &:hover {
+ background-color: $light-gray;
+ }
+ }
+}
+
.collectionSchema-row {
height: 100%;
background-color: white;
&.row-focused .rt-td {
- background-color: #bfffc0; //$light-gray;
+ background-color: $light-blue; //$light-gray;
+ overflow: visible;
}
&.row-wrapped {
.rt-td {
@@ -338,39 +373,40 @@ button.add-column {
}
.row-dragger {
display: flex;
- justify-content: space-around;
- //flex: 50 0 auto;
- width: 0;
- max-width: 50px;
- //height: 100%;
+ justify-content: space-evenly;
+ width: 58px;
+ position: absolute;
+ /* max-width: 50px; */
min-height: 30px;
align-items: center;
color: lightgray;
background-color: white;
transition: color 0.1s ease;
.row-option {
- // padding: 5px;
+ color: black;
cursor: pointer;
- position: absolute;
+ position: relative;
transition: color 0.1s ease;
display: flex;
flex-direction: column;
justify-content: center;
z-index: 2;
+ border-radius: 3px;
+ padding: 3px;
&:hover {
- color: gray;
+ background-color: $light-gray;
}
}
}
.collectionSchema-row-wrapper {
&.row-above {
- border-top: 1px solid red;
+ border-top: 1px solid $medium-blue;
}
&.row-below {
- border-bottom: 1px solid red;
+ border-bottom: 1px solid $medium-blue;
}
&.row-inside {
- border: 1px solid red;
+ border: 2px dashed $medium-blue;
}
.row-dragging {
background-color: blue;
@@ -383,24 +419,32 @@ button.add-column {
height: unset;
}
+.collectionSchemaView-cellContents {
+ width: 100%;
+}
+
.collectionSchemaView-cellWrapper {
+ display: flex;
height: 100%;
- padding: 4px;
text-align: left;
padding-left: 19px;
position: relative;
+ align-items: center;
+ align-content: center;
&:focus {
outline: none;
}
&.editing {
padding: 0;
+ box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
+ transform: scale(1.1);
+ z-index: 40;
input {
outline: 0;
border: none;
- background-color: rgb(255, 217, 217);
+ background-color: $white;
width: 100%;
height: 100%;
- padding: 2px 3px;
min-height: 26px;
}
}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 585cda729..dfe99ffc8 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -338,7 +338,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{this.renderColors(this._col)}
<div className="collectionSchema-headerMenu-group">
<button onClick={() => { this.deleteColumn(this._col.heading); }}
- >Delete Column</button>
+ >Hide Column</button>
</div>
</div>;
}
@@ -413,8 +413,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
isContentActive={returnTrue}
isDocumentActive={returnFalse}
ScreenToLocalTransform={this.getPreviewTransform}
- docFilters={this.docFilters}
- docRangeFilters={this.docRangeFilters}
+ docFilters={this.childDocFilters}
+ docRangeFilters={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
styleProvider={DefaultStyleProvider}
layerProvider={undefined}
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx
index de08c327a..3833f968b 100644
--- a/src/client/views/collections/collectionSchema/SchemaTable.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx
@@ -194,9 +194,10 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}>
{keysDropdown}
- <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
+ <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "pointer" }}>
<FontAwesomeIcon icon={sortIcon} size="lg" />
</div>
+ {/* {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} */}
</div>;
return {
@@ -561,7 +562,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
{this.reactTable}
- {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
+ {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
{!this._showDoc ? (null) :
<div className="collectionSchemaView-documentPreview" ref="overlay"
style={{