From 95429adb77402ce2a218c5585ceef4db0c8494db Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Jul 2020 23:55:59 -0400 Subject: converted collectionChrome into a menu bar --- src/client/views/collections/CollectionMenu.tsx | 443 ++++++++++++++++++++++-- 1 file changed, 415 insertions(+), 28 deletions(-) (limited to 'src/client/views/collections/CollectionMenu.tsx') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index d79ffffa1..1644bc726 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,19 +1,20 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, reaction, runInAction } from "mobx"; +import { action, computed, observable, reaction, runInAction, Lambda } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt } 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 } from "./CollectionView"; +import { CollectionViewType, CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils"; -import { CollectionGridViewChrome } from "./CollectionViewChromes"; import { DragManager } from "../../util/DragManager"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { List } from "../../../fields/List"; -import { SelectionManager } from "../../util/SelectionManager"; +import { EditableView } from "../EditableView"; +import { Id } from "../../../fields/FieldSymbols"; +import { listSpec } from "../../../fields/Schema"; @observer export default class CollectionMenu extends AntimodeMenu { @@ -33,19 +34,10 @@ export default class CollectionMenu extends AntimodeMenu { Doc.UserDoc()["menuCollections-pinned"] = this.Pinned = !this.Pinned; } - @computed get aButton() { - return
- -
; - } - render() { return this.getElement([ - this.aButton, !this.SelectedCollection ? <> : , - ]); @@ -55,7 +47,6 @@ export default class CollectionMenu extends AntimodeMenu { interface CollectionViewChromeProps { CollectionView: CollectionView; type: CollectionViewType; - collapse?: (value: boolean) => any; } const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); @@ -154,12 +145,12 @@ export class CollectionViewBaseChrome extends React.Component); - // case CollectionViewType.Stacking: return (); - // case CollectionViewType.Schema: return (); - // case CollectionViewType.Tree: return (); - // case CollectionViewType.Masonry: return (); - // case CollectionViewType.Carousel3D: return (); - // case CollectionViewType.Grid: return (); + case CollectionViewType.Stacking: return (); + case CollectionViewType.Schema: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Masonry: return (); + case CollectionViewType.Carousel3D: return (); + case CollectionViewType.Grid: return (); default: return null; } } @@ -230,8 +221,7 @@ export class CollectionViewBaseChrome extends React.Component + return
@@ -258,7 +248,7 @@ export class CollectionViewBaseChrome extends React.Component { - const currentFrame = NumCast(this.Document.currentFrame); + const currentFrame = Cast(this.Document.currentFrame, "number", null); if (currentFrame === undefined) { this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); @@ -305,7 +295,7 @@ export class CollectionFreeFormViewChrome extends React.Component { - const currentFrame = NumCast(this.Document.currentFrame); + const currentFrame = Cast(this.Document.currentFrame, "number", null); if (currentFrame === undefined) { this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); @@ -315,7 +305,7 @@ export class CollectionFreeFormViewChrome extends React.Component +
@@ -329,3 +319,400 @@ export class CollectionFreeFormViewChrome extends React.Component; } } +@observer +export class CollectionStackingViewChrome extends React.Component { + @observable private _currentKey: string = ""; + @observable private suggestions: string[] = []; + + @computed private get descending() { return StrCast(this.props.CollectionView.props.Document._columnsSort) === "descending"; } + @computed get pivotField() { return StrCast(this.props.CollectionView.props.Document._pivotField); } + + getKeySuggestions = async (value: string): Promise => { + value = value.toLowerCase(); + const docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]); + if (docs instanceof Doc) { + return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); + } else { + const keys = new Set(); + docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); + return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); + } + } + + @action + onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { + this._currentKey = newValue; + } + + getSuggestionValue = (suggestion: string) => suggestion; + + renderSuggestion = (suggestion: string) => { + return

{suggestion}

; + } + + onSuggestionFetch = async ({ value }: { value: string }) => { + const sugg = await this.getKeySuggestions(value); + runInAction(() => { + this.suggestions = sugg; + }); + } + + @action + onSuggestionClear = () => { + this.suggestions = []; + } + + @action + setValue = (value: string) => { + this.props.CollectionView.props.Document._pivotField = value; + return true; + } + + @action toggleSort = () => { + this.props.CollectionView.props.Document._columnsSort = + this.props.CollectionView.props.Document._columnsSort === "descending" ? "ascending" : + this.props.CollectionView.props.Document._columnsSort === "ascending" ? undefined : "descending"; + } + @action resetValue = () => { this._currentKey = this.pivotField; }; + + render() { + return ( +
+
+
+ GROUP BY: +
+
+ +
+
+ this.pivotField} + autosuggestProps={ + { + resetValue: this.resetValue, + value: this._currentKey, + onChange: this.onKeyChange, + autosuggestProps: { + inputProps: + { + value: this._currentKey, + onChange: this.onKeyChange + }, + getSuggestionValue: this.getSuggestionValue, + suggestions: this.suggestions, + alwaysRenderSuggestions: true, + renderSuggestion: this.renderSuggestion, + onSuggestionsFetchRequested: this.onSuggestionFetch, + onSuggestionsClearRequested: this.onSuggestionClear + } + }} + oneLine + SetValue={this.setValue} + contents={this.pivotField ? this.pivotField : "N/A"} + /> +
+
+
+ ); + } +} + + +@observer +export class CollectionSchemaViewChrome extends React.Component { + // private _textwrapAllRows: boolean = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []).length > 0; + + @undoBatch + togglePreview = () => { + const dividerWidth = 4; + const borderWidth = Number(COLLECTION_BORDER_WIDTH); + const panelWidth = this.props.CollectionView.props.PanelWidth(); + const previewWidth = NumCast(this.props.CollectionView.props.Document.schemaPreviewWidth); + const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth; + this.props.CollectionView.props.Document.schemaPreviewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0; + } + + @undoBatch + @action + toggleTextwrap = async () => { + const textwrappedRows = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []); + if (textwrappedRows.length) { + this.props.CollectionView.props.Document.textwrappedSchemaRows = new List([]); + } else { + const docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]); + const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); + this.props.CollectionView.props.Document.textwrappedSchemaRows = new List(allRows); + } + } + + + render() { + const previewWidth = NumCast(this.props.CollectionView.props.Document.schemaPreviewWidth); + const textWrapped = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []).length > 0; + + return ( +
+
+
Show Preview:
+
+
+ {previewWidth !== 0 ? "on" : "off"} +
+
+
+
+ ); + } +} + +@observer +export class CollectionTreeViewChrome extends React.Component { + + get sortAscending() { + return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"]; + } + set sortAscending(value) { + this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"] = value; + } + @computed private get ascending() { + return Cast(this.sortAscending, "boolean", null); + } + + @action toggleSort = () => { + if (this.sortAscending) this.sortAscending = undefined; + else if (this.sortAscending === undefined) this.sortAscending = false; + else this.sortAscending = true; + } + + render() { + return ( +
+ +
+ ); + } +} + +// Enter scroll speed for 3D Carousel +@observer +export class Collection3DCarouselViewChrome extends React.Component { + @computed get scrollSpeed() { + return this.props.CollectionView.props.Document._autoScrollSpeed; + } + + @action + setValue = (value: string) => { + const numValue = Number(StrCast(value)); + if (numValue > 0) { + this.props.CollectionView.props.Document._autoScrollSpeed = numValue; + return true; + } + return false; + } + + render() { + return ( +
+
+
+ AUTOSCROLL SPEED: +
+
+ StrCast(this.scrollSpeed)} + oneLine + SetValue={this.setValue} + contents={this.scrollSpeed ? this.scrollSpeed : 1000} /> +
+
+
+ ); + } +} + +/** + * Chrome for grid view. + */ +@observer +export class CollectionGridViewChrome extends React.Component { + + private clicked: boolean = false; + private entered: boolean = false; + private decrementLimitReached: boolean = false; + @observable private resize = false; + private resizeListenerDisposer: Opt; + + componentDidMount() { + + runInAction(() => this.resize = this.props.CollectionView.props.PanelWidth() < 700); + + // listener to reduce text on chrome resize (panel resize) + this.resizeListenerDisposer = computed(() => this.props.CollectionView.props.PanelWidth()).observe(({ newValue }) => { + runInAction(() => this.resize = newValue < 700); + }); + } + + componentWillUnmount() { + this.resizeListenerDisposer?.(); + } + + get numCols() { return NumCast(this.props.CollectionView.props.Document.gridNumCols, 10); } + + /** + * Sets the value of `numCols` on the grid's Document to the value entered. + */ + @undoBatch + onNumColsEnter = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === "Tab") { + if (e.currentTarget.valueAsNumber > 0) { + this.props.CollectionView.props.Document.gridNumCols = e.currentTarget.valueAsNumber; + } + + } + } + + /** + * Sets the value of `rowHeight` on the grid's Document to the value entered. + */ + // @undoBatch + // onRowHeightEnter = (e: React.KeyboardEvent) => { + // if (e.key === "Enter" || e.key === "Tab") { + // if (e.currentTarget.valueAsNumber > 0 && this.props.CollectionView.props.Document.rowHeight as number !== e.currentTarget.valueAsNumber) { + // this.props.CollectionView.props.Document.rowHeight = e.currentTarget.valueAsNumber; + // } + // } + // } + + /** + * Sets whether the grid is flexible or not on the grid's Document. + */ + @undoBatch + toggleFlex = () => { + this.props.CollectionView.props.Document.gridFlex = !BoolCast(this.props.CollectionView.props.Document.gridFlex, true); + } + + /** + * Increments the value of numCols on button click + */ + onIncrementButtonClick = () => { + this.clicked = true; + this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)--; + undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1)(); + this.entered = false; + } + + /** + * Decrements the value of numCols on button click + */ + onDecrementButtonClick = () => { + this.clicked = true; + if (!this.decrementLimitReached) { + this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)++; + undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1)(); + } + this.entered = false; + } + + /** + * Increments the value of numCols on button hover + */ + incrementValue = () => { + this.entered = true; + if (!this.clicked && !this.decrementLimitReached) { + this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1; + } + this.decrementLimitReached = false; + this.clicked = false; + } + + /** + * Decrements the value of numCols on button hover + */ + decrementValue = () => { + this.entered = true; + if (!this.clicked) { + if (this.numCols !== 1) { + this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1; + } + else { + this.decrementLimitReached = true; + } + } + + this.clicked = false; + } + + /** + * Toggles the value of preventCollision + */ + toggleCollisions = () => { + this.props.CollectionView.props.Document.gridPreventCollision = !this.props.CollectionView.props.Document.gridPreventCollision; + } + + /** + * Changes the value of the compactType + */ + changeCompactType = (e: React.ChangeEvent) => { + // need to change startCompaction so that this operation will be undoable. + this.props.CollectionView.props.Document.gridStartCompaction = e.target.selectedOptions[0].value; + } + + render() { + return ( +
+ + + + + ) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> + + + + {/* + + + + ) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> + */} + + + + + + + + + + + + + + +
+ ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2