diff options
| author | usodhi <61431818+usodhi@users.noreply.github.com> | 2020-08-06 17:33:19 +0530 |
|---|---|---|
| committer | usodhi <61431818+usodhi@users.noreply.github.com> | 2020-08-06 17:33:19 +0530 |
| commit | 6bd5f0b4d211d0395fd5035a5f17d33bb2399976 (patch) | |
| tree | a567e833632ef8bdd893cb9f305ff94590bd7318 /src/client/views/collections | |
| parent | 988a16c4b69d1d5062bccf70295aa90c490f9e76 (diff) | |
| parent | 6d8dfee38bd39b95396cbc97405516693116b58f (diff) | |
merging
Diffstat (limited to 'src/client/views/collections')
21 files changed, 1089 insertions, 309 deletions
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 6ebd5103b..98babc3d2 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -20,6 +20,67 @@ } } +.miniPres:hover { + opacity: 1; +} + +.miniPres { + position: absolute; + overflow: hidden; + right: 10; + top: 10; + opacity: 0.1; + transition: all 0.4s; + /* border: solid 1px; */ + color: white; + /* box-shadow: black 0.4vw 0.4vw 0.8vw; */ + + .miniPresOverlay { + display: grid; + grid-template-columns: auto auto auto auto auto auto auto auto; + grid-template-rows: 100%; + height: 100%; + justify-items: center; + align-items: center; + + .miniPres-button-text { + display: flex; + height: 20; + font-weight: 400; + min-width: 100%; + border-radius: 5px; + align-items: center; + justify-content: center; + transition: all 0.3s; + } + + .miniPres-divider { + width: 0.5px; + height: 80%; + border-right: solid 2px #5a5a5a; + } + + .miniPres-button { + display: flex; + height: 20; + min-width: 20; + border-radius: 100%; + align-items: center; + justify-content: center; + transition: all 0.3s; + } + + .miniPres-button:hover { + background-color: #5a5a5a; + } + + .miniPres-button-text:hover { + background-color: #5a5a5a; + } + } +} + + .lm_title { margin-top: 3px; border-radius: 5px; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 533c8bffe..6d4a7f311 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -30,6 +30,8 @@ import { SnappingManager } from '../../util/SnappingManager'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { listSpec } from '../../../fields/Schema'; import { clamp } from 'lodash'; +import { PresBox } from '../nodes/PresBox'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { InteractionUtils } from '../../util/InteractionUtils'; import { InkTool } from '../../../fields/InkField'; const _global = (window /* browser */ || global /* node */) as any; @@ -793,10 +795,10 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { let scaling = 1; if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) { scaling = 1; - } else if ((this.layoutDoc?._fitWidth) || - this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) { + } else if (NumCast(this.layoutDoc!._nativeWidth) && ((this.layoutDoc?._fitWidth) || + this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth))) { scaling = this._panelWidth / NumCast(this.layoutDoc!._nativeWidth); - } else { + } else if (nativeW && nativeH) { // if (this.layoutDoc!.type === DocumentType.PDF || this.layoutDoc!.type === DocumentType.WEB) { // if ((this.layoutDoc?._fitWidth) || // this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) { @@ -807,7 +809,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { // } const wscale = this.panelWidth() / nativeW; scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale; - } + } else scaling = 1; return scaling; } @@ -862,6 +864,27 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { return false; }), emptyFunction, emptyFunction); } + getCurrentFrame = (): number => { + const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null); + const currentFrame = Cast(presTargetDoc.currentFrame, "number", null); + return currentFrame; + } + renderMiniPres() { + return <div className="miniPres" style={{ + width: 250, height: 30, background: '#323232' + }}> + <div className="miniPresOverlay" > + <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div> + <div className="miniPres-button" onClick={() => PresBox.Instance.startOrResetPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div> + <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div> + <div className="miniPres-divider"></div> + <div className="miniPres-button-text">Slide {PresBox.Instance.itemIndex + 1} / {PresBox.Instance.childDocs.length}</div> + {/* <div className="miniPres-button-text">{this.getCurrentFrame}</div> */} + <div className="miniPres-divider"></div> + <div className="miniPres-button-text" onClick={PresBox.Instance.updateMinimize}>EXIT</div> + </div> + </div>; + } renderMiniMap() { return <div className="miniMap" style={{ width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor, @@ -944,6 +967,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} /> {document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)} + {document._viewType === CollectionViewType.Freeform && this._document?.miniPres ? this.renderMiniPres() : (null)} </>; } diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss index b8b72e756..f5c4299a9 100644 --- a/src/client/views/collections/CollectionLinearView.scss +++ b/src/client/views/collections/CollectionLinearView.scss @@ -2,7 +2,7 @@ @import "../_nodeModuleOverrides"; .collectionLinearView-outer { - overflow: hidden; + overflow: visible; height: 100%; .collectionLinearView { diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss index 0a316317f..b41cbe92d 100644 --- a/src/client/views/collections/CollectionMenu.scss +++ b/src/client/views/collections/CollectionMenu.scss @@ -368,6 +368,7 @@ } } + .numKeyframe { flex-direction: column; padding-top: 5px; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a7d2c07fa..53d2a136e 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,37 +1,35 @@ import React = require("react"); +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, reaction, runInAction, Lambda } from "mobx"; +import { Tooltip } from "@material-ui/core"; +import { action, computed, Lambda, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, Opt, Field } from "../../../fields/Doc"; -import { BoolCast, Cast, StrCast, NumCast } from "../../../fields/Types"; -import AntimodeMenu from "../AntimodeMenu"; -import "./CollectionMenu.scss"; -import { undoBatch } from "../../util/UndoManager"; -import { CollectionViewType, CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; -import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils"; -import { DragManager } from "../../util/DragManager"; -import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; -import { List } from "../../../fields/List"; -import { EditableView } from "../EditableView"; +import { ColorState } from "react-color"; +import { Doc, DocListCast, Opt } from "../../../fields/Doc"; +import { Document } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; -import { listSpec } from "../../../fields/Schema"; -import FormatShapePane from "./collectionFreeForm/FormatShapePane"; -import { ActiveFillColor, SetActiveInkWidth, ActiveInkColor, SetActiveBezierApprox, SetActiveArrowEnd, SetActiveArrowStart, SetActiveFillColor, SetActiveInkColor } from "../InkingStroke"; -import GestureOverlay from "../GestureOverlay"; import { InkTool } from "../../../fields/InkField"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { Document } from "../../../fields/documentSchemas"; -import { SelectionManager } from "../../util/SelectionManager"; -import { DocumentView } from "../nodes/DocumentView"; -import { ColorState } from "react-color"; +import { List } from "../../../fields/List"; import { ObjectField } from "../../../fields/ObjectField"; -import RichTextMenu from "../nodes/formattedText/RichTextMenu"; import { RichTextField } from "../../../fields/RichTextField"; +import { listSpec } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { DocUtils } from "../../documents/Documents"; -import { Tooltip } from "@material-ui/core"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; +import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils"; +import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { DragManager } from "../../util/DragManager"; +import { SelectionManager } from "../../util/SelectionManager"; +import { undoBatch } from "../../util/UndoManager"; +import AntimodeMenu from "../AntimodeMenu"; +import { EditableView } from "../EditableView"; +import GestureOverlay from "../GestureOverlay"; +import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke"; +import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; +import { DocumentView } from "../nodes/DocumentView"; +import RichTextMenu from "../nodes/formattedText/RichTextMenu"; +import "./CollectionMenu.scss"; +import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView"; @observer export default class CollectionMenu extends AntimodeMenu { @@ -185,7 +183,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; }, }; - @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } + @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } @@ -236,7 +234,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp @computed get subChrome() { switch (this.props.type) { - default: + default: return this.otherSubChrome; + case CollectionViewType.Invalid: case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />); case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />); case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />); @@ -247,6 +246,21 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />); } } + + @computed get otherSubChrome() { + const docType = this.props.docView.Document.type; + switch (docType) { + default: return (null); + case DocumentType.IMG: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />); + case DocumentType.PDF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />); + case DocumentType.INK: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />); + case DocumentType.WEB: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />); + case DocumentType.VID: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />); + case DocumentType.RTF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} isDoc={true} />); + } + } + + private dropDisposer?: DragManager.DragDropDisposer; protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer?.(); @@ -392,7 +406,7 @@ export class CollectionDockingChrome extends React.Component<CollectionMenuProps } @observer -export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean }> { +export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean, isDoc?: boolean }> { public static Instance: CollectionFreeFormViewChrome; constructor(props: any) { super(props); @@ -567,6 +581,8 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}> {/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */} <div className="color-previewII" style={{ backgroundColor: color }} /> + {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""} + </button>)} </div>; } @@ -580,40 +596,44 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu <button className="antimodeMenu-button" key={color} onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })} style={{ backgroundColor: this._fillBtn ? "121212" : "", zIndex: 1001 }}> - <div className="color-previewII" style={{ backgroundColor: color }}></div> + <div className="color-previewII" style={{ backgroundColor: color }}> + {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""} + </div> </button>)} </div>; } + @observable viewType = this.selectedDoc?._viewType; + render() { return !this.props.docView.layoutDoc ? (null) : <div className="collectionFreeFormMenu-cont"> - {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) : + {this.props.docView.props.renderDepth !== 0 || this.isText || this.props.isDoc ? (null) : <Tooltip key="map" title={<div className="dash-tooltip">Toggle Mini Map</div>} placement="bottom"> - <div className="backKeyframe" onClick={this.miniMap}> + <div className="backKeyframe" onClick={this.miniMap} style={{ marginRight: "5px" }}> <FontAwesomeIcon icon={"map"} size={"lg"} /> </div> </Tooltip> } - {!this.isText ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom"> + {!this.isText && !this.props.isDoc ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom"> <div className="backKeyframe" onClick={this.prevKeyframe}> <FontAwesomeIcon icon={"caret-left"} size={"lg"} /> </div> </Tooltip> : null} - {!this.isText ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom"> + {!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom"> <div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }} onClick={action(() => this.document.editing = !this.document.editing)} > {NumCast(this.document.currentFrame)} </div> </Tooltip> : null} - {!this.isText ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom"> + {!this.isText && !this.props.isDoc ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom"> <div className="fwdKeyframe" onClick={this.nextKeyframe}> <FontAwesomeIcon icon={"caret-right"} size={"lg"} /> </div> </Tooltip> : null} - {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) : + {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) : <Tooltip key="hypothesis" title={<div className="dash-tooltip">Use Hypothesis</div>} placement="bottom"> <button className={"antimodeMenu-button"} key="hypothesis" style={{ @@ -625,7 +645,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu </button> </Tooltip> } - {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ? + {!this.isText ? <> {this.drawButtons} {this.widthPicker} @@ -651,6 +671,24 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu getKeySuggestions = async (value: string): Promise<string[]> => { value = value.toLowerCase(); const docs = DocListCast(this.document[this.props.fieldKey]); + + if (Doc.UserDoc().noviceMode) { + if (docs instanceof Doc) { + const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 || + key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 || + (key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_")); + return keys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1); + } else { + const keys = new Set<string>(); + docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); + const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 || + key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 || + key.indexOf("lastModified") >= 0 || (key[0].toUpperCase() === key[0] && + key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_")); + return noviceKeys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1); + } + } + if (docs instanceof Doc) { return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); } else { diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index eecaf7672..d11d6a5ba 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -32,6 +32,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import DatePicker from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; import { DateField } from "../../../fields/DateField"; +import { RichTextField } from "../../../fields/RichTextField"; const path = require('path'); library.add(faExpand); @@ -193,7 +194,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> { const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc); const onItemDown = (e: React.PointerEvent) => { - fieldIsDoc && SetupDrag(this._focusRef, + //fieldIsDoc && + SetupDrag(this._focusRef, () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document, this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument, this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); @@ -240,25 +242,72 @@ export class CollectionSchemaCell extends React.Component<CellProps> { // <FontAwesomeIcon icon="expand" size="sm" /> // </div> // ); - trace(); - - - + const positions = []; + if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { + const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); + let term = ""; + if (cfield !== undefined) { + if (cfield.Text !== undefined) { + term = cfield.Text; + } + else if (StrCast(cfield)) { + term = StrCast(cfield); + } + else { + term = String(NumCast(cfield)); + } + } + term = term.toLowerCase(); + const search = StrCast(this.props.Document._searchString).toLowerCase(); + let start = term.indexOf(search); + let tally = 0; + if (start !== -1) { + positions.push(start); + } + while (start < contents.length && start !== -1) { + term = term.slice(start + search.length + 1); + tally += start + search.length + 1; + start = term.indexOf(search); + positions.push(tally + start); + } + if (positions.length > 1) { + positions.pop(); + } + } return ( - <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }} ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> + <div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }} + ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> <div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}> <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}> - - <EditableView + positions={positions.length > 0 ? positions : undefined} + search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined} editing={this._isEditing} isEditingCallback={this.isEditingCallback} display={"inline"} contents={contents ? contents : type === "number" ? "0" : "undefined"} + highlight={positions.length > 0 ? true : undefined} //contents={StrCast(contents)} height={"auto"} maxHeight={Number(MAX_ROW_HEIGHT)} placeholder={"enter value"} + bing={() => { + const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); + if (cfield !== undefined) { + console.log(typeof (cfield)); + // if (typeof(cfield)===RichTextField) + const a = cfield as RichTextField; + if (a.Text !== undefined) { + return (a.Text); + } + else if (StrCast(cfield)) { + return StrCast(cfield); + } + else { + return String(NumCast(cfield)); + } + } + }} GetValue={() => { if (type === "number" && (contents === 0 || contents === "0")) { return "0"; @@ -272,6 +321,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> { const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; return val; + } }} @@ -827,3 +877,69 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { ); } } + + +@observer +export class CollectionSchemaButtons extends CollectionSchemaCell { + + render() { + // const reference = React.createRef<HTMLDivElement>(); + // const onItemDown = (e: React.PointerEvent) => { + // (!this.props.CollectionView || !this.props.CollectionView.props.isSelected() ? undefined : + // SetupDrag(reference, () => this._document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e)); + // }; + const doc = this.props.rowProps.original; + let buttons: JSX.Element | undefined = undefined; + buttons = <div style={{ + paddingTop: 8, + paddingLeft: 3, + }}><button onClick={() => { + doc.searchMatch = false; + setTimeout(() => doc.searchMatch = true, 0); + doc.searchIndex = NumCast(doc.searchIndex); + }} style={{ padding: 2, left: 77 }}> + <FontAwesomeIcon icon="arrow-up" size="sm" /> + </button> + <button onClick={() => { + { + doc.searchMatchAlt = false; + setTimeout(() => doc.searchMatchAlt = true, 0); + doc.searchIndex = NumCast(doc.searchIndex); + } + }} style={{ padding: 2 }}> + <FontAwesomeIcon icon="arrow-down" size="sm" /> + </button></div>; + const type = StrCast(doc.type); + if (type === "pdf") { + buttons = <div><button + style={{ + position: "relative", + height: 30, + width: 28, + left: 1, + }} + + onClick={() => { + doc.searchMatch = false; + setTimeout(() => doc.searchMatch = true, 0); + doc.searchIndex = NumCast(doc.searchIndex); + }}> + <FontAwesomeIcon icon="arrow-down" size="sm" /> + </button></div >; + } + else if (type !== "rtf") { + buttons = undefined; + } + + if (BoolCast(this.props.Document._searchDoc) === true) { + + } + else { + buttons = undefined; + } + return ( + <div> {buttons}</div> + ); + } +} + diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index efff4db98..e65adcf76 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -9,6 +9,8 @@ import { ColumnType } from "./CollectionSchemaView"; import { faFile } from "@fortawesome/free-regular-svg-icons"; import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; +import { Doc } from "../../../fields/Doc"; +import { StrCast } from "../../../fields/Types"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -76,14 +78,6 @@ export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHe - - - - - - - - export interface ColumnMenuProps { columnField: SchemaHeaderField; // keyValue: string; @@ -288,9 +282,10 @@ export interface KeysDropdownProps { existingKeys: string[]; canAddNew: boolean; addNew: boolean; - onSelect: (oldKey: string, newKey: string, addnew: boolean) => void; + onSelect: (oldKey: string, newKey: string, addnew: boolean, filter?: string) => void; setIsEditing: (isEditing: boolean) => void; width?: string; + docs?: Doc[]; } @observer export class KeysDropdown extends React.Component<KeysDropdownProps> { @@ -306,10 +301,23 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { @action onSelect = (key: string): void => { - this.props.onSelect(this._key, key, this.props.addNew); - this.setKey(key); + if (key.slice(0, this._key.length) === this._key && this._key !== key) { + const filter = key.slice(this._key.length - key.length); + this.props.onSelect(this._key, this._key, this.props.addNew, filter); + } + else { + this.props.onSelect(this._key, key, this.props.addNew); + this.setKey(key); + this._isOpen = false; + this.props.setIsEditing(false); + } + } + + @action + onSelect2 = (key: string): void => { + this._searchTerm = this._searchTerm.slice(0, this._key.length) + key; this._isOpen = false; - this.props.setIsEditing(false); + } @undoBatch @@ -371,22 +379,53 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { }); // if search term does not already exist as a group type, give option to create new group type - if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) { - options.push(<div key={""} className="key-option" style={{ + if (this._key !== this._searchTerm.slice(0, this._key.length)) { + if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) { + options.push(<div key={""} className="key-option" style={{ + border: "1px solid lightgray", + width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" + }} + onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}> + Create "{this._searchTerm}" key</div>); + } + } + + return options; + } + + renderFilterOptions = (): JSX.Element[] | JSX.Element => { + if (!this._isOpen) return <></>; + const keyOptions: string[] = []; + const temp = this._searchTerm.slice(this._key.length); + this.props.docs?.forEach((doc) => { + const key = StrCast(doc[this._key]); + if (keyOptions.includes(key) === false && key.includes(temp)) { + keyOptions.push(key); + } + }); + + + const options = keyOptions.map(key => { + return <div key={key} className="key-option" style={{ border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" }} - onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}> - Create "{this._searchTerm}" key</div>); - } + onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect2(key); }}>{key}</div>; + }); return options; } + render() { return ( - <div className="keys-dropdown" style={{ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" }}> - <input className="keys-search" //style={{ width: this.props.width, maxWidth: "1000" }} + <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}> + {this._key === this._searchTerm.slice(0, this._key.length) ? + <div style={{ position: "absolute", marginLeft: "4px", marginTop: "3", color: "grey", pointerEvents: "none", lineHeight: 1.15 }}> + {this._key} + </div> + : undefined} + <input className="keys-search" style={{ width: "100%" }} ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown} onChange={e => this.onChange(e.target.value)} onClick={(e) => { @@ -395,10 +434,11 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { }} onFocus={this.onFocus} onBlur={this.onBlur}></input> <div className="keys-options-wrapper" style={{ backgroundColor: "white", - width: this.props.width, maxWidth: this.props.width, overflowX: "hidden" + width: this.props.width, maxWidth: this.props.width, }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}> - {this.renderOptions()} + {this._key === this._searchTerm.slice(0, this._key.length) ? + this.renderFilterOptions() : this.renderOptions()} </div> </div > ); diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index b77173b25..dade4f2f2 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -209,6 +209,14 @@ export class MovableRow extends React.Component<MovableRowProps> { return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc); } + @action + onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { + console.log("yes"); + if (e.key === "Backspace" || e.key === "Delete") { + undoBatch(() => this.props.removeDoc(this.props.rowInfo.original)); + } + } + render() { const { children = null, rowInfo } = this.props; if (!rowInfo) { @@ -227,14 +235,14 @@ export class MovableRow extends React.Component<MovableRowProps> { if (this.props.rowWrapped) className += " row-wrapped"; return ( - <div className={className} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}> - <div className="collectionSchema-row-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> - <ReactTableDefaults.TrComponent> - <div className="row-dragger"> + <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}> + <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" 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, "onRight")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div> - </div> + </div> */} {children} </ReactTableDefaults.TrComponent> </div> diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 5226a60f1..ba0a259c5 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -6,7 +6,7 @@ border-style: solid; border-radius: $border-radius; box-sizing: border-box; - position: absolute; + position: relative; top: 0; width: 100%; height: 100%; @@ -25,7 +25,6 @@ .collectionSchemaView-tableContainer { width: 100%; height: 100%; - overflow: scroll; } .collectionSchemaView-dividerDragger { @@ -59,9 +58,7 @@ } .rt-thead { - width: calc(100% - 52px); - margin-left: 50px; - + width: 100%; z-index: 100; overflow-y: visible; @@ -96,7 +93,7 @@ } .rt-tbody { - width: calc(100% - 2px); + width: 100%; direction: rtl; overflow: visible; } @@ -164,16 +161,6 @@ .collectionSchema-col { height: 100%; - - .collectionSchema-col-wrapper { - &.col-before { - border-left: 2px solid red; - } - - &.col-after { - border-right: 2px solid red; - } - } } @@ -297,7 +284,6 @@ button.add-column { background-color: white; border: 1px solid lightgray; padding: 2px 3px; - overflow-x: hidden; &:not(:first-child) { border-top: 0; @@ -525,14 +511,21 @@ button.add-column { .collectionSchemaView-table { width: 100%; height: 100%; - overflow: visible; } .reactTable-sub { padding: 10px 30px; background-color: rgb(252, 252, 252); - width: calc(100% - 50px); - margin-left: 50px; + width: 100%; + + .rt-thead { + display:none; + } + .collectionSchemaView-table{ + border: solid 1px; + overflow: hidden; + } + .row-dragger { background-color: rgb(252, 252, 252); @@ -567,7 +560,6 @@ button.add-column { text-transform: uppercase; cursor: pointer; font-size: 10.5px; - padding: 10px; margin-left: 50px; margin-top: 10px; }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f67e049fd..a003de0d3 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -4,27 +4,26 @@ import { faCog, faPlus, faSortDown, faSortUp, faTable } from '@fortawesome/free- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; +import Measure from "react-measure"; import { Resize } from "react-table"; import "react-table/react-table.css"; import { Doc } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; -import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { Docs, DocumentOptions } from "../../documents/Documents"; +import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +import { Cast, NumCast } from "../../../fields/Types"; +import { TraceMobx } from "../../../fields/util"; +import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils"; +import { SnappingManager } from "../../util/SnappingManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss'; import '../DocumentDecorations.scss'; +import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; import { KeysDropdown } from "./CollectionSchemaHeaders"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; -import { setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils"; -import { SnappingManager } from "../../util/SnappingManager"; -import Measure from "react-measure"; import { SchemaTable } from "./SchemaTable"; -import { TraceMobx } from "../../../fields/util"; library.add(faCog, faPlus, faSortUp, faSortDown); library.add(faTable); @@ -170,6 +169,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @action setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => { const columns = this.columns; + columns.forEach(col => col.setDesc(undefined)); + const index = columns.findIndex(c => c.heading === columnField.heading); const column = columns[index]; column.setDesc(descending); @@ -310,7 +311,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @undoBatch @action - changeColumns = (oldKey: string, newKey: string, addNew: boolean) => { + changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => { const columns = this.columns; if (columns === undefined) { this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, "f1efeb")]); @@ -325,6 +326,20 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { column.setHeading(newKey); columns[index] = column; this.columns = columns; + if (filter) { + Doc.setDocFilter(this.props.Document, newKey, filter, "match"); + if (this.props.Document.selectedDoc !== undefined) { + const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc; + Doc.setDocFilter(doc, newKey, filter, "match"); + } + } + else { + this.props.Document._docFilters = undefined; + if (this.props.Document.selectedDoc !== undefined) { + const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc; + doc._docFilters = undefined; + } + } } } } @@ -591,6 +606,10 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } } + + + onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { + } render() { TraceMobx(); const menuContent = this.renderMenuContent; @@ -608,14 +627,15 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>} </Measure> </div>; - return <div className="collectionSchemaView-container" style={{ + overflow: this.props.overflow === true ? "auto" : undefined, pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined, - width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%" + width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", }} > <div className="collectionSchemaView-tableContainer" - style={{ width: `calc(100% - ${this.previewWidth()}px)` }} + style={{ backgroundColor: "white", width: `calc(100% - ${this.previewWidth()}px)` }} + onKeyPress={this.onKeyPress} onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cca78cf9f..fe3d57bdb 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -184,7 +184,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) if (found) { const top = found.getBoundingClientRect().top; const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); - smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); + smoothScroll(doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); } afterFocus && setTimeout(() => { if (afterFocus?.()) { } @@ -287,19 +287,31 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) } }); if (super.onInternalDrop(e, de)) { - const newDoc = de.complete.docDragData.droppedDocuments[0]; + const newDocs = de.complete.docDragData.droppedDocuments; const docs = this.childDocList; if (docs) { - if (targInd === -1) targInd = docs.length; - else targInd = docs.indexOf(this.filteredChildren[targInd]); - const srcInd = docs.indexOf(newDoc); - docs.splice(srcInd, 1); - docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, newDoc); + newDocs.map((doc, i) => { + console.log(doc.title); + if (i === 0) { + if (targInd === -1) targInd = docs.length; + else targInd = docs.indexOf(this.filteredChildren[targInd]); + const srcInd = docs.indexOf(doc); + docs.splice(srcInd, 1); + docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc); + } else if (i < (newDocs.length / 2)) { //glr: for some reason dragged documents are duplicated + if (targInd === -1) targInd = docs.length; + else targInd = docs.indexOf(newDocs[0]) + 1; + const srcInd = docs.indexOf(doc); + docs.splice(srcInd, 1); + docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc); + } + }); } } } return false; } + @undoBatch @action onExternalDrop = async (e: React.DragEvent): Promise<void> => { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 4042a070d..f193a9787 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -12,6 +12,7 @@ import { NumCast, StrCast, Cast } from "../../../fields/Types"; import { ImageField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; import { Docs, DocUtils } from "../../documents/Documents"; +import { DocumentType } from "../../documents/DocumentTypes"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; @@ -346,7 +347,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC </div> : (null); for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `; const chromeStatus = this.props.parent.props.Document._chromeStatus; - + const type = this.props.parent.props.Document.type; return <> {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView} { @@ -366,9 +367,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC {this.props.parent.children(this.props.docList, uniqueHeadings.length)} {singleColumn ? (null) : this.props.parent.columnDragger} </div> - {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? + {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== DocumentType.PRES) ? <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" - style={{ width: style.columnWidth / style.numGroupColumns }}> + style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 70 }}> <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} /> </div> : null} </div> diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 3ebc6baca..4025e25f9 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,7 +1,7 @@ import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx"; import { basename } from 'path'; import CursorField from "../../../fields/CursorField"; -import { Doc, Opt, Field } from "../../../fields/Doc"; +import { Doc, Opt, Field, DocListCast } from "../../../fields/Doc"; import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; @@ -112,9 +112,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; } @computed get childDocs() { + let rawdocs: (Doc | Promise<Doc>)[] = DocListCast(this.props.Document._searchDocs); - let rawdocs: (Doc | Promise<Doc>)[] = []; - if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list; + if (rawdocs.length !== 0) { + } else if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list; rawdocs = [this.dataField]; } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it. rawdocs = Cast(this.dataField, listSpec(Doc), null); @@ -126,11 +127,66 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: } const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc); + const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); + let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; + + const searchDocs = DocListCast(this.props.Document._searchDocs); + // if (searchDocs !== undefined && searchDocs.length > 0) { + // let newdocs: Doc[] = []; + // childDocs.forEach((el) => { + // searchDocs.includes(el) ? newdocs.push(el) : undefined; + // }); + // childDocs = newdocs; + // } + + let docsforFilter: Doc[] = childDocs; + if (searchDocs !== undefined && searchDocs.length > 0) { + docsforFilter = []; + // let newdocs: Doc[] = []; + // let newarray: Doc[] = []; + //while (childDocs.length > 0) { + //newarray = []; + childDocs.forEach((d) => { + if (d.data !== undefined) { + console.log(d); + let newdocs = DocListCast(d.data); + if (newdocs.length > 0) { + let vibecheck: boolean | undefined = undefined; + let newarray: Doc[] = []; + while (newdocs.length > 0) { + newarray = []; + newdocs.forEach((t) => { + if (d.data !== undefined) { + const newdocs = DocListCast(t.data); + newdocs.forEach((newdoc) => { + newarray.push(newdoc); + }); + } + if (searchDocs.includes(t)) { + vibecheck = true; + } + }); + newdocs = newarray; + } + if (vibecheck === true) { + docsforFilter.push(d); + } + } + } + if (searchDocs.includes(d)) { + docsforFilter.push(d); + } + }); + //childDocs = newarray; + //} + } + childDocs = docsforFilter; + + const docFilters = this.docFilters(); - const viewSpecScript = ScriptCast(this.props.Document.viewSpecScript); const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []); - return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, docFilters, docRangeFilters, viewSpecScript); + return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript); } @action @@ -436,4 +492,3 @@ import { CollectionView, CollectionViewType } from "./CollectionView"; import { SelectionManager } from "../../util/SelectionManager"; import { OverlayView } from "../OverlayView"; import { setTimeout } from "timers"; - diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 50f0534bd..c9bf82406 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -22,7 +22,7 @@ ul { list-style: none; padding-left: 20px; - margin-bottom: 1px;// otherwise vertical scrollbars may pop up for no apparent reason.... + margin-bottom: 1px; // otherwise vertical scrollbars may pop up for no apparent reason.... } @@ -35,7 +35,7 @@ width: 15px; color: $intermediate-color; margin-top: 3px; - transform: scale(1.3, 1.3); + transform: scale(1.3, 1.3); border: #80808030 1px solid; border-radius: 4px; } @@ -67,8 +67,10 @@ margin-left: 3px; display: none; } + .collectionTreeView-keyHeader:hover { background: #797777; + cursor: pointer; } .collectionTreeView-subtitle { @@ -89,8 +91,10 @@ height: 17px; width: 15px; } + .treeViewItem-openRight:hover { background: #797777; + cursor: pointer; } .treeViewItem-border { @@ -106,10 +110,12 @@ .editableView-container-editing-oneLine { min-width: 15px; } + .documentView-node-topmost { width: unset; } - > svg { + + >svg { display: none; } @@ -119,7 +125,8 @@ .collectionTreeView-keyHeader { display: inherit; } - > svg { + + >svg { display: inherit; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 44875ac1e..dcd5a31f6 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -74,7 +74,7 @@ export enum CollectionViewType { Pile = "pileup" } export interface CollectionViewCustomProps { - filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + filterAddDocument?: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt<Doc>; // specify a layout Doc template to use for children of the collection childLayoutString?: string; // specify a layout string to use for children of the collection childOpacity?: () => number; @@ -88,6 +88,7 @@ export interface CollectionRenderProps { active: () => boolean; whenActiveChanged: (isActive: boolean) => void; PanelWidth: () => number; + PanelHeight: () => number; ChildLayoutTemplate?: () => Doc; ChildLayoutString?: string; } @@ -520,6 +521,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus </div> <div className="collectionTimeView-tree" key="tree"> <CollectionTreeView + PanelPosition={""} Document={facetCollection} DataDoc={facetCollection} fieldKey={`${this.props.fieldKey}-filter`} @@ -571,6 +573,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus active: this.active, whenActiveChanged: this.whenActiveChanged, PanelWidth: this.bodyPanelWidth, + PanelHeight: this.props.PanelHeight, ChildLayoutTemplate: this.childLayoutTemplate, ChildLayoutString: this.childLayoutString, }; @@ -579,7 +582,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus return (<div className={"collectionView"} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}> {this.showIsTagged()} - <div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}> + <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition === "absolute" ? "flex" : "", justifyContent: this.props.PanelPosition === "absolute" ? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}> {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)} </div> {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx index 7e2840c2c..75d484cbe 100644 --- a/src/client/views/collections/SchemaTable.tsx +++ b/src/client/views/collections/SchemaTable.tsx @@ -11,22 +11,22 @@ import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { ComputedField } from "../../../fields/ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../fields/Types"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types"; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils"; import { Docs, DocumentOptions } from "../../documents/Documents"; +import { DocumentType } from "../../documents/DocumentTypes"; import { CompileScript, Transformer, ts } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss'; import { ContextMenu } from "../ContextMenu"; import '../DocumentDecorations.scss'; -import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaDateCell } from "./CollectionSchemaCells"; +import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; +import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells"; import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders"; import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC"; import "./CollectionSchemaView.scss"; import { CollectionView } from "./CollectionView"; -import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; -import { emptyFunction, returnZero, returnOne, returnFalse, returnEmptyFilter, emptyPath } from "../../../Utils"; -import { TouchScrollableMenuItem } from "../TouchScrollableMenu"; enum ColumnType { @@ -128,7 +128,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { } @computed get sorted(): SortingRule[] { return this.props.columns.reduce((sorted, shf) => { - shf.desc && sorted.push({ id: shf.heading, desc: shf.desc }); + shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc }); return sorted; }, [] as SortingRule[]); } @@ -160,7 +160,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { const focusedCol = this._focusedCell.col; const isEditable = !this.props.headerIsEditing; - if (this.childDocs.reduce((found, doc) => found || doc.type === "collection", false)) { + if (this.childDocs.reduce((found, doc) => found || doc.type === DocumentType.COL, false)) { columns.push( { expander: true, @@ -177,6 +177,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { } ); } + console.log(columns); const cols = this.props.columns.map(col => { @@ -188,7 +189,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { addNew={false} onSelect={this.props.changeColumns} setIsEditing={this.props.setHeaderIsEditing} - + docs={this.props.childDocs} // try commenting this out width={"100%"} />; @@ -216,21 +217,21 @@ export class SchemaTable extends React.Component<SchemaTableProps> { className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", - display: "flex" + display: "flex", cursor: "default", height: "100%", }}> - <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingLeft: "7px" }} /> - <div className="keys-dropdown" - style={{ display: "inline", zIndex: 1000 }}> - {keysDropdown} - </div> + <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px" }} /> + {/* <div className="keys-dropdown" + style={{ display: "inline", zIndex: 1000 }}> */} + {keysDropdown} + {/* </div> */} <div onClick={e => this.changeSorting(col)} - style={{ paddingRight: "6px", marginLeft: "4px", display: "inline" }}> - <FontAwesomeIcon icon={sortIcon} size="sm" /> - </div> - <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} - style={{ float: "right", paddingRight: "6px" }}> - <FontAwesomeIcon icon={"cog"} size="sm" /> + style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit" }}> + <FontAwesomeIcon icon={sortIcon} size="lg" /> </div> + {/* <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} + style={{ float: "right", paddingRight: "6px", zIndex: 1, background: "inherit" }}> + <FontAwesomeIcon icon={"compass"} size="sm" /> + </div> */} </div>; return { @@ -283,13 +284,63 @@ export class SchemaTable extends React.Component<SchemaTableProps> { Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />, accessor: (doc: Doc) => 0, id: "add", - Cell: (rowProps: CellInfo) => <></>, + Cell: (rowProps: CellInfo) => { + const rowIndex = rowProps.index; + const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!); + const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused; + const props: CellProps = { + row: rowIndex, + col: columnIndex, + rowProps: rowProps, + isFocused: isFocused, + changeFocusedCellByIndex: this.changeFocusedCellByIndex, + CollectionView: this.props.CollectionView, + ContainingCollection: this.props.ContainingCollectionView, + Document: this.props.Document, + fieldKey: this.props.fieldKey, + renderDepth: this.props.renderDepth, + addDocTab: this.props.addDocTab, + pinToPres: this.props.pinToPres, + moveDocument: this.props.moveDocument, + setIsEditing: this.setCellIsEditing, + isEditable: isEditable, + setPreviewDoc: this.props.setPreviewDoc, + setComputed: this.setComputed, + getField: this.getField, + showDoc: this.showDoc, + }; + + return <CollectionSchemaButtons {...props} />; + }, width: 28, resizable: false }); + console.log(columns); return columns; } + + + @action + nextHighlight = (e: React.MouseEvent, doc: Doc) => { + e.preventDefault(); + e.stopPropagation(); + doc.searchMatch = false; + console.log(doc.searchMatch); + setTimeout(() => doc.searchMatch = true, 0); + console.log(doc.searchMatch); + + doc.searchIndex = NumCast(doc.searchIndex); + } + + @action + nextHighlight2 = (doc: Doc) => { + + doc.searchMatchAlt = false; + setTimeout(() => doc.searchMatchAlt = true, 0); + doc.searchIndex = NumCast(doc.searchIndex); + } + constructor(props: SchemaTableProps) { super(props); // convert old schema columns (list of strings) into new schema columns (list of schema header fields) @@ -574,7 +625,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> { return <div className="collectionSchemaView-table" onPointerDown={this.props.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} > {this.reactTable} - <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div> + {StrCast(this.props.Document.type) !== "search" ? <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div> + : undefined} {!this._showDoc ? (null) : <div className="collectionSchemaView-documentPreview" //onClick={() => { this.onOpenClick(); }} style={{ diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 92aee3776..2b07c4efb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -13,16 +13,153 @@ } .collectionfreeformview-viewdef { - > .collectionFreeFormDocumentView-container { + >.collectionFreeFormDocumentView-container { pointer-events: none; + .contentFittingDocumentDocumentView-previewDoc { pointer-events: all; } } + + svg.presPaths { + position: absolute; + z-index: 100000; + overflow: visible; + } + + svg.presPaths-hidden { + display: none; + } } .collectionfreeformview-none { touch-action: none; + + svg.presPaths { + position: absolute; + z-index: 100000; + overflow: visible; + } + + svg.presPaths-hidden { + display: none; + } +} + +.pathOrder { + position: absolute; + z-index: 200000; + + .pathOrder-frame { + position: absolute; + width: 40; + text-align: center; + font-size: 30; + background-color: #69a6db; + font-family: Roboto; + font-weight: 300; + } +} + +.progressivizeButton { + position: absolute; + display: grid; + grid-template-columns: auto 20px auto; + transform: translate(-105%, 0); + align-items: center; + border: black solid 1px; + border-radius: 3px; + justify-content: center; + width: 40; + z-index: 30000; + height: 20; + overflow: hidden; + background-color: #d5dce2; + transition: all 1s; + + .progressivizeButton-prev:hover { + color: #5a9edd; + } + + .progressivizeButton-frame { + justify-self: center; + text-align: center; + width: 15px; + } + + .progressivizeButton-next:hover { + color: #5a9edd; + } +} + +.resizable { + background: rgba(0, 0, 0, 0.2); + width: 100px; + height: 100px; + position: absolute; + top: 100px; + left: 100px; + + .resizers { + width: 100%; + height: 100%; + border: 3px solid #69a6db; + box-sizing: border-box; + + .resizer { + position: absolute; + width: 10px; + height: 10px; + border-radius: 50%; + /*magic to turn square into circle*/ + background: white; + border: 3px solid #69a6db; + } + + .resizer.top-left { + left: -3px; + top: -3px; + cursor: nwse-resize; + /*resizer cursor*/ + } + + .resizer.top-right { + right: -3px; + top: -3px; + cursor: nesw-resize; + } + + .resizer.bottom-left { + left: -3px; + bottom: -3px; + cursor: nesw-resize; + } + + .resizer.bottom-right { + right: -3px; + bottom: -3px; + cursor: nwse-resize; + } + } +} + +.progressivizeMove-frame { + width: 20px; + border-radius: 2px; + z-index: 100000; + color: white; + text-align: center; + background-color: #5a9edd; + transform: translate(-110%, 110%); +} + +.progressivizeButton:hover { + box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5); + + .progressivizeButton-frame { + background-color: #5a9edd; + color: white; + } } .collectionFreeform-customText { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index badbc48a1..ffeb3024d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc"; @@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); +import { PresBox } from "../../nodes/PresBox"; import { SearchUtil } from "../../../util/SearchUtil"; import { LinkManager } from "../../../util/LinkManager"; @@ -76,7 +77,7 @@ export type collectionFreeformViewProps = { forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: boolean; - scaleField?: string; // used by formattedTextBox when displaying a sidebar freeform view which needs its own scale field + scaleField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) }; @@ -213,7 +214,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const layoutDoc = Doc.Layout(d); if (this.Document.currentFrame !== undefined) { const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000)); - CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.opacity); + CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.opacity); } else { d.x = x + NumCast(d.x) - dropPos[0]; d.y = y + NumCast(d.y) - dropPos[1]; @@ -911,7 +912,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P // !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); // } else { if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { - if (!doc.z) this.setPan(newPanX, newPanY, "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow + // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active... + if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition || doc.presTransition === 0 ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow } Doc.BrushDoc(this.props.Document); this.props.focus(this.props.Document); @@ -1257,7 +1259,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" }); - appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); + optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" }); if (!Doc.UserDoc().noviceMode) { optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); optionItems.push({ description: `${this.Document._freeformLOD ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" }); @@ -1399,6 +1401,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} + presPaths={BoolCast(this.Document.presPathView)} + progressivize={BoolCast(this.Document.editProgressivize)} + zoomProgressivize={BoolCast(this.Document.editZoomProgressivize)} transition={Cast(this.layoutDoc._viewTransition, "string", null)} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> @@ -1482,11 +1487,69 @@ interface CollectionFreeFormViewPannableContentsProps { viewDefDivClick?: ScriptField; children: () => JSX.Element[]; transition?: string; + presPaths?: boolean; + progressivize?: boolean; + zoomProgressivize?: boolean; } @observer class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{ + @computed get zoomProgressivize() { + if (this.props.zoomProgressivize) { + console.log("should render"); + return ( + <> + {PresBox.Instance.zoomProgressivizeContainer} + </> + ); + } + } + + @computed get progressivize() { + if (this.props.progressivize) { + console.log("should render"); + return ( + <> + {PresBox.Instance.progressivizeChildDocs} + </> + ); + } + } + + @computed get presPaths() { + const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden"); + if (this.props.presPaths) { + return ( + <> + <div>{PresBox.Instance.order}</div> + <svg className={presPaths}> + <defs> + <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth"> + <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" /> + </marker> + <marker id="square" markerWidth="3" markerHeight="3" overflow="visible" + refX="5" refY="5" orient="auto" markerUnits="strokeWidth"> + <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" /> + </marker> + <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4" + orient="auto" overflow="visible"> + <rect x="1" y="1" width="5" height="5" fill="#69a6db" /> + </marker> + + <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7" + orient="auto" overflow="visible"> + <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" /> + </marker> + </defs>; + {PresBox.Instance.paths} + </svg> + </> + ); + } + } + render() { + // trace(); const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none"); const cenx = this.props.centeringShiftX(); const ceny = this.props.centeringShiftY(); @@ -1499,6 +1562,9 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF transition: this.props.transition }}> {this.props.children()} + {this.presPaths} + {this.progressivize} + {this.zoomProgressivize} </div>; } } diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss index 7b5d611f3..fef1db9aa 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss @@ -5,8 +5,8 @@ font-family: "Noto Sans"; cursor: auto; - overflow-x: visible; - overflow-y: visible; + overflow-x: hidden; + overflow-y: scroll; .propertiesView-title { background-color: rgb(159, 159, 159); @@ -41,7 +41,7 @@ font-size: 12.5px; &:hover { - cursor: pointer; + cursor: text; } } @@ -586,6 +586,27 @@ } } +.propertiesView-presSelected { + border-top: solid 1px darkgrey; + width: 100%; + padding-top: 5px; + font-family: Roboto; + font-weight: 500; + display: inline-flex; + + .propertiesView-selectedList { + border-left: solid 1px darkgrey; + margin-left: 10px; + padding-left: 5px; + + .selectedList-items { + font-size: 12; + font-weight: 300; + margin-top: 1; + } + } +} + .widthAndDash { .width { @@ -615,6 +636,7 @@ display: flex; margin-bottom: 3px; + margin-left: 4px; .arrows-head { @@ -648,7 +670,7 @@ .dashed { display: flex; - margin-left: 74px; + margin-left: 64px; margin-bottom: 6px; .dashed-title { @@ -660,4 +682,15 @@ margin-top: 2px; } } +} + +.editable-title { + border: none; + padding: 6px; + padding-bottom: 2px; + + + &:hover { + border: 0.75px solid rgb(122, 28, 28); + } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx index 81202b126..d22c00b1f 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx @@ -19,9 +19,16 @@ import SharingManager from "../../../util/SharingManager"; import { DocumentType } from "../../../documents/DocumentTypes"; import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util"; import { InkField } from "../../../../fields/InkField"; -import { undoBatch } from "../../../util/UndoManager"; +import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { ColorState, SketchPicker } from "react-color"; import "./FormatShapePane.scss"; +import { discovery_v1 } from "googleapis"; +import { PresBox } from "../../nodes/PresBox"; +import { DocumentManager } from "../../../util/DocumentManager"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; + // import * as fa from '@fortawesome/free-solid-svg-icons'; // import { library } from "@fortawesome/fontawesome-svg-core"; @@ -37,14 +44,21 @@ interface PropertiesViewProps { @observer export class PropertiesView extends React.Component<PropertiesViewProps> { + private _widthUndo?: UndoManager.Batch; @computed get MAX_EMBED_HEIGHT() { return 200; } @computed get selectedDocumentView() { if (SelectionManager.SelectedDocuments().length) { return SelectionManager.SelectedDocuments()[0]; + } else if (PresBox.Instance._selectedArray.length >= 1) { + return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc); } else { return undefined; } } + @computed get isPres(): boolean { + if (this.selectedDoc?.type === DocumentType.PRES) return true; + return false; + } @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; } @@ -58,6 +72,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { @observable openTransform: boolean = true; // @observable selectedUser: string = ""; // @observable addButtonPressed: boolean = false; + //Pres Trails booleans: + @observable openAddSlide: boolean = true; + @observable openPresentationTools: boolean = true; + @observable openPresTransitions: boolean = true; + @observable openPresProgressivize: boolean = true; + @observable openSlideOptions: boolean = true; + + @observable inActions: boolean = false; + @observable _controlBtn: boolean = false; + @observable _lock: boolean = false; @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; } @@ -156,7 +180,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); const rows: JSX.Element[] = []; for (const key of Object.keys(ids).slice().sort()) { - if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL") + if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL" && key !== "UseCors") || key[0] === "#" || key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) { @@ -236,7 +260,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { rootSelected={returnFalse} treeViewDoc={undefined} backgroundColor={() => "lightgrey"} - fitToBox={false} + fitToBox={true} FreezeDimensions={true} NativeWidth={layoutDoc.type === StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero} @@ -259,6 +283,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { bringToFront={returnFalse} ContentScaling={returnOne} dontRegisterView={true} + dropAction={undefined} /> </div>; } else { @@ -380,20 +405,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { />; } - @undoBatch @action toggleCheckbox = () => { this.layoutFields = !this.layoutFields; } @computed get editableTitle() { - return <EditableView + return <div className="editable-title"><EditableView key="editableView" contents={StrCast(this.selectedDoc?.title)} height={25} fontSize={14} GetValue={() => StrCast(this.selectedDoc?.title)} - SetValue={this.setTitle} />; + SetValue={this.setTitle} /> </div>; } @undoBatch @@ -430,15 +454,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { var index = 0; if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { doc.rotation = Number(doc.rotation) + Number(angle); - const ink = Cast(doc.data, InkField)?.inkData; - if (ink) { - + const inks = Cast(doc.data, InkField)?.inkData; + if (inks) { const newPoints: { X: number, Y: number }[] = []; - for (var i = 0; i < ink.length; i++) { - const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X; - const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y; + inks.forEach(ink => { + const newX = Math.cos(angle) * (ink.X - _centerPoints[index].X) - Math.sin(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].X; + const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y; newPoints.push({ X: newX, Y: newY }); - } + }); doc.data = new InkField(newPoints); const xs = newPoints.map(p => p.X); const ys = newPoints.map(p => p.Y); @@ -455,20 +478,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } } - @observable _controlBtn: boolean = false; - @observable _lock: boolean = false; + @computed get controlPointsButton() { return <div className="inking-button"> <Tooltip title={<><div className="dash-tooltip">{"Edit points"}</div></>}> - <div className="inking-button-points" onPointerDown={action(() => this._controlBtn = !this._controlBtn)} style={{ backgroundColor: this._controlBtn ? "black" : "" }}> + <div className="inking-button-points" onPointerDown={action(() => FormatShapePane.Instance._controlBtn = !FormatShapePane.Instance._controlBtn)} style={{ backgroundColor: FormatShapePane.Instance._controlBtn ? "black" : "" }}> <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" /> </div> </Tooltip> - <Tooltip title={<><div className="dash-tooltip">{this._lock ? "Unlock points" : "Lock points"}</div></>}> - <div className="inking-button-lock" onPointerDown={action(() => this._lock = !this._lock)} > - <FontAwesomeIcon icon={this._lock ? "unlock" : "lock"} color="white" size="lg" /> + <Tooltip title={<><div className="dash-tooltip">{FormatShapePane.Instance._lock ? "Unlock ratio" : "Lock ratio"}</div></>}> + <div className="inking-button-lock" onPointerDown={action(() => FormatShapePane.Instance._lock = !FormatShapePane.Instance._lock)} > + <FontAwesomeIcon icon={FormatShapePane.Instance._lock ? "lock" : "unlock"} color="white" size="lg" /> </div> </Tooltip> <Tooltip title={<><div className="dash-tooltip">{"Rotate 90˚"}</div></>}> @@ -523,12 +545,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { const oldX = NumCast(this.selectedDoc?.x); const oldY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === "up" ? 10 : - 10)); - this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height))); + FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height))); const doc = this.selectedDoc; if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) { - console.log(doc.x, doc.y, doc._height, doc._width); const ink = Cast(doc.data, InkField)?.inkData; - console.log(ink); if (ink) { const newPoints: { X: number, Y: number }[] = []; for (var j = 0; j < ink.length; j++) { @@ -547,12 +567,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { const oX = NumCast(this.selectedDoc?.x); const oY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === "up" ? 10 : - 10)); - this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width))); + FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width))); const docu = this.selectedDoc; if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) { - console.log(docu.x, docu.y, docu._height, docu._width); const ink = Cast(docu.data, InkField)?.inkData; - console.log(ink); if (ink) { const newPoints: { X: number, Y: number }[] = []; for (var j = 0; j < ink.length; j++) { @@ -570,7 +588,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { getField(key: string) { //if (this.selectedDoc) { - return Field.toString(this.selectedDoc![key] as Field); + return Field.toString(this.selectedDoc?.[key] as Field); // } else { // return undefined as Opt<string>; // } @@ -587,17 +605,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { set shapeWid(value) { const oldWidth = NumCast(this.selectedDoc?._width); this.selectedDoc && (this.selectedDoc._width = Number(value)); - this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth); + FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth); } set shapeHgt(value) { const oldHeight = NumCast(this.selectedDoc?._height); this.selectedDoc && (this.selectedDoc._height = Number(value)); - this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight); + FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight); } - @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); } - @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); } - @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); } + @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => { if (!isNaN(Number(val))) { this.shapeHgt = val; } return true; }, "H:", "wid", this.shapeWid, (val: string) => { if (!isNaN(Number(val))) { this.shapeWid = val; } return true; }, "W:"); } + @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeXps = val; } return true; }, "X:", "Yps", this.shapeYps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeYps = val; } return true; }, "Y:"); } + @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, "∠:", "rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, ""); } + @observable private _fillBtn = false; @observable private _lineBtn = false; @@ -611,14 +630,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); } set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); } - colorButton(value: string, setter: () => {}) { - return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}> - <div className="color-button-preview" style={{ - backgroundColor: value ?? "121212", width: 15, height: 15, - display: value === "" || value === "transparent" ? "none" : "" - }} /> - {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""} - </div>; + colorButton(value: string, type: string, setter: () => {}) { + return <Flyout anchorPoint={anchorPoints.LEFT_TOP} + content={type === "fill" ? this.fillPicker : this.linePicker}> + <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}> + <div className="color-button-preview" style={{ + backgroundColor: value ?? "121212", width: 15, height: 15, + display: value === "" || value === "transparent" ? "none" : "" + }} /> + {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""} + </div> + </Flyout>; + } @undoBatch @@ -644,8 +667,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { color={type === "stk" ? this.colorStk : this.colorFil} />; } - @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); } - @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); } + @computed get fillButton() { return this.colorButton(this.colorFil, "fill", () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); } + @computed get lineButton() { return this.colorButton(this.colorStk, "line", () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); } @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); } @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); } @@ -662,8 +685,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { <div className="stroke-button">{this.lineButton}</div> </div> </div> - {this._fillBtn ? this.fillPicker : ""} - {this._lineBtn ? this.linePicker : ""} + {/* {this._fillBtn ? this.fillPicker : ""} + {this._lineBtn ? this.linePicker : ""} */} </div>; } @@ -714,7 +737,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { </div> <input className="width-range" type="range" defaultValue={Number(this.widthStk)} min={1} max={100} - onChange={undoBatch(action((e) => this.widthStk = e.target.value))} /> + onChange={(action((e) => this.widthStk = e.target.value))} + onMouseDown={(e) => { this._widthUndo = UndoManager.StartBatch("width undo"); }} + onMouseUp={(e) => { this._widthUndo?.end(); this._widthUndo = undefined; }} + /> </div> <div className="arrows"> @@ -732,7 +758,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { </div> </div> <div className="dashed"> - <div className="dashed-title">Dash:</div> + <div className="dashed-title">Dashed Line:</div> <input key="markHead" className="dashed-input" type="checkbox" checked={this.dashdStk === "2"} onChange={this.changeDash} /> @@ -773,56 +799,58 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { // } render() { - if (!this.selectedDoc) { + if (!this.selectedDoc && !this.isPres) { return <div className="propertiesView" style={{ width: this.props.width }}> <div className="propertiesView-title" style={{ width: this.props.width }}> No Document Selected - <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}> - <FontAwesomeIcon icon="times" color="black" size="xs" /> - </div> </div> </div>; - } - - const novice = Doc.UserDoc().noviceMode; - return <div className="propertiesView" style={{ width: this.props.width }} > - <div className="propertiesView-title" style={{ width: this.props.width }}> - Properties - <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}> - <FontAwesomeIcon icon="times" color="black" size="sm" /> - </div> - </div> - <div className="propertiesView-name"> - {this.editableTitle} - </div> - <div className="propertiesView-settings"> - <div className="propertiesView-settings-title" - onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })} - style={{ backgroundColor: this.openActions ? "black" : "" }}> - Actions - <div className="propertiesView-settings-title-icon"> - <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" /> + } else { + const novice = Doc.UserDoc().noviceMode; + + if (this.selectedDoc && !this.isPres) { + return <div className="propertiesView" style={{ + width: this.props.width, + // overflowY: this.inActions ? "visible" : "scroll" + }} > + <div className="propertiesView-title" style={{ width: this.props.width }}> + Properties + {/* <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}> + <FontAwesomeIcon icon="times" color="black" size="sm" /> + </div> */} </div> - </div> - {!this.openActions ? (null) : - <div className="propertiesView-settings-content"> - <PropertiesButtons /> - </div>} - </div> - <div className="propertiesView-sharing"> - <div className="propertiesView-sharing-title" - onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })} - style={{ backgroundColor: this.openSharing ? "black" : "" }}> - Sharing {"&"} Permissions - <div className="propertiesView-sharing-title-icon"> - <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" /> + <div className="propertiesView-name"> + {this.editableTitle} </div> - </div> - {!this.openSharing ? (null) : - <div className="propertiesView-sharing-content"> - {this.sharingTable} - {/* <div className="change-buttons"> + <div className="propertiesView-settings" onPointerEnter={() => runInAction(() => { this.inActions = true; })} + onPointerLeave={action(() => this.inActions = false)}> + <div className="propertiesView-settings-title" + onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })} + style={{ backgroundColor: this.openActions ? "black" : "" }}> + Actions + <div className="propertiesView-settings-title-icon"> + <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {!this.openActions ? (null) : + <div className="propertiesView-settings-content"> + <PropertiesButtons /> + </div>} + </div> + <div className="propertiesView-sharing"> + <div className="propertiesView-sharing-title" + onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })} + style={{ backgroundColor: this.openSharing ? "black" : "" }}> + Sharing {"&"} Permissions + <div className="propertiesView-sharing-title-icon"> + <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {!this.openSharing ? (null) : + <div className="propertiesView-sharing-content"> + {this.sharingTable} + {/* <div className="change-buttons"> <button onPointerDown={action(() => this.addButtonPressed = !this.addButtonPressed)} > @@ -852,70 +880,156 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { </select> : null} </div> */} - </div>} - </div> + </div>} + </div> - {!this.isInk ? (null) : - <div className="propertiesView-appearance"> - <div className="propertiesView-appearance-title" - onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })} - style={{ backgroundColor: this.openAppearance ? "black" : "" }}> - Appearance - <div className="propertiesView-appearance-title-icon"> - <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" /> + {!this.isInk ? (null) : + <div className="propertiesView-appearance"> + <div className="propertiesView-appearance-title" + onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })} + style={{ backgroundColor: this.openAppearance ? "black" : "" }}> + Appearance + <div className="propertiesView-appearance-title-icon"> + <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {!this.openAppearance ? (null) : + <div className="propertiesView-appearance-content"> + {this.appearanceEditor} + </div>} + </div>} + + {this.isInk ? <div className="propertiesView-transform"> + <div className="propertiesView-transform-title" + onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })} + style={{ backgroundColor: this.openTransform ? "black" : "" }}> + Transform + <div className="propertiesView-transform-title-icon"> + <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> </div> + {this.openTransform ? <div className="propertiesView-transform-content"> + {this.transformEditor} + </div> : null} + </div> : null} + + <div className="propertiesView-fields"> + <div className="propertiesView-fields-title" + onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })} + style={{ backgroundColor: this.openFields ? "black" : "" }}> + <div className="propertiesView-fields-title-name"> + Fields {"&"} Tags + <div className="propertiesView-fields-title-icon"> + <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + </div> + {!novice && this.openFields ? <div className="propertiesView-fields-checkbox"> + {this.fieldsCheckbox} + <div className="propertiesView-fields-checkbox-text">Layout</div> + </div> : null} + {!this.openFields ? (null) : + <div className="propertiesView-fields-content"> + {novice ? this.noviceFields : this.expandedField} + </div>} </div> - {!this.openAppearance ? (null) : - <div className="propertiesView-appearance-content"> - {this.appearanceEditor} - </div>} - </div>} - - {this.isInk ? <div className="propertiesView-transform"> - <div className="propertiesView-transform-title" - onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })} - style={{ backgroundColor: this.openTransform ? "black" : "" }}> - Transform - <div className="propertiesView-transform-title-icon"> - <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" /> + <div className="propertiesView-layout"> + <div className="propertiesView-layout-title" + onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })} + style={{ backgroundColor: this.openLayout ? "black" : "" }}> + Layout + <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}> + <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null} </div> - </div> - {this.openTransform ? <div className="propertiesView-transform-content"> - {this.transformEditor} - </div> : null} - </div> : null} - - <div className="propertiesView-fields"> - <div className="propertiesView-fields-title" - onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })} - style={{ backgroundColor: this.openFields ? "black" : "" }}> - <div className="propertiesView-fields-title-name"> - Fields {"&"} Tags - <div className="propertiesView-fields-title-icon"> - <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div>; + } + if (this.isPres) { + return <div className="propertiesView" style={{ width: this.props.width }} > + <div className="propertiesView-title" style={{ width: this.props.width }}> + Presentation + <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}> + <FontAwesomeIcon icon="times" color="black" size="sm" /> </div> </div> - </div> - {!novice && this.openFields ? <div className="propertiesView-fields-checkbox"> - {this.fieldsCheckbox} - <div className="propertiesView-fields-checkbox-text">Layout</div> - </div> : null} - {!this.openFields ? (null) : - <div className="propertiesView-fields-content"> - {novice ? this.noviceFields : this.expandedField} - </div>} - </div> - <div className="propertiesView-layout"> - <div className="propertiesView-layout-title" - onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })} - style={{ backgroundColor: this.openLayout ? "black" : "" }}> - Layout - <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}> - <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" /> + <div className="propertiesView-name"> + {this.editableTitle} + <div className="propertiesView-presSelected"> + {PresBox.Instance._selectedArray.length} selected + <div className="propertiesView-selectedList"> + {PresBox.Instance.listOfSelected} + </div> + </div> </div> - </div> - {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null} - </div> - </div>; + <div className="propertiesView-settings"> + <div className="propertiesView-settings-title" + onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })} + style={{ backgroundColor: this.openAddSlide ? "black" : "" }}> + <FontAwesomeIcon icon={"plus"} /> Add new slide + <div className="propertiesView-settings-title-icon"> + <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openAddSlide ? <div className="propertiesView-settings-content"> + {PresBox.Instance.newDocumentDropdown} + </div> : null} + </div> + <div className="propertiesView-sharing"> + <div className="propertiesView-sharing-title" + onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })} + style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}> + <FontAwesomeIcon icon={"rocket"} /> Transitions + <div className="propertiesView-sharing-title-icon"> + <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openPresTransitions ? <div className="propertiesView-sharing-content"> + {PresBox.Instance.transitionDropdown} + </div> : null} + </div> + <div className="propertiesView-sharing"> + <div className="propertiesView-sharing-title" + onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })} + style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}> + <FontAwesomeIcon icon={"tasks"} /> Progressivize + <div className="propertiesView-sharing-title-icon"> + <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openPresProgressivize ? <div className="propertiesView-sharing-content"> + {PresBox.Instance.progressivizeDropdown} + </div> : null} + </div> + <div className="propertiesView-sharing"> + <div className="propertiesView-sharing-title" + onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })} + style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}> + <FontAwesomeIcon icon={"cog"} /> {PresBox.Instance.stringType} options + <div className="propertiesView-sharing-title-icon"> + <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openSlideOptions ? <div className="propertiesView-sharing-content"> + {PresBox.Instance.optionsDropdown} + </div> : null} + </div> + <div className="propertiesView-sharing"> + <div className="propertiesView-sharing-title" + onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })} + style={{ backgroundColor: this.openSharing ? "black" : "" }}> + Sharing {"&"} Permissions + <div className="propertiesView-sharing-title-icon"> + <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" /> + </div> + </div> + {this.openSharing ? <div className="propertiesView-sharing-content"> + {this.sharingTable} + </div> : null} + </div> + </div>; + } + } } -}
\ No newline at end of file +}
\ No newline at end of file diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 21f77e47b..e6ac7021a 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -240,7 +240,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { w: Math.min(w, this.numCols), // reduces width if greater than numCols static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout.lockedPosition, false) // checks if the lock position item has been selected in the context menu })) : - this.savedLayoutList.map((layout, index) => Object.assign(layout, this.unflexedPosition(index))); + this.savedLayoutList.map((layout, index) => { Object.assign(layout, this.unflexedPosition(index)); return layout; }); } /** |
