diff options
Diffstat (limited to 'src/client/views/collections/CollectionStackingViewFieldColumn.tsx')
-rw-r--r-- | src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 176 |
1 files changed, 110 insertions, 66 deletions
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 387e189e7..74c7ef305 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -1,24 +1,27 @@ import React = require("react"); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faPalette } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { number } from "prop-types"; import { Doc, WidthSym } from "../../../new_fields/Doc"; -import { CollectionStackingView } from "./CollectionStackingView"; import { Id } from "../../../new_fields/FieldSymbols"; +import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { NumCast, StrCast } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; -import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; -import { EditableView } from "../EditableView"; -import { action, observable, computed } from "mobx"; -import { undoBatch } from "../../util/UndoManager"; +import { Docs } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; -import { DocumentManager } from "../../util/DocumentManager"; +import { CompileScript } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; +import { Transform } from "../../util/Transform"; +import { undoBatch } from "../../util/UndoManager"; +import { anchorPoints, Flyout } from "../DocumentDecorations"; +import { EditableView } from "../EditableView"; +import { CollectionStackingView } from "./CollectionStackingView"; import "./CollectionStackingView.scss"; -import { Docs } from "../../documents/Documents"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { CompileScript } from "../../util/Scripting"; -import { RichTextField } from "../../../new_fields/RichTextField"; + +library.add(faPalette); interface CSVFieldColumnProps { @@ -30,17 +33,21 @@ interface CSVFieldColumnProps { parent: CollectionStackingView; type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; createDropTarget: (ele: HTMLDivElement) => void; + screenToLocalTransform: () => Transform; } @observer export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldColumnProps> { - @observable private _background = "white"; + @observable private _background = "inherit"; private _dropRef: HTMLDivElement | null = null; private dropDisposer?: DragManager.DragDropDisposer; private _headerRef: React.RefObject<HTMLDivElement> = React.createRef(); + private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 }; + private _sensitivity: number = 16; @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading; + @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; createColumnDropRef = (ele: HTMLDivElement | null) => { this._dropRef = ele; @@ -71,38 +78,17 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC let parent = this.props.parent; parent._docXfs.length = 0; return docs.map((d, i) => { - let headings = this.props.headings(); - let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d); - let width = () => (d.nativeWidth && !BoolCast(d.ignoreAspect) ? Math.min(pair.layout[WidthSym](), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1); - let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1); + let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns); + let height = () => parent.getDocHeight(pair.layout); let dref = React.createRef<HTMLDivElement>(); - // if (uniqueHeadings.length > 0) { let dxf = () => this.getDocTransform(pair.layout, dref.current!); this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // } - // else { - // //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. - // let dxf = () => this.getDocTransform(layoutDoc, i, width()); - // this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // } - let rowHgtPcnt = height(); let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap); - let style = parent.singleColumn ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` }; - return <div className={`collectionStackingView-${parent.singleColumn ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} > + let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; + return <div className={`collectionStackingView-${parent.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} > {this.props.parent.getDisplayDoc(pair.layout, pair.data, dxf, width)} </div>; - // } else { - // let dref = React.createRef<HTMLDivElement>(); - // let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - // this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); - // let rowHgtPcnt = height(); - // let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap); - // let divStyle = parent.singleColumn ? { width: width(), marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` }; - // return <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={divStyle} > - // {this.props.parent.getDisplayDoc(layoutDoc, d, dxf, width)} - // </div>; - // } }); } @@ -111,7 +97,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC let outerXf = Utils.GetScreenTransform(this.props.parent._masonryGridRef!); let offset = this.props.parent.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); return this.props.parent.props.ScreenToLocalTransform(). - translate(offset[0], offset[1] - (this.props.parent.chromeCollapsed ? 0 : 100)). + translate(offset[0], offset[1]). scale(NumCast(doc.width, 1) / this.props.parent.columnWidth); } @@ -150,6 +136,14 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } @action + changeColumnColor = (color: string) => { + if (this.props.headingObject) { + this.props.headingObject.setColor(color); + this._color = color; + } + } + + @action pointerEntered = () => { if (SelectionManager.GetIsDragging()) { this._background = "#b4b4b4"; @@ -158,7 +152,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC @action pointerLeave = () => { - this._background = "white"; + this._background = "inherit"; + document.removeEventListener("pointermove", this.startDrag); } @action @@ -180,22 +175,25 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } startDrag = (e: PointerEvent) => { - let alias = Doc.MakeAlias(this.props.parent.props.Document); - let key = StrCast(this.props.parent.props.Document.sectionFilter); - let value = this.getValue(this._heading); - value = typeof value === "string" ? `"${value}"` : value; - let script = `return doc.${key} === ${value}`; - let compiled = CompileScript(script, { params: { doc: Doc.name } }); - if (compiled.compiled) { - let scriptField = new ScriptField(compiled); - alias.viewSpecScript = scriptField; - let dragData = new DragManager.DocumentDragData([alias], [alias.proto]); - DragManager.StartDocumentDrag([this._headerRef.current!], dragData, e.clientX, e.clientY); - } + let [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y); + if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) { + let alias = Doc.MakeAlias(this.props.parent.props.Document); + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let value = this.getValue(this._heading); + value = typeof value === "string" ? `"${value}"` : value; + let script = `return doc.${key} === ${value}`; + let compiled = CompileScript(script, { params: { doc: Doc.name } }); + if (compiled.compiled) { + let scriptField = new ScriptField(compiled); + alias.viewSpecScript = scriptField; + let dragData = new DragManager.DocumentDragData([alias], [alias.proto]); + DragManager.StartDocumentDrag([this._headerRef.current!], dragData, e.clientX, e.clientY); + } - e.stopPropagation(); - document.removeEventListener("pointermove", this.startDrag); - document.removeEventListener("pointerup", this.pointerUp); + e.stopPropagation(); + document.removeEventListener("pointermove", this.startDrag); + document.removeEventListener("pointerup", this.pointerUp); + } } pointerUp = (e: PointerEvent) => { @@ -210,12 +208,45 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC e.stopPropagation(); e.preventDefault(); + let [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX, e.clientY); + this._startDragPosition = { x: dx, y: dy }; + document.removeEventListener("pointermove", this.startDrag); document.addEventListener("pointermove", this.startDrag); document.removeEventListener("pointerup", this.pointerUp); document.addEventListener("pointerup", this.pointerUp); } + renderColorPicker = () => { + let selected = this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + + let pink = PastelSchemaPalette.get("pink2"); + let purple = PastelSchemaPalette.get("purple4"); + let blue = PastelSchemaPalette.get("bluegreen1"); + let yellow = PastelSchemaPalette.get("yellow4"); + let red = PastelSchemaPalette.get("red2"); + let green = PastelSchemaPalette.get("bluegreen7"); + let cyan = PastelSchemaPalette.get("bluegreen5"); + let orange = PastelSchemaPalette.get("orange1"); + let gray = "#f1efeb"; + + return ( + <div className="collectionStackingView-colorPicker"> + <div className="colorOptions"> + <div className={"colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div> + <div className={"colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div> + <div className={"colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div> + <div className={"colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div> + <div className={"colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div> + <div className={"colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div> + <div className={"colorPicker" + (selected === green ? " active" : "")} style={{ backgroundColor: green }} onClick={() => this.changeColumnColor(green!)}></div> + <div className={"colorPicker" + (selected === cyan ? " active" : "")} style={{ backgroundColor: cyan }} onClick={() => this.changeColumnColor(cyan!)}></div> + <div className={"colorPicker" + (selected === orange ? " active" : "")} style={{ backgroundColor: orange }} onClick={() => this.changeColumnColor(orange!)}></div> + </div> + </div> + ); + } + render() { let cols = this.props.cols(); let key = StrCast(this.props.parent.props.Document.sectionFilter); @@ -223,7 +254,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC let headings = this.props.headings(); let heading = this._heading; let style = this.props.parent; - let singleColumn = style.singleColumn; + let singleColumn = style.isStackingView; let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; let headerEditableViewProps = { @@ -239,7 +270,11 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC }; let headingView = this.props.headingObject ? <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef} - style={{ width: (style.columnWidth) / (uniqueHeadings.length + 1) }}> + style={{ + width: (style.columnWidth) / + ((uniqueHeadings.length + + ((this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ? 1 : 0)) || 1) + }}> {/* the default bucket (no key value) has a tooltip that describes what it is. Further, it does not have a color and cannot be deleted. */} <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} @@ -247,11 +282,19 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""} style={{ width: "100%", - background: this.props.headingObject && evContents !== `NO ${key.toUpperCase()} VALUE` ? - this.props.headingObject.color : "lightgrey", + background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey", color: "grey" }}> <EditableView {...headerEditableViewProps} /> + {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : + <div className="collectionStackingView-sectionColor"> + <Flyout anchorPoint={anchorPoints.TOP_CENTER} content={this.renderColorPicker()}> + <button className="collectionStackingView-sectionColorButton"> + <FontAwesomeIcon icon="palette" size="sm" /> + </button> + </ Flyout > + </div> + } {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : <button className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}> @@ -259,9 +302,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC </button>} </div> </div> : (null); - for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `; + for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `; return ( - <div key={heading} style={{ width: `${100 / (uniqueHeadings.length + 1)}%`, background: this._background }} + <div className="collectionStackingViewFieldColumn" key={heading} style={{ width: `${100 / ((uniqueHeadings.length + ((this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`, background: this._background }} ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}> {headingView} <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`} @@ -279,10 +322,11 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC {this.children(this.props.docList)} {singleColumn ? (null) : this.props.parent.columnDragger} </div> - <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" - style={{ width: style.columnWidth / (uniqueHeadings.length + 1) }}> - <EditableView {...newEditableViewProps} /> - </div> + {(this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ? + <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" + style={{ width: style.columnWidth / style.numGroupColumns }}> + <EditableView {...newEditableViewProps} /> + </div> : null} </div> ); } |